1#------------------------------------------------------------------------------
2# File:         QuickTime.pm
3#
4# Description:  Read QuickTime and MP4 meta information
5#
6# Revisions:    10/04/2005 - P. Harvey Created
7#               12/19/2005 - P. Harvey Added MP4 support
8#               09/22/2006 - P. Harvey Added M4A support
9#               07/27/2010 - P. Harvey Updated to 2010-05-03 QuickTime spec
10#
11# References:
12#
13#   1) http://developer.apple.com/mac/library/documentation/QuickTime/QTFF/QTFFChap1/qtff1.html
14#   2) http://search.cpan.org/dist/MP4-Info-1.04/
15#   3) http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt
16#   4) http://wiki.multimedia.cx/index.php?title=Apple_QuickTime
17#   5) ISO 14496-12 (http://read.pudn.com/downloads64/ebook/226547/ISO_base_media_file_format.pdf)
18#   6) ISO 14496-16 (http://www.iec-normen.de/previewpdf/info_isoiec14496-16%7Bed2.0%7Den.pdf)
19#   7) http://atomicparsley.sourceforge.net/mpeg-4files.html
20#   8) http://wiki.multimedia.cx/index.php?title=QuickTime_container
21#   9) http://www.adobe.com/devnet/xmp/pdfs/XMPSpecificationPart3.pdf (Oct 2008)
22#   10) http://code.google.com/p/mp4v2/wiki/iTunesMetadata
23#   11) http://www.canieti.com.mx/assets/files/1011/IEC_100_1384_DC.pdf
24#   12) QuickTime file format specification 2010-05-03
25#   13) http://www.adobe.com/devnet/flv/pdf/video_file_format_spec_v10.pdf
26#   14) http://standards.iso.org/ittf/PubliclyAvailableStandards/c051533_ISO_IEC_14496-12_2008.zip
27#   15) http://getid3.sourceforge.net/source/module.audio-video.quicktime.phps
28#   16) http://qtra.apple.com/atoms.html
29#   17) http://www.etsi.org/deliver/etsi_ts/126200_126299/126244/10.01.00_60/ts_126244v100100p.pdf
30#   18) https://github.com/appsec-labs/iNalyzer/blob/master/scinfo.m
31#   19) http://nah6.com/~itsme/cvs-xdadevtools/iphone/tools/decodesinf.pl
32#   20) https://developer.apple.com/legacy/library/documentation/quicktime/reference/QT7-1_Update_Reference/QT7-1_Update_Reference.pdf
33#   21) Francois Bonzon private communication
34#   22) https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/Metadata/Metadata.html
35#   23) http://atomicparsley.sourceforge.net/mpeg-4files.html
36#   24) https://github.com/sergiomb2/libmp4v2/wiki/iTunesMetadata
37#   25) https://cconcolato.github.io/mp4ra/atoms.html
38#   26) https://github.com/SamsungVR/android_upload_sdk/blob/master/SDKLib/src/main/java/com/samsung/msca/samsungvr/sdk/UserVideo.java
39#   27) https://exiftool.org/forum/index.php?topic=11517.0
40#------------------------------------------------------------------------------
41
42package Image::ExifTool::QuickTime;
43
44use strict;
45use vars qw($VERSION $AUTOLOAD %stringEncoding);
46use Image::ExifTool qw(:DataAccess :Utils);
47use Image::ExifTool::Exif;
48use Image::ExifTool::GPS;
49
50$VERSION = '2.56';
51
52sub ProcessMOV($$;$);
53sub ProcessKeys($$$);
54sub ProcessMetaKeys($$$);
55sub ProcessMetaData($$$);
56sub ProcessEncodingParams($$$);
57sub ProcessSampleDesc($$$);
58sub ProcessHybrid($$$);
59sub ProcessRights($$$);
60# ++vvvvvvvvvvvv++ (in QuickTimeStream.pl)
61sub Process_mebx($$$);
62sub Process_3gf($$$);
63sub Process_gps0($$$);
64sub Process_gsen($$$);
65sub ProcessRIFFTrailer($$$);
66sub ProcessTTAD($$$);
67sub ProcessNMEA($$$);
68sub SaveMetaKeys($$$);
69# ++^^^^^^^^^^^^++
70sub ParseItemLocation($$);
71sub ParseContentDescribes($$);
72sub ParseItemInfoEntry($$);
73sub ParseItemPropAssoc($$);
74sub FixWrongFormat($);
75sub GetMatrixStructure($$);
76sub ConvertISO6709($);
77sub ConvInvISO6709($);
78sub ConvertChapterList($);
79sub PrintChapter($);
80sub PrintGPSCoordinates($);
81sub PrintInvGPSCoordinates($);
82sub UnpackLang($;$);
83sub WriteKeys($$$);
84sub WriteQuickTime($$$);
85sub WriteMOV($$);
86sub GetLangInfo($$);
87sub CheckQTValue($$$);
88
89# MIME types for all entries in the ftypLookup with file extensions
90# (defaults to 'video/mp4' if not found in this lookup)
91my %mimeLookup = (
92   '3G2' => 'video/3gpp2',
93   '3GP' => 'video/3gpp',
94    AAX  => 'audio/vnd.audible.aax',
95    DVB  => 'video/vnd.dvb.file',
96    F4A  => 'audio/mp4',
97    F4B  => 'audio/mp4',
98    JP2  => 'image/jp2',
99    JPM  => 'image/jpm',
100    JPX  => 'image/jpx',
101    M4A  => 'audio/mp4',
102    M4B  => 'audio/mp4',
103    M4P  => 'audio/mp4',
104    M4V  => 'video/x-m4v',
105    MOV  => 'video/quicktime',
106    MQV  => 'video/quicktime',
107    HEIC => 'image/heic',
108    HEVC => 'image/heic-sequence',
109    HEICS=> 'image/heic-sequence',
110    HEIF => 'image/heif',
111    HEIFS=> 'image/heif-sequence',
112    AVIF => 'image/avif', #PH (NC)
113    CRX  => 'video/x-canon-crx',    # (will get overridden)
114);
115
116# look up file type from ftyp atom type, with MIME type in comment if known
117# (ref http://www.ftyps.com/)
118my %ftypLookup = (
119    '3g2a' => '3GPP2 Media (.3G2) compliant with 3GPP2 C.S0050-0 V1.0', # video/3gpp2
120    '3g2b' => '3GPP2 Media (.3G2) compliant with 3GPP2 C.S0050-A V1.0.0', # video/3gpp2
121    '3g2c' => '3GPP2 Media (.3G2) compliant with 3GPP2 C.S0050-B v1.0', # video/3gpp2
122    '3ge6' => '3GPP (.3GP) Release 6 MBMS Extended Presentations', # video/3gpp
123    '3ge7' => '3GPP (.3GP) Release 7 MBMS Extended Presentations', # video/3gpp
124    '3gg6' => '3GPP Release 6 General Profile', # video/3gpp
125    '3gp1' => '3GPP Media (.3GP) Release 1 (probably non-existent)', # video/3gpp
126    '3gp2' => '3GPP Media (.3GP) Release 2 (probably non-existent)', # video/3gpp
127    '3gp3' => '3GPP Media (.3GP) Release 3 (probably non-existent)', # video/3gpp
128    '3gp4' => '3GPP Media (.3GP) Release 4', # video/3gpp
129    '3gp5' => '3GPP Media (.3GP) Release 5', # video/3gpp
130    '3gp6' => '3GPP Media (.3GP) Release 6 Basic Profile', # video/3gpp
131    '3gp6' => '3GPP Media (.3GP) Release 6 Progressive Download', # video/3gpp
132    '3gp6' => '3GPP Media (.3GP) Release 6 Streaming Servers', # video/3gpp
133    '3gs7' => '3GPP Media (.3GP) Release 7 Streaming Servers', # video/3gpp
134    'aax ' => 'Audible Enhanced Audiobook (.AAX)', #PH
135    'avc1' => 'MP4 Base w/ AVC ext [ISO 14496-12:2005]', # video/mp4
136    'CAEP' => 'Canon Digital Camera',
137    'caqv' => 'Casio Digital Camera',
138    'CDes' => 'Convergent Design',
139    'da0a' => 'DMB MAF w/ MPEG Layer II aud, MOT slides, DLS, JPG/PNG/MNG images',
140    'da0b' => 'DMB MAF, extending DA0A, with 3GPP timed text, DID, TVA, REL, IPMP',
141    'da1a' => 'DMB MAF audio with ER-BSAC audio, JPG/PNG/MNG images',
142    'da1b' => 'DMB MAF, extending da1a, with 3GPP timed text, DID, TVA, REL, IPMP',
143    'da2a' => 'DMB MAF aud w/ HE-AAC v2 aud, MOT slides, DLS, JPG/PNG/MNG images',
144    'da2b' => 'DMB MAF, extending da2a, with 3GPP timed text, DID, TVA, REL, IPMP',
145    'da3a' => 'DMB MAF aud with HE-AAC aud, JPG/PNG/MNG images',
146    'da3b' => 'DMB MAF, extending da3a w/ BIFS, 3GPP timed text, DID, TVA, REL, IPMP',
147    'dmb1' => 'DMB MAF supporting all the components defined in the specification',
148    'dmpf' => 'Digital Media Project', # various
149    'drc1' => 'Dirac (wavelet compression), encapsulated in ISO base media (MP4)',
150    'dv1a' => 'DMB MAF vid w/ AVC vid, ER-BSAC aud, BIFS, JPG/PNG/MNG images, TS',
151    'dv1b' => 'DMB MAF, extending dv1a, with 3GPP timed text, DID, TVA, REL, IPMP',
152    'dv2a' => 'DMB MAF vid w/ AVC vid, HE-AAC v2 aud, BIFS, JPG/PNG/MNG images, TS',
153    'dv2b' => 'DMB MAF, extending dv2a, with 3GPP timed text, DID, TVA, REL, IPMP',
154    'dv3a' => 'DMB MAF vid w/ AVC vid, HE-AAC aud, BIFS, JPG/PNG/MNG images, TS',
155    'dv3b' => 'DMB MAF, extending dv3a, with 3GPP timed text, DID, TVA, REL, IPMP',
156    'dvr1' => 'DVB (.DVB) over RTP', # video/vnd.dvb.file
157    'dvt1' => 'DVB (.DVB) over MPEG-2 Transport Stream', # video/vnd.dvb.file
158    'F4A ' => 'Audio for Adobe Flash Player 9+ (.F4A)', # audio/mp4
159    'F4B ' => 'Audio Book for Adobe Flash Player 9+ (.F4B)', # audio/mp4
160    'F4P ' => 'Protected Video for Adobe Flash Player 9+ (.F4P)', # video/mp4
161    'F4V ' => 'Video for Adobe Flash Player 9+ (.F4V)', # video/mp4
162    'isc2' => 'ISMACryp 2.0 Encrypted File', # ?/enc-isoff-generic
163    'iso2' => 'MP4 Base Media v2 [ISO 14496-12:2005]', # video/mp4
164    'isom' => 'MP4  Base Media v1 [IS0 14496-12:2003]', # video/mp4
165    'JP2 ' => 'JPEG 2000 Image (.JP2) [ISO 15444-1 ?]', # image/jp2
166    'JP20' => 'Unknown, from GPAC samples (prob non-existent)',
167    'jpm ' => 'JPEG 2000 Compound Image (.JPM) [ISO 15444-6]', # image/jpm
168    'jpx ' => 'JPEG 2000 with extensions (.JPX) [ISO 15444-2]', # image/jpx
169    'KDDI' => '3GPP2 EZmovie for KDDI 3G cellphones', # video/3gpp2
170    #LCAG  => (found in CompatibleBrands of Leica MOV videos)
171    'M4A ' => 'Apple iTunes AAC-LC (.M4A) Audio', # audio/x-m4a
172    'M4B ' => 'Apple iTunes AAC-LC (.M4B) Audio Book', # audio/mp4
173    'M4P ' => 'Apple iTunes AAC-LC (.M4P) AES Protected Audio', # audio/mp4
174    'M4V ' => 'Apple iTunes Video (.M4V) Video', # video/x-m4v
175    'M4VH' => 'Apple TV (.M4V)', # video/x-m4v
176    'M4VP' => 'Apple iPhone (.M4V)', # video/x-m4v
177    'mj2s' => 'Motion JPEG 2000 [ISO 15444-3] Simple Profile', # video/mj2
178    'mjp2' => 'Motion JPEG 2000 [ISO 15444-3] General Profile', # video/mj2
179    'mmp4' => 'MPEG-4/3GPP Mobile Profile (.MP4/3GP) (for NTT)', # video/mp4
180    'mp21' => 'MPEG-21 [ISO/IEC 21000-9]', # various
181    'mp41' => 'MP4 v1 [ISO 14496-1:ch13]', # video/mp4
182    'mp42' => 'MP4 v2 [ISO 14496-14]', # video/mp4
183    'mp71' => 'MP4 w/ MPEG-7 Metadata [per ISO 14496-12]', # various
184    'MPPI' => 'Photo Player, MAF [ISO/IEC 23000-3]', # various
185    'mqt ' => 'Sony / Mobile QuickTime (.MQV) US Patent 7,477,830 (Sony Corp)', # video/quicktime
186    'MSNV' => 'MPEG-4 (.MP4) for SonyPSP', # audio/mp4
187    'NDAS' => 'MP4 v2 [ISO 14496-14] Nero Digital AAC Audio', # audio/mp4
188    'NDSC' => 'MPEG-4 (.MP4) Nero Cinema Profile', # video/mp4
189    'NDSH' => 'MPEG-4 (.MP4) Nero HDTV Profile', # video/mp4
190    'NDSM' => 'MPEG-4 (.MP4) Nero Mobile Profile', # video/mp4
191    'NDSP' => 'MPEG-4 (.MP4) Nero Portable Profile', # video/mp4
192    'NDSS' => 'MPEG-4 (.MP4) Nero Standard Profile', # video/mp4
193    'NDXC' => 'H.264/MPEG-4 AVC (.MP4) Nero Cinema Profile', # video/mp4
194    'NDXH' => 'H.264/MPEG-4 AVC (.MP4) Nero HDTV Profile', # video/mp4
195    'NDXM' => 'H.264/MPEG-4 AVC (.MP4) Nero Mobile Profile', # video/mp4
196    'NDXP' => 'H.264/MPEG-4 AVC (.MP4) Nero Portable Profile', # video/mp4
197    'NDXS' => 'H.264/MPEG-4 AVC (.MP4) Nero Standard Profile', # video/mp4
198    'odcf' => 'OMA DCF DRM Format 2.0 (OMA-TS-DRM-DCF-V2_0-20060303-A)', # various
199    'opf2' => 'OMA PDCF DRM Format 2.1 (OMA-TS-DRM-DCF-V2_1-20070724-C)',
200    'opx2' => 'OMA PDCF DRM + XBS extensions (OMA-TS-DRM_XBS-V1_0-20070529-C)',
201    'pana' => 'Panasonic Digital Camera',
202    'qt  ' => 'Apple QuickTime (.MOV/QT)', # video/quicktime
203    'ROSS' => 'Ross Video',
204    'sdv ' => 'SD Memory Card Video', # various?
205    'ssc1' => 'Samsung stereoscopic, single stream',
206    'ssc2' => 'Samsung stereoscopic, dual stream',
207    'XAVC' => 'Sony XAVC', #PH
208    'heic' => 'High Efficiency Image Format HEVC still image (.HEIC)', # image/heic
209    'hevc' => 'High Efficiency Image Format HEVC sequence (.HEICS)', # image/heic-sequence
210    'mif1' => 'High Efficiency Image Format still image (.HEIF)', # image/heif
211    'msf1' => 'High Efficiency Image Format sequence (.HEIFS)', # image/heif-sequence
212    'heix' => 'High Efficiency Image Format still image (.HEIF)', # image/heif (ref PH, Canon 1DXmkIII)
213    'avif' => 'AV1 Image File Format (.AVIF)', # image/avif
214    'crx ' => 'Canon Raw (.CRX)', #PH (CR3 or CRM; use Canon CompressorVersion to decide)
215);
216
217# information for int32u date/time tags (time zero is Jan 1, 1904)
218my %timeInfo = (
219    Notes => 'converted from UTC to local time if the QuickTimeUTC option is set',
220    Shift => 'Time',
221    Writable => 1,
222    Permanent => 1,
223    DelValue => 0,
224    # It is not uncommon for brain-dead software to use the wrong time zero,
225    # so assume a time zero of Jan 1, 1970 if the date is before this
226    # Note: This value will be in UTC if generated by a system that is aware of the time zone
227    RawConv => q{
228        my $offset = (66 * 365 + 17) * 24 * 3600;
229        return $val - $offset if $val >= $offset or $$self{OPTIONS}{QuickTimeUTC};
230        if ($val and not $$self{IsWriting}) {
231            $self->WarnOnce('Patched incorrect time zero for QuickTime date/time tag',1);
232        }
233        return $val;
234    },
235    RawConvInv => q{
236        if ($$self{FileType} eq 'CR3' and not $self->Options('QuickTimeUTC')) {
237            # convert to UTC
238            my $offset = (66 * 365 + 17) * 24 * 3600;
239            $val = ConvertUnixTime($val - $offset);
240            $val = GetUnixTime($val, 1) + $offset;
241        }
242        return $val;
243    },
244    # (all CR3 files store UTC times - PH)
245    ValueConv => 'ConvertUnixTime($val, $self->Options("QuickTimeUTC") || $$self{FileType} eq "CR3")',
246    ValueConvInv => 'GetUnixTime($val, $self->Options("QuickTimeUTC")) + (66 * 365 + 17) * 24 * 3600',
247    PrintConv => '$self->ConvertDateTime($val)',
248    PrintConvInv => '$self->InverseDateTime($val)',
249    # (can't put Groups here because they aren't constant!)
250);
251# information for duration tags
252my %durationInfo = (
253    ValueConv => '$$self{TimeScale} ? $val / $$self{TimeScale} : $val',
254    PrintConv => '$$self{TimeScale} ? ConvertDuration($val) : $val',
255);
256# handle unknown tags
257my %unknownInfo = (
258    Unknown => 1,
259    ValueConv => '$val =~ /^([\x20-\x7e]*)\0*$/ ? $1 : \$val',
260);
261# parsing for most of the 3gp udta language text boxes
262my %langText = (
263    Notes => 'used in 3gp videos',
264    IText => 6,
265    Avoid => 1,
266);
267
268# 4-character Vendor ID codes (ref PH)
269my %vendorID = (
270    appl => 'Apple',
271    fe20 => 'Olympus (fe20)', # (FE200)
272    FFMP => 'FFmpeg',
273   'GIC '=> 'General Imaging Co.',
274    kdak => 'Kodak',
275    KMPI => 'Konica-Minolta',
276    leic => 'Leica',
277    mino => 'Minolta',
278    niko => 'Nikon',
279    NIKO => 'Nikon',
280    olym => 'Olympus',
281    pana => 'Panasonic',
282    pent => 'Pentax',
283    pr01 => 'Olympus (pr01)', # (FE100,FE110,FE115)
284    sany => 'Sanyo',
285   'SMI '=> 'Sorenson Media Inc.',
286    ZORA => 'Zoran Corporation',
287   'AR.D'=> 'Parrot AR.Drone',
288   ' KD '=> 'Kodak', # (FZ201)
289);
290
291# QuickTime data atom encodings for string types (ref 12)
292%stringEncoding = (
293    1 => 'UTF8',
294    2 => 'UTF16',
295    3 => 'ShiftJIS',
296    4 => 'UTF8',
297    5 => 'UTF16',
298);
299
300my %graphicsMode = (
301    # (ref http://homepage.mac.com/vanhoek/MovieGuts%20docs/64.html)
302    0x00 => 'srcCopy',
303    0x01 => 'srcOr',
304    0x02 => 'srcXor',
305    0x03 => 'srcBic',
306    0x04 => 'notSrcCopy',
307    0x05 => 'notSrcOr',
308    0x06 => 'notSrcXor',
309    0x07 => 'notSrcBic',
310    0x08 => 'patCopy',
311    0x09 => 'patOr',
312    0x0a => 'patXor',
313    0x0b => 'patBic',
314    0x0c => 'notPatCopy',
315    0x0d => 'notPatOr',
316    0x0e => 'notPatXor',
317    0x0f => 'notPatBic',
318    0x20 => 'blend',
319    0x21 => 'addPin',
320    0x22 => 'addOver',
321    0x23 => 'subPin',
322    0x24 => 'transparent',
323    0x25 => 'addMax',
324    0x26 => 'subOver',
325    0x27 => 'addMin',
326    0x31 => 'grayishTextOr',
327    0x32 => 'hilite',
328    0x40 => 'ditherCopy',
329    # the following ref ISO/IEC 15444-3
330    0x100 => 'Alpha',
331    0x101 => 'White Alpha',
332    0x102 => 'Pre-multiplied Black Alpha',
333    0x110 => 'Component Alpha',
334);
335
336my %channelLabel = (
337    0xFFFFFFFF => 'Unknown',
338    0 => 'Unused',
339    100 => 'UseCoordinates',
340    1 => 'Left',
341    2 => 'Right',
342    3 => 'Center',
343    4 => 'LFEScreen',
344    5 => 'LeftSurround',
345    6 => 'RightSurround',
346    7 => 'LeftCenter',
347    8 => 'RightCenter',
348    9 => 'CenterSurround',
349    10 => 'LeftSurroundDirect',
350    11 => 'RightSurroundDirect',
351    12 => 'TopCenterSurround',
352    13 => 'VerticalHeightLeft',
353    14 => 'VerticalHeightCenter',
354    15 => 'VerticalHeightRight',
355    16 => 'TopBackLeft',
356    17 => 'TopBackCenter',
357    18 => 'TopBackRight',
358    33 => 'RearSurroundLeft',
359    34 => 'RearSurroundRight',
360    35 => 'LeftWide',
361    36 => 'RightWide',
362    37 => 'LFE2',
363    38 => 'LeftTotal',
364    39 => 'RightTotal',
365    40 => 'HearingImpaired',
366    41 => 'Narration',
367    42 => 'Mono',
368    43 => 'DialogCentricMix',
369    44 => 'CenterSurroundDirect',
370    45 => 'Haptic',
371    200 => 'Ambisonic_W',
372    201 => 'Ambisonic_X',
373    202 => 'Ambisonic_Y',
374    203 => 'Ambisonic_Z',
375    204 => 'MS_Mid',
376    205 => 'MS_Side',
377    206 => 'XY_X',
378    207 => 'XY_Y',
379    301 => 'HeadphonesLeft',
380    302 => 'HeadphonesRight',
381    304 => 'ClickTrack',
382    305 => 'ForeignLanguage',
383    400 => 'Discrete',
384    0x10000 => 'Discrete_0',
385    0x10001 => 'Discrete_1',
386    0x10002 => 'Discrete_2',
387    0x10003 => 'Discrete_3',
388    0x10004 => 'Discrete_4',
389    0x10005 => 'Discrete_5',
390    0x10006 => 'Discrete_6',
391    0x10007 => 'Discrete_7',
392    0x10008 => 'Discrete_8',
393    0x10009 => 'Discrete_9',
394    0x1000a => 'Discrete_10',
395    0x1000b => 'Discrete_11',
396    0x1000c => 'Discrete_12',
397    0x1000d => 'Discrete_13',
398    0x1000e => 'Discrete_14',
399    0x1000f => 'Discrete_15',
400    0x1ffff => 'Discrete_65535',
401);
402
403# properties which don't get inherited from the parent
404my %dontInherit = (
405    ispe => 1,  # size of parent may be different
406    hvcC => 1,  # (likely redundant)
407);
408
409# tags that may be duplicated and directories that may contain duplicate tags
410# (used only to avoid warnings when Validate-ing)
411my %dupTagOK = ( mdat => 1, trak => 1, free => 1, infe => 1, sgpd => 1, dimg => 1, CCDT => 1,
412                 sbgp => 1, csgm => 1, uuid => 1, cdsc => 1, maxr => 1, '----' => 1 );
413my %dupDirOK = ( ipco => 1, '----' => 1 );
414
415# the usual atoms required to decode timed metadata with the ExtractEmbedded option
416my %eeStd = ( stco => 'stbl', co64 => 'stbl', stsz => 'stbl', stz2 => 'stbl',
417              stsc => 'stbl', stts => 'stbl' );
418
419# boxes and their containers for the various handler types that we want to save
420# when the ExtractEmbedded is enabled (currently only the 'gps ' container name is
421# used, but others have been checked against all available sample files and may be
422# useful in the future if the names are used for different boxes on other locations)
423my %eeBox = (
424    # (note: vide is only processed if specific atoms exist in the VideoSampleDesc)
425    vide => { %eeStd,
426        JPEG => 'stsd',
427      # avcC => 'stsd', # (uncomment to parse H264 stream)
428    },
429    text => { %eeStd },
430    meta => { %eeStd },
431    sbtl => { %eeStd },
432    data => { %eeStd },
433    camm => { %eeStd }, # (Insta360)
434    ctbx => { %eeStd }, # (GM cars)
435    ''   => { 'gps ' => 'moov', 'GPS ' => 'main' }, # (no handler -- in top level 'moov' box, and main)
436);
437
438# QuickTime atoms
439%Image::ExifTool::QuickTime::Main = (
440    PROCESS_PROC => \&ProcessMOV,
441    WRITE_PROC => \&WriteQuickTime, # (only needs to be defined for directories to process when writing)
442    GROUPS => { 2 => 'Video' },
443    meta => { # 'meta' is found here in my Sony ILCE-7S MP4 sample - PH
444        Name => 'Meta',
445        SubDirectory => {
446            TagTable => 'Image::ExifTool::QuickTime::Meta',
447            Start => 4, # skip 4-byte version number header
448        },
449    },
450    meco => { #ISO14496-12:2015
451        Name => 'OtherMeta',
452        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::OtherMeta' },
453    },
454    free => [
455        {
456            Name => 'KodakFree',
457            # (found in Kodak M5370 MP4 videos)
458            Condition => '$$valPt =~ /^\0\0\0.Seri/s',
459            SubDirectory => { TagTable => 'Image::ExifTool::Kodak::Free' },
460        },{
461            Name => 'Pittasoft',
462            # (Pittasoft Blackview dashcam MP4 videos)
463            Condition => '$$valPt =~ /^\0\0..(cprt|sttm|ptnm|ptrh|thum|gps |3gf )/s',
464            SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Pittasoft' },
465        },{
466            Unknown => 1,
467            Binary => 1,
468        },
469        # (also Samsung WB750 uncompressed thumbnail data starting with "SDIC\0")
470    ],
471    # fre1 - 4 bytes: "june" (Kodak PixPro SP360)
472    frea => {
473        Name => 'Kodak_frea',
474        SubDirectory => { TagTable => 'Image::ExifTool::Kodak::frea' },
475    },
476    skip => [
477        {
478            Name => 'CanonSkip',
479            Condition => '$$valPt =~ /^\0.{3}(CNDB|CNCV|CNMN|CNFV|CNTH|CNDM)/s',
480            SubDirectory => { TagTable => 'Image::ExifTool::Canon::Skip' },
481        },
482        {
483            Name => 'PreviewImage', # (found in  DuDuBell M1 dashcam MOV files)
484            Groups => { 2 => 'Preview' },
485            Condition => '$$valPt =~ /^.{12}\xff\xd8\xff/',
486            Binary => 1,
487            RawConv => q{
488                my $len = Get32u(\$val, 8);
489                return undef unless length($val) >= $len + 12;
490                return substr($val, 12, $len);
491            },
492        },
493        { Name => 'Skip', Unknown => 1, Binary => 1 },
494    ],
495    wide => { Unknown => 1, Binary => 1 },
496    ftyp => { #MP4
497        Name => 'FileType',
498        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::FileType' },
499    },
500    pnot => {
501        Name => 'Preview',
502        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Preview' },
503    },
504    PICT => {
505        Name => 'PreviewPICT',
506        Groups => { 2 => 'Preview' },
507        Binary => 1,
508    },
509    pict => { #8
510        Name => 'PreviewPICT',
511        Groups => { 2 => 'Preview' },
512        Binary => 1,
513    },
514    # (note that moov is present for an HEIF sequence)
515    moov => {
516        Name => 'Movie',
517        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Movie' },
518    },
519    moof => {
520        Name => 'MovieFragment',
521        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MovieFragment' },
522    },
523    # mfra - movie fragment random access: contains tfra (track fragment random access), and
524    #           mfro (movie fragment random access offset) (ref 5)
525    mdat => { Name => 'MediaData', Unknown => 1, Binary => 1 },
526    'mdat-size' => {
527        Name => 'MediaDataSize',
528        Notes => q{
529            not a real tag ID, this tag represents the size of the 'mdat' data in bytes
530            and is used in the AvgBitrate calculation
531        },
532    },
533    'mdat-offset' => 'MediaDataOffset',
534    junk => { Unknown => 1, Binary => 1 }, #8
535    uuid => [
536        { #9 (MP4 files)
537            Name => 'XMP',
538            # *** this is where ExifTool writes XMP in MP4 videos (as per XMP spec) ***
539            Condition => '$$valPt=~/^\xbe\x7a\xcf\xcb\x97\xa9\x42\xe8\x9c\x71\x99\x94\x91\xe3\xaf\xac/',
540            WriteGroup => 'XMP',    # (write main XMP tags here)
541            SubDirectory => {
542                TagTable => 'Image::ExifTool::XMP::Main',
543                Start => 16,
544            },
545        },
546        { #11 (MP4 files)
547            Name => 'UUID-PROF',
548            Condition => '$$valPt=~/^PROF!\xd2\x4f\xce\xbb\x88\x69\x5c\xfa\xc9\xc7\x40/',
549            SubDirectory => {
550                TagTable => 'Image::ExifTool::QuickTime::Profile',
551                Start => 24, # uid(16) + version(1) + flags(3) + count(4)
552            },
553        },
554        { #PH (Flip MP4 files)
555            Name => 'UUID-Flip',
556            Condition => '$$valPt=~/^\x4a\xb0\x3b\x0f\x61\x8d\x40\x75\x82\xb2\xd9\xfa\xce\xd3\x5f\xf5/',
557            SubDirectory => {
558                TagTable => 'Image::ExifTool::QuickTime::Flip',
559                Start => 16,
560            },
561        },
562        # "\x98\x7f\xa3\xdf\x2a\x85\x43\xc0\x8f\x8f\xd9\x7c\x47\x1e\x8e\xea" - unknown data in Flip videos
563        { #PH (Canon CR3)
564            Name => 'UUID-Canon2',
565            WriteLast => 1, # MUST come after mdat or DPP will drop mdat when writing!
566            Condition => '$$valPt=~/^\x21\x0f\x16\x87\x91\x49\x11\xe4\x81\x11\x00\x24\x21\x31\xfc\xe4/',
567            SubDirectory => {
568                TagTable => 'Image::ExifTool::Canon::uuid2',
569                Start => 16,
570            },
571        },
572        { # (ref https://github.com/JamesHeinrich/getID3/blob/master/getid3/module.audio-video.quicktime.php)
573            Name => 'SensorData', # sensor data for the 360Fly
574            Condition => '$$valPt=~/^\xef\xe1\x58\x9a\xbb\x77\x49\xef\x80\x95\x27\x75\x9e\xb1\xdc\x6f/ and $$self{OPTIONS}{ExtractEmbedded}',
575            SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Tags360Fly' },
576        },
577        {
578            Name => 'SensorData',
579            Condition => '$$valPt=~/^\xef\xe1\x58\x9a\xbb\x77\x49\xef\x80\x95\x27\x75\x9e\xb1\xdc\x6f/',
580            Notes => 'raw 360Fly sensor data without ExtractEmbedded option',
581            RawConv => q{
582                $self->WarnOnce('Use the ExtractEmbedded option to decode timed SensorData',3);
583                return \$val;
584            },
585        },
586        { #PH (Canon CR3)
587            Name => 'PreviewImage',
588            Condition => '$$valPt=~/^\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16/',
589            Groups => { 2 => 'Preview' },
590            # 0x00 - undef[16]: UUID
591            # 0x10 - int32u[2]: "0 1" (version and/or item count?)
592            # 0x18 - int32u: PRVW atom size
593            # 0x20 - int32u: 'PRVW'
594            # 0x30 - int32u: 0
595            # 0x34 - int16u: 1
596            # 0x36 - int16u: image width
597            # 0x38 - int16u: image height
598            # 0x3a - int16u: 1
599            # 0x3c - int32u: preview length
600            RawConv => '$val = substr($val, 0x30); $self->ValidateImage(\$val, $tag)',
601        },
602        { #8
603            Name => 'UUID-Unknown',
604            %unknownInfo,
605        },
606    ],
607    _htc => {
608        Name => 'HTCInfo',
609        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HTCInfo' },
610    },
611    udta => {
612        Name => 'UserData',
613        SubDirectory => { TagTable => 'Image::ExifTool::FLIR::UserData' },
614    },
615    thum => { #PH
616        Name => 'ThumbnailImage',
617        Groups => { 2 => 'Preview' },
618        Binary => 1,
619    },
620   'thm ' => { #PH (70mai A800)
621        Name => 'ThumbnailImage',
622        Groups => { 2 => 'Preview' },
623        Binary => 1,
624    },
625    ardt => { #PH
626        Name => 'ARDroneFile',
627        ValueConv => 'length($val) > 4 ? substr($val,4) : $val', # remove length
628    },
629    prrt => { #PH
630        Name => 'ARDroneTelemetry',
631        Notes => q{
632            telemetry information for each video frame: status1, status2, time, pitch,
633            roll, yaw, speed, altitude
634        },
635        ValueConv => q{
636            my $size = length $val;
637            return \$val if $size < 12 or not $$self{OPTIONS}{Binary};
638            my $len = Get16u(\$val, 2);
639            my $str = '';
640            SetByteOrder('II');
641            my $pos = 12;
642            while ($pos + $len <= $size) {
643                my $s1 = Get16u(\$val, $pos);
644                # s2: 7=take-off?, 3=moving, 4=hovering, 9=landing?, 2=landed
645                my $s2 = Get16u(\$val, $pos + 2);
646                $str .= "$s1 $s2";
647                my $num = int(($len-4)/4);
648                my ($i, $v);
649                for ($i=0; $i<$num; ++$i) {
650                    my $pt = $pos + 4 + $i * 4;
651                    if ($i > 0 && $i < 4) {
652                        $v = GetFloat(\$val, $pt); # pitch/roll/yaw
653                    } else {
654                        $v = Get32u(\$val, $pt);
655                        # convert time to sec, and speed(NC)/altitude to metres
656                        $v /= 1000 if $i <= 5;
657                    }
658                    $str .= " $v";
659                }
660                $str .= "\n";
661                $pos += $len;
662            }
663            SetByteOrder('MM');
664            return \$str;
665        },
666    },
667    udat => { #PH (GPS NMEA-format log written by Datakam Player software)
668        Name => 'GPSLog',
669        Binary => 1,    # (actually ASCII, but very lengthy)
670    },
671    # meta - proprietary XML information written by some Flip cameras - PH
672    # beam - 16 bytes found in an iPhone video
673    IDIT => { #PH (written by DuDuBell M1, VSYS M6L dashcams)
674        Name => 'DateTimeOriginal',
675        Description => 'Date/Time Original',
676        Groups => { 2 => 'Time' },
677        Format => 'string', # (removes trailing "\0")
678        Shift => 'Time',
679        Writable => 1,
680        Permanent => 1,
681        DelValue => '0000-00-00T00:00:00+0000',
682        ValueConv => '$val=~tr/-/:/; $val',
683        ValueConvInv => '$val=~s/(\d+):(\d+):/$1-$2-/; $val',
684        PrintConv => '$self->ConvertDateTime($val)',
685        PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist)
686    },
687    gps0 => { #PH (DuDuBell M1, VSYS M6L)
688        Name => 'GPSTrack',
689        SubDirectory => {
690            TagTable => 'Image::ExifTool::QuickTime::Stream',
691            ProcessProc => \&Process_gps0,
692        },
693    },
694    gsen => { #PH (DuDuBell M1, VSYS M6L)
695        Name => 'GSensor',
696        SubDirectory => {
697            TagTable => 'Image::ExifTool::QuickTime::Stream',
698            ProcessProc => \&Process_gsen,
699        },
700    },
701    # gpsa - seen hex "01 20 00 00" (DuDuBell M1, VSYS M6L)
702    # gsea - 20 bytes hex "05 00's..." (DuDuBell M1) "05 08 02 01 ..." (VSYS M6L)
703   'GPS ' => {  # GPS data written by 70mai dashcam (parsed in QuickTimeStream.pl)
704        Name => 'GPSDataList2',
705        Unknown => 1,
706        Binary => 1,
707    },
708);
709
710# MPEG-4 'ftyp' atom
711# (ref http://developer.apple.com/mac/library/documentation/QuickTime/QTFF/QTFFChap1/qtff1.html)
712%Image::ExifTool::QuickTime::FileType = (
713    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
714    GROUPS => { 2 => 'Video' },
715    FORMAT => 'int32u',
716    0 => {
717        Name => 'MajorBrand',
718        Format => 'undef[4]',
719        PrintConv => \%ftypLookup,
720    },
721    1 => {
722        Name => 'MinorVersion',
723        Format => 'undef[4]',
724        ValueConv => 'sprintf("%x.%x.%x", unpack("nCC", $val))',
725    },
726    2 => {
727        Name => 'CompatibleBrands',
728        Format => 'undef[$size-8]',
729        # ignore any entry with a null, and return others as a list
730        ValueConv => 'my @a=($val=~/.{4}/sg); @a=grep(!/\0/,@a); \@a',
731    },
732);
733
734# proprietary HTC atom (HTC One MP4 video)
735%Image::ExifTool::QuickTime::HTCInfo = (
736    PROCESS_PROC => \&ProcessMOV,
737    GROUPS => { 2 => 'Video' },
738    NOTES => 'Tags written by some HTC camera phones.',
739    slmt => {
740        Name => 'Unknown_slmt',
741        Unknown => 1,
742        Format => 'int32u', # (observed values: 4)
743    },
744);
745
746# atoms used in QTIF files
747%Image::ExifTool::QuickTime::ImageFile = (
748    PROCESS_PROC => \&ProcessMOV,
749    GROUPS => { 2 => 'Image' },
750    NOTES => 'Tags used in QTIF QuickTime Image Files.',
751    idsc => {
752        Name => 'ImageDescription',
753        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ImageDesc' },
754    },
755    idat => {
756        Name => 'ImageData',
757        Binary => 1,
758    },
759    iicc => {
760        Name => 'ICC_Profile',
761        SubDirectory => { TagTable => 'Image::ExifTool::ICC_Profile::Main' },
762    },
763);
764
765# image description data block
766%Image::ExifTool::QuickTime::ImageDesc = (
767    PROCESS_PROC => \&ProcessHybrid,
768    VARS => { ID_LABEL => 'ID/Index' },
769    GROUPS => { 2 => 'Image' },
770    FORMAT => 'int16u',
771    2 => {
772        Name => 'CompressorID',
773        Format => 'string[4]',
774# not very useful since this isn't a complete list and name is given below
775#        # ref http://developer.apple.com/mac/library/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html
776#        PrintConv => {
777#            cvid => 'Cinepak',
778#            jpeg => 'JPEG',
779#           'smc '=> 'Graphics',
780#           'rle '=> 'Animation',
781#            rpza => 'Apple Video',
782#            kpcd => 'Kodak Photo CD',
783#           'png '=> 'Portable Network Graphics',
784#            mjpa => 'Motion-JPEG (format A)',
785#            mjpb => 'Motion-JPEG (format B)',
786#            SVQ1 => 'Sorenson video, version 1',
787#            SVQ3 => 'Sorenson video, version 3',
788#            mp4v => 'MPEG-4 video',
789#           'dvc '=> 'NTSC DV-25 video',
790#            dvcp => 'PAL DV-25 video',
791#           'gif '=> 'Compuserve Graphics Interchange Format',
792#            h263 => 'H.263 video',
793#            tiff => 'Tagged Image File Format',
794#           'raw '=> 'Uncompressed RGB',
795#           '2vuY'=> "Uncompressed Y'CbCr, 3x8-bit 4:2:2 (2vuY)",
796#           'yuv2'=> "Uncompressed Y'CbCr, 3x8-bit 4:2:2 (yuv2)",
797#            v308 => "Uncompressed Y'CbCr, 8-bit 4:4:4",
798#            v408 => "Uncompressed Y'CbCr, 8-bit 4:4:4:4",
799#            v216 => "Uncompressed Y'CbCr, 10, 12, 14, or 16-bit 4:2:2",
800#            v410 => "Uncompressed Y'CbCr, 10-bit 4:4:4",
801#            v210 => "Uncompressed Y'CbCr, 10-bit 4:2:2",
802#            hvc1 => 'HEVC', #PH
803#        },
804    },
805    10 => {
806        Name => 'VendorID',
807        Format => 'string[4]',
808        RawConv => 'length $val ? $val : undef',
809        PrintConv => \%vendorID,
810        SeparateTable => 'VendorID',
811    },
812  # 14 - ("Quality" in QuickTime docs) ??
813    16 => 'SourceImageWidth',
814    17 => 'SourceImageHeight',
815    18 => { Name => 'XResolution',  Format => 'fixed32u' },
816    20 => { Name => 'YResolution',  Format => 'fixed32u' },
817  # 24 => 'FrameCount', # always 1 (what good is this?)
818    25 => {
819        Name => 'CompressorName',
820        Format => 'string[32]',
821        # (sometimes this is a Pascal string, and sometimes it is a C string)
822        RawConv => q{
823            $val=substr($val,1,ord($1)) if $val=~/^([\0-\x1f])/ and ord($1)<length($val);
824            length $val ? $val : undef;
825        },
826    },
827    41 => 'BitDepth',
828#
829# Observed offsets for child atoms of various CompressorID types:
830#
831#   CompressorID  Offset  Child atoms
832#   -----------   ------  ----------------
833#   avc1          86      avcC, btrt, colr, pasp, fiel, clap, svcC
834#   mp4v          86      esds, pasp
835#   s263          86      d263
836#
837    btrt => {
838        Name => 'BitrateInfo',
839        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Bitrate' },
840    },
841    # Reference for fiel, colr, pasp, clap:
842    # https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9
843    fiel => {
844        Name => 'VideoFieldOrder',
845        ValueConv => 'join(" ", unpack("C*",$val))',
846        PrintConv => [{
847            1 => 'Progressive',
848            2 => '2:1 Interlaced',
849        }],
850    },
851    colr => {
852        Name => 'ColorRepresentation',
853        ValueConv => 'join(" ", substr($val,0,4), unpack("x4n*",$val))',
854    },
855    pasp => {
856        Name => 'PixelAspectRatio',
857        ValueConv => 'join(":", unpack("N*",$val))',
858    },
859    clap => {
860        Name => 'CleanAperture',
861        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::CleanAperture' },
862    },
863    avcC => {
864        # (see http://thompsonng.blogspot.ca/2010/11/mp4-file-format-part-2.html)
865        Name => 'AVCConfiguration',
866        Unknown => 1,
867        Binary => 1,
868    },
869    JPEG => { # (found in CR3 images; used as a flag to identify JpgFromRaw 'vide' stream)
870        Name => 'JPEGInfo',
871        # (4 bytes all zero)
872        Unknown => 1,
873        Binary => 1,
874    },
875    # hvcC - HEVC configuration
876    # svcC - 7 bytes: 00 00 00 00 ff e0 00
877    # esds - elementary stream descriptor
878    # d263
879    gama => { Name => 'Gamma', Format => 'fixed32u' },
880    # mjqt - default quantization table for MJPEG
881    # mjht - default Huffman table for MJPEG
882    # csgm ? (seen in hevc video)
883    CMP1 => { # Canon CR3
884        Name => 'CMP1',
885        SubDirectory => { TagTable => 'Image::ExifTool::Canon::CMP1' },
886    },
887    CDI1 => { # Canon CR3
888        Name => 'CDI1',
889        SubDirectory => {
890            TagTable => 'Image::ExifTool::Canon::CDI1',
891            Start => 4,
892        },
893    },
894    # JPEG - 4 bytes all 0 (Canon CR3)
895    # free - (Canon CR3)
896#
897# spherical video v2 stuff (untested)
898#
899    st3d => {
900        Name => 'Stereoscopic3D',
901        Format => 'int8u',
902        ValueConv => '$val =~ s/.* //; $val', # (remove leading version/flags bytes?)
903        PrintConv => {
904            0 => 'Monoscopic',
905            1 => 'Stereoscopic Top-Bottom',
906            2 => 'Stereoscopic Left-Right',
907            3 => 'Stereoscopic Stereo-Custom', # (provisional in spec as of 2017-10-10)
908        },
909    },
910    sv3d => {
911        Name => 'SphericalVideo',
912        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::sv3d' },
913    },
914);
915
916# 'sv3d' atom information (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md)
917%Image::ExifTool::QuickTime::sv3d = (
918    PROCESS_PROC => \&ProcessMOV,
919    GROUPS => { 2 => 'Video' },
920    NOTES => q{
921        Tags defined by the Spherical Video V2 specification.  See
922        L<https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md>
923        for the specification.
924    },
925    svhd => {
926        Name => 'MetadataSource',
927        Format => 'undef',
928        ValueConv => '$val=~tr/\0//d; $val', # (remove version/flags? and terminator?)
929    },
930    proj => {
931        Name => 'Projection',
932        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::proj' },
933    },
934);
935
936# 'proj' atom information (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md)
937%Image::ExifTool::QuickTime::proj = (
938    PROCESS_PROC => \&ProcessMOV,
939    GROUPS => { 2 => 'Video' },
940    prhd => {
941        Name => 'ProjectionHeader',
942        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::prhd' },
943    },
944    cbmp => {
945        Name => 'CubemapProj',
946        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::cbmp' },
947    },
948    equi => {
949        Name => 'EquirectangularProj',
950        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::equi' },
951    },
952    # mshp - MeshProjection (P.I.T.A. to decode, for not much reward, see ref)
953);
954
955# 'prhd' atom information (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md)
956%Image::ExifTool::QuickTime::prhd = (
957    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
958    GROUPS => { 2 => 'Video' },
959    FORMAT => 'fixed32s',
960    # 0 - version (high 8 bits) / flags (low 24 bits)
961    1 => 'PoseYawDegrees',
962    2 => 'PosePitchDegrees',
963    3 => 'PoseRollDegrees',
964);
965
966# 'cbmp' atom information (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md)
967%Image::ExifTool::QuickTime::cbmp = (
968    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
969    GROUPS => { 2 => 'Video' },
970    FORMAT => 'int32u',
971    # 0 - version (high 8 bits) / flags (low 24 bits)
972    1 => 'Layout',
973    2 => 'Padding',
974);
975
976# 'equi' atom information (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md)
977%Image::ExifTool::QuickTime::equi = (
978    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
979    GROUPS => { 2 => 'Video' },
980    FORMAT => 'int32u', # (actually 0.32 fixed point)
981    # 0 - version (high 8 bits) / flags (low 24 bits)
982    1 => { Name => 'ProjectionBoundsTop',   ValueConv => '$val / 4294967296' },
983    2 => { Name => 'ProjectionBoundsBottom',ValueConv => '$val / 4294967296' },
984    3 => { Name => 'ProjectionBoundsLeft',  ValueConv => '$val / 4294967296' },
985    4 => { Name => 'ProjectionBoundsRight', ValueConv => '$val / 4294967296' },
986);
987
988# 'btrt' atom information (ref http://lists.freedesktop.org/archives/gstreamer-commits/2011-October/054459.html)
989%Image::ExifTool::QuickTime::Bitrate = (
990    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
991    GROUPS => { 2 => 'Video' },
992    FORMAT => 'int32u',
993    PRIORITY => 0, # often filled with zeros
994    0 => 'BufferSize',
995    1 => 'MaxBitrate',
996    2 => 'AverageBitrate',
997);
998
999# 'clap' atom information (ref https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9)
1000%Image::ExifTool::QuickTime::CleanAperture = (
1001    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
1002    GROUPS => { 2 => 'Video' },
1003    FORMAT => 'rational64s',
1004    0 => 'CleanApertureWidth',
1005    1 => 'CleanApertureHeight',
1006    2 => 'CleanApertureOffsetX',
1007    3 => 'CleanApertureOffsetY',
1008);
1009
1010# preview data block
1011%Image::ExifTool::QuickTime::Preview = (
1012    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
1013    WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
1014    CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
1015    GROUPS => { 2 => 'Image' },
1016    FORMAT => 'int16u',
1017    0 => {
1018        Name => 'PreviewDate',
1019        Format => 'int32u',
1020        Groups => { 2 => 'Time' },
1021        %timeInfo,
1022    },
1023    2 => 'PreviewVersion',
1024    3 => {
1025        Name => 'PreviewAtomType',
1026        Format => 'string[4]',
1027    },
1028    5 => 'PreviewAtomIndex',
1029);
1030
1031# movie atoms
1032%Image::ExifTool::QuickTime::Movie = (
1033    PROCESS_PROC => \&ProcessMOV,
1034    WRITE_PROC => \&WriteQuickTime,
1035    GROUPS => { 2 => 'Video' },
1036    mvhd => {
1037        Name => 'MovieHeader',
1038        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MovieHeader' },
1039    },
1040    trak => {
1041        Name => 'Track',
1042        CanCreate => 0, # don't create this atom
1043        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Track' },
1044    },
1045    udta => {
1046        Name => 'UserData',
1047        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::UserData' },
1048    },
1049    meta => { # 'meta' is found here in my EX-F1 MOV sample - PH
1050        Name => 'Meta',
1051        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' },
1052    },
1053    iods => {
1054        Name => 'InitialObjectDescriptor',
1055        Flags => ['Binary','Unknown'],
1056    },
1057    uuid => [
1058        { #11 (MP4 files) (also found in QuickTime::Track)
1059            Name => 'UUID-USMT',
1060            Condition => '$$valPt=~/^USMT!\xd2\x4f\xce\xbb\x88\x69\x5c\xfa\xc9\xc7\x40/',
1061            SubDirectory => {
1062                TagTable => 'Image::ExifTool::QuickTime::UserMedia',
1063                Start => 16,
1064            },
1065        },
1066        { #PH (Canon SX280)
1067            Name => 'UUID-Canon',
1068            Condition => '$$valPt=~/^\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48/',
1069            SubDirectory => {
1070                TagTable => 'Image::ExifTool::Canon::uuid',
1071                Start => 16,
1072            },
1073        },
1074        {
1075            Name => 'UUID-Unknown',
1076            %unknownInfo,
1077        },
1078    ],
1079    cmov => {
1080        Name => 'CompressedMovie',
1081        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::CMovie' },
1082    },
1083    htka => { # (written by HTC One M8 in slow-motion 1280x720 video - PH)
1084        Name => 'HTCTrack',
1085        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Track' },
1086    },
1087   'gps ' => {  # GPS data written by Novatek cameras (parsed in QuickTimeStream.pl)
1088        Name => 'GPSDataList',
1089        Unknown => 1,
1090        Binary => 1,
1091    },
1092    meco => { #ISO14496-12:2015
1093        Name => 'OtherMeta',
1094        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::OtherMeta' },
1095    },
1096    # prfl - Profile (ref 12)
1097    # clip - clipping --> contains crgn (clip region) (ref 12)
1098    # mvex - movie extends --> contains mehd (movie extends header), trex (track extends) (ref 14)
1099    # ICAT - 4 bytes: "6350" (Nikon CoolPix S6900), "6500" (Panasonic FT7)
1100);
1101
1102# (ref CFFMediaFormat-2_1.pdf)
1103%Image::ExifTool::QuickTime::MovieFragment = (
1104    PROCESS_PROC => \&ProcessMOV,
1105    WRITE_PROC => \&WriteQuickTime,
1106    GROUPS => { 2 => 'Video' },
1107    mfhd => {
1108        Name => 'MovieFragmentHeader',
1109        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MovieFragHdr' },
1110    },
1111    traf => {
1112        Name => 'TrackFragment',
1113        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TrackFragment' },
1114    },
1115    meta => { #ISO14496-12:2015
1116        Name => 'Meta',
1117        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' },
1118    },
1119);
1120
1121# (ref CFFMediaFormat-2_1.pdf)
1122%Image::ExifTool::QuickTime::MovieFragHdr = (
1123    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
1124    GROUPS => { 2 => 'Video' },
1125    FORMAT => 'int32u',
1126    1 => 'MovieFragmentSequence',
1127);
1128
1129# (ref CFFMediaFormat-2_1.pdf)
1130%Image::ExifTool::QuickTime::TrackFragment = (
1131    PROCESS_PROC => \&ProcessMOV,
1132    WRITE_PROC => \&WriteQuickTime,
1133    GROUPS => { 2 => 'Video' },
1134    meta => { #ISO14496-12:2015
1135        Name => 'Meta',
1136        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' },
1137    },
1138    # tfhd - track fragment header
1139    # edts - edits --> contains elst (edit list) (ref PH)
1140    # tfdt - track fragment base media decode time
1141    # trik - trick play box
1142    # trun - track fragment run box
1143    # avcn - AVC NAL unit storage box
1144    # secn - sample encryption box
1145    # saio - sample auxiliary information offsets box
1146    # sbgp - sample to group box
1147    # sgpd - sample group description box
1148    # sdtp - independent and disposable samples (ref 5)
1149    # subs - sub-sample information (ref 5)
1150);
1151
1152# movie header data block
1153%Image::ExifTool::QuickTime::MovieHeader = (
1154    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
1155    WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
1156    CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
1157    GROUPS => { 2 => 'Video' },
1158    FORMAT => 'int32u',
1159    DATAMEMBER => [ 0, 1, 2, 3, 4 ],
1160    0 => {
1161        Name => 'MovieHeaderVersion',
1162        Format => 'int8u',
1163        RawConv => '$$self{MovieHeaderVersion} = $val',
1164    },
1165    1 => {
1166        Name => 'CreateDate',
1167        Groups => { 2 => 'Time' },
1168        %timeInfo,
1169        # this is int64u if MovieHeaderVersion == 1 (ref 13)
1170        Hook => '$$self{MovieHeaderVersion} and $format = "int64u", $varSize += 4',
1171    },
1172    2 => {
1173        Name => 'ModifyDate',
1174        Groups => { 2 => 'Time' },
1175        %timeInfo,
1176        # this is int64u if MovieHeaderVersion == 1 (ref 13)
1177        Hook => '$$self{MovieHeaderVersion} and $format = "int64u", $varSize += 4',
1178    },
1179    3 => {
1180        Name => 'TimeScale',
1181        RawConv => '$$self{TimeScale} = $val',
1182    },
1183    4 => {
1184        Name => 'Duration',
1185        %durationInfo,
1186        # this is int64u if MovieHeaderVersion == 1 (ref 13)
1187        Hook => '$$self{MovieHeaderVersion} and $format = "int64u", $varSize += 4',
1188    },
1189    5 => {
1190        Name => 'PreferredRate',
1191        ValueConv => '$val / 0x10000',
1192    },
1193    6 => {
1194        Name => 'PreferredVolume',
1195        Format => 'int16u',
1196        ValueConv => '$val / 256',
1197        PrintConv => 'sprintf("%.2f%%", $val * 100)',
1198    },
1199    9 => {
1200        Name => 'MatrixStructure',
1201        Format => 'fixed32s[9]',
1202        # (the right column is fixed 2.30 instead of 16.16)
1203        ValueConv => q{
1204            my @a = split ' ',$val;
1205            $_ /= 0x4000 foreach @a[2,5,8];
1206            return "@a";
1207        },
1208    },
1209    18 => { Name => 'PreviewTime',      %durationInfo },
1210    19 => { Name => 'PreviewDuration',  %durationInfo },
1211    20 => { Name => 'PosterTime',       %durationInfo },
1212    21 => { Name => 'SelectionTime',    %durationInfo },
1213    22 => { Name => 'SelectionDuration',%durationInfo },
1214    23 => { Name => 'CurrentTime',      %durationInfo },
1215    24 => 'NextTrackID',
1216);
1217
1218# track atoms
1219%Image::ExifTool::QuickTime::Track = (
1220    PROCESS_PROC => \&ProcessMOV,
1221    WRITE_PROC => \&WriteQuickTime,
1222    GROUPS => { 1 => 'Track#', 2 => 'Video' },
1223    tkhd => {
1224        Name => 'TrackHeader',
1225        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TrackHeader' },
1226    },
1227    udta => {
1228        Name => 'UserData',
1229        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::UserData' },
1230    },
1231    mdia => { #MP4
1232        Name => 'Media',
1233        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Media' },
1234    },
1235    meta => { #PH (MOV)
1236        Name => 'Meta',
1237        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' },
1238    },
1239    tref => {
1240        Name => 'TrackRef',
1241        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TrackRef' },
1242    },
1243    tapt => {
1244        Name => 'TrackAperture',
1245        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TrackAperture' },
1246    },
1247    uuid => [
1248        { #11 (MP4 files) (also found in QuickTime::Movie)
1249            Name => 'UUID-USMT',
1250            Condition => '$$valPt=~/^USMT!\xd2\x4f\xce\xbb\x88\x69\x5c\xfa\xc9\xc7\x40/',
1251            SubDirectory => {
1252                TagTable => 'Image::ExifTool::QuickTime::UserMedia',
1253                Start => 16,
1254            },
1255        },
1256        { #https://github.com/google/spatial-media/blob/master/docs/spherical-video-rfc.md
1257            Name => 'SphericalVideoXML',
1258            Condition => '$$valPt=~/^\xff\xcc\x82\x63\xf8\x55\x4a\x93\x88\x14\x58\x7a\x02\x52\x1f\xdd/',
1259            WriteGroup => 'GSpherical', # write only GSpherical XMP tags here
1260            HandlerType => 'vide',      # only write in video tracks
1261            SubDirectory => {
1262                TagTable => 'Image::ExifTool::XMP::Main',
1263                Start => 16,
1264                WriteProc => 'Image::ExifTool::XMP::WriteGSpherical',
1265            },
1266        },
1267        {
1268            Name => 'UUID-Unknown',
1269            %unknownInfo,
1270        },
1271    ],
1272    meco => { #ISO14492-12:2015 pg 83
1273        Name => 'OtherMeta',
1274        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::OtherMeta' },
1275    },
1276    # edts - edits --> contains elst (edit list)
1277    # clip - clipping --> contains crgn (clip region)
1278    # matt - track matt --> contains kmat (compressed matt)
1279    # load - track loading settings
1280    # imap - track input map --> contains '  in' --> contains '  ty', obid
1281    # prfl - Profile (ref 12)
1282);
1283
1284# track header data block
1285%Image::ExifTool::QuickTime::TrackHeader = (
1286    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
1287    WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
1288    CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
1289    GROUPS => { 1 => 'Track#', 2 => 'Video' },
1290    FORMAT => 'int32u',
1291    DATAMEMBER => [ 0, 1, 2, 5, 7 ],
1292    0 => {
1293        Name => 'TrackHeaderVersion',
1294        Format => 'int8u',
1295        Priority => 0,
1296        RawConv => '$$self{TrackHeaderVersion} = $val',
1297    },
1298    1 => {
1299        Name => 'TrackCreateDate',
1300        Priority => 0,
1301        Groups => { 2 => 'Time' },
1302        %timeInfo,
1303        # this is int64u if TrackHeaderVersion == 1 (ref 13)
1304        Hook => '$$self{TrackHeaderVersion} and $format = "int64u", $varSize += 4',
1305    },
1306    2 => {
1307        Name => 'TrackModifyDate',
1308        Priority => 0,
1309        Groups => { 2 => 'Time' },
1310        %timeInfo,
1311        # this is int64u if TrackHeaderVersion == 1 (ref 13)
1312        Hook => '$$self{TrackHeaderVersion} and $format = "int64u", $varSize += 4',
1313    },
1314    3 => {
1315        Name => 'TrackID',
1316        Priority => 0,
1317    },
1318    5 => {
1319        Name => 'TrackDuration',
1320        Priority => 0,
1321        %durationInfo,
1322        # this is int64u if TrackHeaderVersion == 1 (ref 13)
1323        Hook => '$$self{TrackHeaderVersion} and $format = "int64u", $varSize += 4',
1324    },
1325    7 => { # (used only for writing MatrixStructure)
1326        Name => 'ImageSizeLookahead',
1327        Hidden => 1,
1328        Format => 'int32u[14]',
1329        RawConv => '$$self{ImageSizeLookahead} = $val; undef',
1330    },
1331    8 => {
1332        Name => 'TrackLayer',
1333        Format => 'int16u',
1334        Priority => 0,
1335    },
1336    9 => {
1337        Name => 'TrackVolume',
1338        Format => 'int16u',
1339        Priority => 0,
1340        ValueConv => '$val / 256',
1341        PrintConv => 'sprintf("%.2f%%", $val * 100)',
1342    },
1343    10 => {
1344        Name => 'MatrixStructure',
1345        Format => 'fixed32s[9]',
1346        Notes => 'writable for the video track via the Composite Rotation tag',
1347        Writable => 1,
1348        Protected => 1,
1349        Permanent => 1,
1350        # only set rotation if image size is non-zero
1351        RawConvInv => \&GetMatrixStructure,
1352        # (the right column is fixed 2.30 instead of 16.16)
1353        ValueConv => q{
1354            my @a = split ' ',$val;
1355            $_ /= 0x4000 foreach @a[2,5,8];
1356            return "@a";
1357        },
1358        ValueConvInv => q{
1359            my @a = split ' ',$val;
1360            $_ *= 0x4000 foreach @a[2,5,8];
1361            return "@a";
1362        },
1363    },
1364    19 => {
1365        Name => 'ImageWidth',
1366        Priority => 0,
1367        RawConv => \&FixWrongFormat,
1368    },
1369    20 => {
1370        Name => 'ImageHeight',
1371        Priority => 0,
1372        RawConv => \&FixWrongFormat,
1373    },
1374);
1375
1376# user data atoms
1377%Image::ExifTool::QuickTime::UserData = (
1378    PROCESS_PROC => \&ProcessMOV,
1379    WRITE_PROC => \&WriteQuickTime,
1380    CHECK_PROC => \&CheckQTValue,
1381    GROUPS => { 1 => 'UserData', 2 => 'Video' },
1382    WRITABLE => 1,
1383    PREFERRED => 1, # (preferred over Keys tags when writing)
1384    FORMAT => 'string',
1385    WRITE_GROUP => 'UserData',
1386    LANG_INFO => \&GetLangInfo,
1387    NOTES => q{
1388        Tag ID's beginning with the copyright symbol (hex 0xa9) are multi-language
1389        text.  Alternate language tags are accessed by adding a dash followed by a
1390        3-character ISO 639-2 language code to the tag name.  ExifTool will extract
1391        any multi-language user data tags found, even if they aren't in this table.
1392        Note when creating new tags,
1393        L<ItemList|Image::ExifTool::TagNames/QuickTime ItemList Tags> tags are
1394        preferred over these, so to create the tag when a same-named ItemList tag
1395        exists, either "UserData" must be specified (eg. C<-UserData:Artist=Monet>
1396        on the command line), or the PREFERRED level must be changed via
1397        L<the config file|../config.html#PREF>.
1398    },
1399    "\xa9cpy" => { Name => 'Copyright',  Groups => { 2 => 'Author' } },
1400    "\xa9day" => {
1401        Name => 'ContentCreateDate',
1402        Groups => { 2 => 'Time' },
1403        Shift => 'Time',
1404        # handle values in the form "2010-02-12T13:27:14-0800" (written by Apple iPhone)
1405        ValueConv => q{
1406            require Image::ExifTool::XMP;
1407            $val =  Image::ExifTool::XMP::ConvertXMPDate($val);
1408            $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary
1409            return $val;
1410        },
1411        ValueConvInv => q{
1412            require Image::ExifTool::XMP;
1413            my $tmp = Image::ExifTool::XMP::FormatXMPDate($val);
1414            ($val = $tmp) =~ s/([-+]\d{2}):(\d{2})$/$1$2/ if defined $tmp; # remove time zone colon
1415            return $val;
1416        },
1417        PrintConv => '$self->ConvertDateTime($val)',
1418        PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist)
1419    },
1420    "\xa9ART" => 'Artist', #PH (iTunes 8.0.2)
1421    "\xa9alb" => 'Album', #PH (iTunes 8.0.2)
1422    "\xa9arg" => 'Arranger', #12
1423    "\xa9ark" => 'ArrangerKeywords', #12
1424    "\xa9cmt" => 'Comment', #PH (iTunes 8.0.2)
1425    "\xa9cok" => 'ComposerKeywords', #12
1426    "\xa9com" => 'Composer', #12
1427    "\xa9dir" => 'Director', #12
1428    "\xa9ed1" => 'Edit1',
1429    "\xa9ed2" => 'Edit2',
1430    "\xa9ed3" => 'Edit3',
1431    "\xa9ed4" => 'Edit4',
1432    "\xa9ed5" => 'Edit5',
1433    "\xa9ed6" => 'Edit6',
1434    "\xa9ed7" => 'Edit7',
1435    "\xa9ed8" => 'Edit8',
1436    "\xa9ed9" => 'Edit9',
1437    "\xa9fmt" => 'Format',
1438    "\xa9gen" => 'Genre', #PH (iTunes 8.0.2)
1439    "\xa9grp" => 'Grouping', #PH (NC)
1440    "\xa9inf" => 'Information',
1441    "\xa9isr" => 'ISRCCode', #12
1442    "\xa9lab" => 'RecordLabelName', #12
1443    "\xa9lal" => 'RecordLabelURL', #12
1444    "\xa9lyr" => 'Lyrics', #PH (NC)
1445    "\xa9mak" => 'Make', #12
1446    "\xa9mal" => 'MakerURL', #12
1447    "\xa9mod" => 'Model', #PH
1448    "\xa9nam" => 'Title', #12
1449    "\xa9pdk" => 'ProducerKeywords', #12
1450    "\xa9phg" => 'RecordingCopyright', #12
1451    "\xa9prd" => 'Producer',
1452    "\xa9prf" => 'Performers',
1453    "\xa9prk" => 'PerformerKeywords', #12
1454    "\xa9prl" => 'PerformerURL',
1455    "\xa9req" => 'Requirements',
1456    "\xa9snk" => 'SubtitleKeywords', #12
1457    "\xa9snm" => 'Subtitle', #12
1458    "\xa9src" => 'SourceCredits', #12
1459    "\xa9swf" => 'SongWriter', #12
1460    "\xa9swk" => 'SongWriterKeywords', #12
1461    "\xa9swr" => 'SoftwareVersion', #12
1462    "\xa9too" => 'Encoder', #PH (NC)
1463    "\xa9trk" => 'Track', #PH (NC)
1464    "\xa9wrt" => { Name => 'Composer', Avoid => 1 }, # ("\xa9com" is preferred in UserData)
1465    "\xa9xyz" => { #PH (iPhone 3GS)
1466        Name => 'GPSCoordinates',
1467        Groups => { 2 => 'Location' },
1468        ValueConv => \&ConvertISO6709,
1469        ValueConvInv => \&ConvInvISO6709,
1470        PrintConv => \&PrintGPSCoordinates,
1471        PrintConvInv => \&PrintInvGPSCoordinates,
1472    },
1473    # \xa9 tags written by DJI Phantom 3: (ref PH)
1474    "\xa9xsp" => 'SpeedX', #PH (guess)
1475    "\xa9ysp" => 'SpeedY', #PH (guess)
1476    "\xa9zsp" => 'SpeedZ', #PH (guess)
1477    "\xa9fpt" => 'Pitch', #PH
1478    "\xa9fyw" => 'Yaw', #PH
1479    "\xa9frl" => 'Roll', #PH
1480    "\xa9gpt" => 'CameraPitch', #PH
1481    "\xa9gyw" => 'CameraYaw', #PH
1482    "\xa9grl" => 'CameraRoll', #PH
1483    "\xa9enc" => 'EncoderID', #PH (forum9271)
1484    # and the following entries don't have the proper 4-byte header for \xa9 tags:
1485    "\xa9dji" => { Name => 'UserData_dji', Format => 'undef', Binary => 1, Unknown => 1, Hidden => 1 },
1486    "\xa9res" => { Name => 'UserData_res', Format => 'undef', Binary => 1, Unknown => 1, Hidden => 1 },
1487    "\xa9uid" => { Name => 'UserData_uid', Format => 'undef', Binary => 1, Unknown => 1, Hidden => 1 },
1488    "\xa9mdl" => {
1489        Name => 'Model',
1490        Notes => 'non-standard-format DJI tag',
1491        Format => 'string',
1492        Avoid => 1,
1493    },
1494    # end DJI tags
1495    name => 'Name',
1496    WLOC => {
1497        Name => 'WindowLocation',
1498        Format => 'int16u',
1499    },
1500    LOOP => {
1501        Name => 'LoopStyle',
1502        Format => 'int32u',
1503        PrintConv => {
1504            1 => 'Normal',
1505            2 => 'Palindromic',
1506        },
1507    },
1508    SelO => {
1509        Name => 'PlaySelection',
1510        Format => 'int8u',
1511    },
1512    AllF => {
1513        Name => 'PlayAllFrames',
1514        Format => 'int8u',
1515    },
1516    meta => {
1517        Name => 'Meta',
1518        SubDirectory => {
1519            TagTable => 'Image::ExifTool::QuickTime::Meta',
1520            Start => 4, # must skip 4-byte version number header
1521        },
1522    },
1523   'ptv '=> {
1524        Name => 'PrintToVideo',
1525        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Video' },
1526    },
1527    hnti => {
1528        Name => 'HintInfo',
1529        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HintInfo' },
1530    },
1531    hinf => {
1532        Name => 'HintTrackInfo',
1533        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HintTrackInfo' },
1534    },
1535    hinv => 'HintVersion', #PH (guess)
1536    XMP_ => { #PH (Adobe CS3 Bridge)
1537        Name => 'XMP',
1538        WriteGroup => 'XMP',    # (write main tags here)
1539        # *** this is where ExifTool writes XMP in MOV videos (as per XMP spec) ***
1540        SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' },
1541    },
1542    # the following are 3gp tags, references:
1543    # http://atomicparsley.sourceforge.net
1544    # http://www.3gpp.org/ftp/tsg_sa/WG4_CODEC/TSGS4_25/Docs/
1545    # (note that all %langText tags are Avoid => 1)
1546    cprt => { Name => 'Copyright',  %langText, Groups => { 2 => 'Author' } },
1547    auth => { Name => 'Author',     %langText, Groups => { 2 => 'Author' } },
1548    titl => { Name => 'Title',      %langText },
1549    dscp => { Name => 'Description',%langText },
1550    perf => { Name => 'Performer',  %langText },
1551    gnre => { Name => 'Genre',      %langText },
1552    albm => { Name => 'Album',      %langText },
1553    coll => { Name => 'CollectionName', %langText }, #17
1554    rtng => {
1555        Name => 'Rating',
1556        # (4-byte flags, 4-char entity, 4-char criteria, 2-byte lang, string)
1557        RawConv => q{
1558            return '<err>' unless length $val >= 14;
1559            my $str = 'Entity=' . substr($val,4,4) . ' Criteria=' . substr($val,8,4);
1560            $str =~ tr/\0-\x1f\x7f-\xff//d; # remove unprintable characters
1561            my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 12));
1562            $lang = $lang ? "($lang) " : '';
1563            $val = substr($val, 14);
1564            $val = $self->Decode($val, 'UCS2') if $val =~ /^\xfe\xff/;
1565            return $lang . $str . ' ' . $val;
1566        },
1567    },
1568    clsf => {
1569        Name => 'Classification',
1570        # (4-byte flags, 4-char entity, 2-byte index, 2-byte lang, string)
1571        RawConv => q{
1572            return '<err>' unless length $val >= 12;
1573            my $str = 'Entity=' . substr($val,4,4) . ' Index=' . Get16u(\$val,8);
1574            $str =~ tr/\0-\x1f\x7f-\xff//d; # remove unprintable characters
1575            my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 10));
1576            $lang = $lang ? "($lang) " : '';
1577            $val = substr($val, 12);
1578            $val = $self->Decode($val, 'UCS2') if $val =~ /^\xfe\xff/;
1579            return $lang . $str . ' ' . $val;
1580        },
1581    },
1582    kywd => {
1583        Name => 'Keywords',
1584        # (4 byte flags, 2-byte lang, 1-byte count, count x pascal strings)
1585        RawConv => q{
1586            return '<err>' unless length $val >= 7;
1587            my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 4));
1588            $lang = $lang ? "($lang) " : '';
1589            my $num = Get8u(\$val, 6);
1590            my ($i, @vals);
1591            my $pos = 7;
1592            for ($i=0; $i<$num; ++$i) {
1593                last if $pos >= length $val;
1594                my $len = Get8u(\$val, $pos++);
1595                last if $pos + $len > length $val;
1596                my $v = substr($val, $pos, $len);
1597                $v = $self->Decode($v, 'UCS2') if $v =~ /^\xfe\xff/;
1598                push @vals, $v;
1599                $pos += $len;
1600            }
1601            my $sep = $self->Options('ListSep');
1602            return $lang . join($sep, @vals);
1603        },
1604    },
1605    loci => {
1606        Name => 'LocationInformation',
1607        Groups => { 2 => 'Location' },
1608        # (4-byte flags, 2-byte lang, location string, 1-byte role, 4-byte fixed longitude,
1609        #  4-byte fixed latitude, 4-byte fixed altitude, body string, notes string)
1610        RawConv => q{
1611            return '<err>' unless length $val >= 6;
1612            my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 4));
1613            $lang = $lang ? "($lang) " : '';
1614            $val = substr($val, 6);
1615            my $str;
1616            if ($val =~ /^\xfe\xff/) {
1617                $val =~ s/^(\xfe\xff(.{2})*?)\0\0//s or return '<err>';
1618                $str = $self->Decode($1, 'UCS2');
1619            } else {
1620                $val =~ s/^(.*?)\0//s or return '<err>';
1621                $str = $1;
1622            }
1623            $str = '(none)' unless length $str;
1624            return '<err>' if length $val < 13;
1625            my $role = Get8u(\$val, 0);
1626            my $lon = GetFixed32s(\$val, 1);
1627            my $lat = GetFixed32s(\$val, 5);
1628            my $alt = GetFixed32s(\$val, 9);
1629            my $roleStr = {0=>'shooting',1=>'real',2=>'fictional',3=>'reserved'}->{$role};
1630            $str .= ' Role=' . ($roleStr || "unknown($role)");
1631            $str .= sprintf(' Lat=%.5f Lon=%.5f Alt=%.2f', $lat, $lon, $alt);
1632            $val = substr($val, 13);
1633            if ($val =~ s/^(\xfe\xff(.{2})*?)\0\0//s) {
1634                $str .= ' Body=' . $self->Decode($1, 'UCS2');
1635            } elsif ($val =~ s/^(.*?)\0//s) {
1636                $str .= " Body=$1";
1637            }
1638            if ($val =~ s/^(\xfe\xff(.{2})*?)\0\0//s) {
1639                $str .= ' Notes=' . $self->Decode($1, 'UCS2');
1640            } elsif ($val =~ s/^(.*?)\0//s) {
1641                $str .= " Notes=$1";
1642            }
1643            return $lang . $str;
1644        },
1645    },
1646    yrrc => {
1647        Name => 'Year',
1648        Groups => { 2 => 'Time' },
1649        RawConv => 'length($val) >= 6 ? Get16u(\$val,4) : "<err>"',
1650    },
1651    urat => { #17
1652        Name => 'UserRating',
1653        RawConv => q{
1654            return '<err>' unless length $val >= 8;
1655            return Get8u(\$val, 7);
1656        },
1657    },
1658    # tsel - TrackSelection (ref 17)
1659    # Apple tags (ref 16[dead] -- see ref 25 instead)
1660    angl => { Name => 'CameraAngle',  Format => 'string' }, # (NC)
1661    clfn => { Name => 'ClipFileName', Format => 'string' }, # (NC)
1662    clid => { Name => 'ClipID',       Format => 'string' }, # (NC)
1663    cmid => { Name => 'CameraID',     Format => 'string' }, # (NC)
1664    cmnm => { # (NC)
1665        Name => 'Model',
1666        Description => 'Camera Model Name',
1667        Avoid => 1,
1668        Format => 'string', # (necessary to remove the trailing NULL)
1669    },
1670    date => {
1671        Name => 'DateTimeOriginal',
1672        Description => 'Date/Time Original',
1673        Groups => { 2 => 'Time' },
1674        Notes => q{
1675            Apple Photos has been reported to show a crazy date/time for some MP4 files
1676            containing this tag, but perhaps only if it is missing a time zone
1677        }, #forum10690/11125
1678        Shift => 'Time',
1679        ValueConv => q{
1680            require Image::ExifTool::XMP;
1681            $val =  Image::ExifTool::XMP::ConvertXMPDate($val);
1682            $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary
1683            return $val;
1684        },
1685        ValueConvInv => q{
1686            require Image::ExifTool::XMP;
1687            $val =  Image::ExifTool::XMP::FormatXMPDate($val);
1688            $val =~ s/([-+]\d{2}):(\d{2})$/$1$2/; # remove time zone colon
1689            return $val;
1690        },
1691        PrintConv => '$self->ConvertDateTime($val)',
1692        PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist)
1693    },
1694    manu => { # (SX280)
1695        Name => 'Make',
1696        Avoid => 1,
1697        # (with Canon there are 6 unknown bytes before the model: "\0\0\0\0\x15\xc7")
1698        RawConv => '$val=~s/^\0{4}..//s; $val=~s/\0.*//; $val',
1699    },
1700    modl => { # (Samsung GT-S8530, Canon SX280)
1701        Name => 'Model',
1702        Description => 'Camera Model Name',
1703        Avoid => 1,
1704        # (with Canon there are 6 unknown bytes before the model: "\0\0\0\0\x15\xc7")
1705        RawConv => '$val=~s/^\0{4}..//s; $val=~s/\0.*//; $val',
1706    },
1707    reel => { Name => 'ReelName',     Format => 'string' }, # (NC)
1708    scen => { Name => 'Scene',        Format => 'string' }, # (NC)
1709    shot => { Name => 'ShotName',     Format => 'string' }, # (NC)
1710    slno => { Name => 'SerialNumber', Format => 'string' }, # (NC)
1711    apmd => { Name => 'ApertureMode', Format => 'undef' }, #20
1712    kgtt => { #http://lists.ffmpeg.org/pipermail/ffmpeg-devel-irc/2012-June/000707.html
1713        # 'TrackType' will expand to 'Track#Type' when found inside a track
1714        Name => 'TrackType',
1715        # set flag to process this as international text
1716        # even though the tag ID doesn't start with 0xa9
1717        IText => 4, # IText with 4-byte header
1718    },
1719    chpl => { # (Nero chapter list)
1720        Name => 'ChapterList',
1721        ValueConv => \&ConvertChapterList,
1722        PrintConv => \&PrintChapter,
1723    },
1724    # ndrm - 7 bytes (0 0 0 1 0 0 0) Nero Digital Rights Management? (PH)
1725    # other non-Apple tags (ref 16)
1726    # hpix - HipixRichPicture (ref 16, HIPIX)
1727    # strk - sub-track information (ref 16, ISO)
1728#
1729# Manufacturer-specific metadata
1730#
1731    TAGS => [ #PH
1732        # these tags were initially discovered in a Pentax movie,
1733        # but similar information is found in videos from other manufacturers
1734        {
1735            Name => 'FujiFilmTags',
1736            Condition => '$$valPt =~ /^FUJIFILM DIGITAL CAMERA\0/',
1737            SubDirectory => {
1738                TagTable => 'Image::ExifTool::FujiFilm::MOV',
1739                ByteOrder => 'LittleEndian',
1740            },
1741        },
1742        {
1743            Name => 'KodakTags',
1744            Condition => '$$valPt =~ /^EASTMAN KODAK COMPANY/',
1745            SubDirectory => {
1746                TagTable => 'Image::ExifTool::Kodak::MOV',
1747                ByteOrder => 'LittleEndian',
1748            },
1749        },
1750        {
1751            Name => 'KonicaMinoltaTags',
1752            Condition => '$$valPt =~ /^KONICA MINOLTA DIGITAL CAMERA/',
1753            SubDirectory => {
1754                TagTable => 'Image::ExifTool::Minolta::MOV1',
1755                ByteOrder => 'LittleEndian',
1756            },
1757        },
1758        {
1759            Name => 'MinoltaTags',
1760            Condition => '$$valPt =~ /^MINOLTA DIGITAL CAMERA/',
1761            SubDirectory => {
1762                TagTable => 'Image::ExifTool::Minolta::MOV2',
1763                ByteOrder => 'LittleEndian',
1764            },
1765        },
1766        {
1767            Name => 'NikonTags',
1768            Condition => '$$valPt =~ /^NIKON DIGITAL CAMERA\0/',
1769            SubDirectory => {
1770                TagTable => 'Image::ExifTool::Nikon::MOV',
1771                ByteOrder => 'LittleEndian',
1772            },
1773        },
1774        {
1775            Name => 'OlympusTags1',
1776            Condition => '$$valPt =~ /^OLYMPUS DIGITAL CAMERA\0.{9}\x01\0/s',
1777            SubDirectory => {
1778                TagTable => 'Image::ExifTool::Olympus::MOV1',
1779                ByteOrder => 'LittleEndian',
1780            },
1781        },
1782        {
1783            Name => 'OlympusTags2',
1784            Condition => '$$valPt =~ /^OLYMPUS DIGITAL CAMERA(?!\0.{21}\x0a\0{3})/s',
1785            SubDirectory => {
1786                TagTable => 'Image::ExifTool::Olympus::MOV2',
1787                ByteOrder => 'LittleEndian',
1788            },
1789        },
1790        {
1791            Name => 'OlympusTags3',
1792            Condition => '$$valPt =~ /^OLYMPUS DIGITAL CAMERA\0/',
1793            SubDirectory => {
1794                TagTable => 'Image::ExifTool::Olympus::MP4',
1795                ByteOrder => 'LittleEndian',
1796            },
1797        },
1798        {
1799            Name => 'OlympusTags4',
1800            Condition => '$$valPt =~ /^.{16}OLYM\0/s',
1801            SubDirectory => {
1802                TagTable => 'Image::ExifTool::Olympus::MOV3',
1803                Start => 12,
1804            },
1805        },
1806        {
1807            Name => 'PentaxTags',
1808            Condition => '$$valPt =~ /^PENTAX DIGITAL CAMERA\0/',
1809            SubDirectory => {
1810                TagTable => 'Image::ExifTool::Pentax::MOV',
1811                ByteOrder => 'LittleEndian',
1812            },
1813        },
1814        {
1815            Name => 'SamsungTags',
1816            Condition => '$$valPt =~ /^SAMSUNG DIGITAL CAMERA\0/',
1817            SubDirectory => {
1818                TagTable => 'Image::ExifTool::Samsung::MP4',
1819                ByteOrder => 'LittleEndian',
1820            },
1821        },
1822        {
1823            Name => 'SanyoMOV',
1824            Condition => q{
1825                $$valPt =~ /^SANYO DIGITAL CAMERA\0/ and
1826                $self->{VALUE}->{FileType} eq "MOV"
1827            },
1828            SubDirectory => {
1829                TagTable => 'Image::ExifTool::Sanyo::MOV',
1830                ByteOrder => 'LittleEndian',
1831            },
1832        },
1833        {
1834            Name => 'SanyoMP4',
1835            Condition => q{
1836                $$valPt =~ /^SANYO DIGITAL CAMERA\0/ and
1837                $self->{VALUE}->{FileType} eq "MP4"
1838            },
1839            SubDirectory => {
1840                TagTable => 'Image::ExifTool::Sanyo::MP4',
1841                ByteOrder => 'LittleEndian',
1842            },
1843        },
1844        {
1845            Name => 'UnknownTags',
1846            Unknown => 1,
1847            Binary => 1
1848        },
1849    ],
1850    # ---- Canon ----
1851    CNCV => { Name => 'CompressorVersion', Format => 'string' }, #PH (5D Mark II)
1852    CNMN => {
1853        Name => 'Model', #PH (EOS 550D)
1854        Description => 'Camera Model Name',
1855        Avoid => 1,
1856        Format => 'string', # (necessary to remove the trailing NULL)
1857    },
1858    CNFV => { Name => 'FirmwareVersion', Format => 'string' }, #PH (EOS 550D)
1859    CNTH => { #PH (PowerShot S95)
1860        Name => 'CanonCNTH',
1861        SubDirectory => { TagTable => 'Image::ExifTool::Canon::CNTH' },
1862    },
1863    CNOP => { #PH (7DmkII)
1864        Name => 'CanonCNOP',
1865        SubDirectory => { TagTable => 'Image::ExifTool::Canon::CNOP' },
1866    },
1867    # CNDB - 2112 bytes (550D)
1868    # CNDM - 4 bytes - 0xff,0xd8,0xff,0xd9 (S95)
1869    # CNDG - 10232 bytes, mostly zeros (N100)
1870    # ---- Casio ----
1871    QVMI => { #PH
1872        Name => 'CasioQVMI',
1873        # Casio stores standard EXIF-format information in MOV videos (eg. EX-S880)
1874        SubDirectory => {
1875            TagTable => 'Image::ExifTool::Exif::Main',
1876            ProcessProc => \&Image::ExifTool::Exif::ProcessExif, # (because ProcessMOV is default)
1877            DirName => 'IFD0',
1878            Multi => 0, # (no NextIFD pointer)
1879            Start => 10,
1880            ByteOrder => 'BigEndian',
1881        },
1882    },
1883    # ---- FujiFilm ----
1884    FFMV => { #PH (FinePix HS20EXR)
1885        Name => 'FujiFilmFFMV',
1886        SubDirectory => { TagTable => 'Image::ExifTool::FujiFilm::FFMV' },
1887    },
1888    MVTG => { #PH (FinePix HS20EXR)
1889        Name => 'FujiFilmMVTG',
1890        SubDirectory => {
1891            TagTable => 'Image::ExifTool::Exif::Main',
1892            ProcessProc => \&Image::ExifTool::Exif::ProcessExif, # (because ProcessMOV is default)
1893            DirName => 'IFD0',
1894            Start => 16,
1895            Base => '$start',
1896            ByteOrder => 'LittleEndian',
1897        },
1898    },
1899    # ---- Garmin ---- (ref PH)
1900    uuid => [{
1901        Name => 'GarminSoftware', # (NC)
1902        Condition => '$$valPt =~ /^VIRBactioncamera/',
1903        RawConv => 'substr($val, 16)',
1904        RawConvInv => '"VIRBactioncamera$val"',
1905    },{
1906        # have seen "28 f3 11 e2 b7 91 4f 6f 94 e2 4f 5d ea cb 3c 01" for RicohThetaZ1 accelerometer RADT data (not yet decoded)
1907        Name => 'UUID-Unknown',
1908        Writable => 0,
1909        %unknownInfo,
1910    }],
1911    pmcc => {
1912        Name => 'GarminSettings',
1913        ValueConv => 'substr($val, 4)',
1914        ValueConvInv => '"\0\0\0\x01$val"',
1915    },
1916    # hmtp - "\0\0\0\x01" followed by 408 bytes of zero
1917    # vrin - "\0\0\0\x01" followed by 8 bytes of zero
1918    # ---- GoPro ---- (ref PH)
1919    GoPr => 'GoProType', # (Hero3+)
1920    FIRM => { Name => 'FirmwareVersion', Avoid => 1 }, # (Hero4)
1921    LENS => 'LensSerialNumber', # (Hero4)
1922    CAME => { # (Hero4)
1923        Name => 'SerialNumberHash',
1924        Description => 'Camera Serial Number Hash',
1925        ValueConv => 'unpack("H*",$val)',
1926        ValueConvInv => 'pack("H*",$val)',
1927    },
1928    # SETT? 12 bytes (Hero4)
1929    # MUID? 32 bytes (Hero4, starts with serial number hash)
1930    # HMMT? 404 bytes (Hero4, all zero)
1931    # BCID? 26 bytes (Hero5, all zero), 36 bytes GoPro Max
1932    # GUMI? 16 bytes (Hero5)
1933   "FOV\0" => 'FieldOfView', #forum8938 (Hero2) seen: "Wide"
1934    GPMF => {
1935        Name => 'GoProGPMF',
1936        SubDirectory => { TagTable => 'Image::ExifTool::GoPro::GPMF' },
1937    },
1938    # free (all zero)
1939    "\xa9TSC" => 'StartTimeScale', # (Hero6)
1940    "\xa9TSZ" => 'StartTimeSampleSize', # (Hero6)
1941    "\xa9TIM" => 'StartTimecode', #PH (NC)
1942    # --- HTC ----
1943    htcb => {
1944        Name => 'HTCBinary',
1945        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HTCBinary' },
1946    },
1947    # ---- Kodak ----
1948    DcMD => {
1949        Name => 'KodakDcMD',
1950        SubDirectory => { TagTable => 'Image::ExifTool::Kodak::DcMD' },
1951    },
1952    SNum => { Name => 'SerialNumber', Avoid => 1, Groups => { 2 => 'Camera' } },
1953    ptch => { Name => 'Pitch', Format => 'rational64s', Avoid => 1 }, # Units??
1954    _yaw => { Name => 'Yaw',   Format => 'rational64s', Avoid => 1 }, # Units??
1955    roll => { Name => 'Roll',  Format => 'rational64s', Avoid => 1 }, # Units??
1956    _cx_ => { Name => 'CX',    Format => 'rational64s', Unknown => 1 },
1957    _cy_ => { Name => 'CY',    Format => 'rational64s', Unknown => 1 },
1958    rads => { Name => 'Rads',  Format => 'rational64s', Unknown => 1 },
1959    lvlm => { Name => 'LevelMeter', Format => 'rational64s', Unknown => 1 }, # (guess)
1960    Lvlm => { Name => 'LevelMeter', Format => 'rational64s', Unknown => 1 }, # (guess)
1961    pose => { Name => 'pose', SubDirectory => { TagTable => 'Image::ExifTool::Kodak::pose' } },
1962    # AMBA => Ambarella AVC atom (unknown data written by Kodak Playsport video cam)
1963    # tmlp - 1 byte: 0 (PixPro SP360/4KVR360)
1964    # pivi - 72 bytes (PixPro SP360)
1965    # pive - 12 bytes (PixPro SP360)
1966    # loop - 4 bytes: 0 0 0 0 (PixPro 4KVR360)
1967    # m cm - 2 bytes: 0 0 (PixPro 4KVR360)
1968    # m ev - 2 bytes: 0 0 (PixPro SP360/4KVR360) (exposure comp?)
1969    # m vr - 2 bytes: 0 1 (PixPro 4KVR360) (virtual reality?)
1970    # m wb - 4 bytes: 0 0 0 0 (PixPro SP360/4KVR360) (white balance?)
1971    # mclr - 4 bytes: 0 0 0 0 (PixPro SP360/4KVR360)
1972    # mmtr - 4 bytes: 0,6 0 0 0 (PixPro SP360/4KVR360)
1973    # mflr - 4 bytes: 0 0 0 0 (PixPro SP360)
1974    # lvlm - 24 bytes (PixPro SP360)
1975    # Lvlm - 24 bytes (PixPro 4KVR360)
1976    # ufdm - 4 bytes: 0 0 0 1 (PixPro SP360)
1977    # mtdt - 1 byte: 0 (PixPro SP360/4KVR360)
1978    # gdta - 75240 bytes (PixPro SP360)
1979    # EIS1 - 4 bytes: 03 07 00 00 (PixPro 4KVR360)
1980    # EIS2 - 4 bytes: 04 97 00 00 (PixPro 4KVR360)
1981    # ---- LG ----
1982    adzc => { Name => 'Unknown_adzc', Unknown => 1, Hidden => 1, %langText }, # "false\0/","true\0/"
1983    adze => { Name => 'Unknown_adze', Unknown => 1, Hidden => 1, %langText }, # "false\0/"
1984    adzm => { Name => 'Unknown_adzm', Unknown => 1, Hidden => 1, %langText }, # "\x0e\x04/","\x10\x06"
1985    # ---- Microsoft ----
1986    Xtra => { #PH (microsoft)
1987        Name => 'MicrosoftXtra',
1988        SubDirectory => { TagTable => 'Image::ExifTool::Microsoft::Xtra' },
1989    },
1990    # ---- Minolta ----
1991    MMA0 => { #PH (DiMage 7Hi)
1992        Name => 'MinoltaMMA0',
1993        SubDirectory => { TagTable => 'Image::ExifTool::Minolta::MMA' },
1994    },
1995    MMA1 => { #PH (Dimage A2)
1996        Name => 'MinoltaMMA1',
1997        SubDirectory => { TagTable => 'Image::ExifTool::Minolta::MMA' },
1998    },
1999    # ---- Nikon ----
2000    NCDT => { #PH
2001        Name => 'NikonNCDT',
2002        SubDirectory => { TagTable => 'Image::ExifTool::Nikon::NCDT' },
2003    },
2004    # ---- Olympus ----
2005    scrn => { #PH (TG-810)
2006        Name => 'OlympusPreview',
2007        Condition => '$$valPt =~ /^.{4}\xff\xd8\xff\xdb/s',
2008        SubDirectory => { TagTable => 'Image::ExifTool::Olympus::scrn' },
2009    },
2010    # ---- Panasonic/Leica ----
2011    PANA => { #PH
2012        Name => 'PanasonicPANA',
2013        SubDirectory => { TagTable => 'Image::ExifTool::Panasonic::PANA' },
2014    },
2015    LEIC => { #PH
2016        Name => 'LeicaLEIC',
2017        SubDirectory => { TagTable => 'Image::ExifTool::Panasonic::PANA' },
2018    },
2019    # ---- Pentax ----
2020    thmb => [ # (apparently defined by 3gpp, ref 16)
2021        { #PH (Pentax Q)
2022            Name => 'MakerNotePentax5a',
2023            Condition => '$$valPt =~ /^PENTAX \0II/',
2024            SubDirectory => {
2025                TagTable => 'Image::ExifTool::Pentax::Main',
2026                ProcessProc => \&Image::ExifTool::Exif::ProcessExif, # (because ProcessMOV is default)
2027                Start => 10,
2028                Base => '$start - 10',
2029                ByteOrder => 'LittleEndian',
2030            },
2031        },{ #PH (TG-810)
2032            Name => 'OlympusThumbnail',
2033            Condition => '$$valPt =~ /^.{4}\xff\xd8\xff\xdb/s',
2034            SubDirectory => { TagTable => 'Image::ExifTool::Olympus::thmb' },
2035        },{ #17 (format is in bytes 3-7)
2036            Name => 'ThumbnailImage',
2037            Condition => '$$valPt =~ /^.{8}\xff\xd8\xff\xdb/s',
2038            Groups => { 2 => 'Preview' },
2039            RawConv => 'substr($val, 8)',
2040            Binary => 1,
2041        },{ #17 (format is in bytes 3-7)
2042            Name => 'ThumbnailPNG',
2043            Condition => '$$valPt =~ /^.{8}\x89PNG\r\n\x1a\n/s',
2044            Groups => { 2 => 'Preview' },
2045            RawConv => 'substr($val, 8)',
2046            Binary => 1,
2047        },{
2048            Name => 'UnknownThumbnail',
2049            Groups => { 2 => 'Preview' },
2050            Binary => 1,
2051        },
2052    ],
2053    PENT => { #PH
2054        Name => 'PentaxPENT',
2055        SubDirectory => {
2056            TagTable => 'Image::ExifTool::Pentax::PENT',
2057            ByteOrder => 'LittleEndian',
2058        },
2059    },
2060    PXTH => { #PH (Pentax K-01)
2061        Name => 'PentaxPreview',
2062        SubDirectory => { TagTable => 'Image::ExifTool::Pentax::PXTH' },
2063    },
2064    PXMN => [{ #PH (Pentax K-01)
2065        Name => 'MakerNotePentax5b',
2066        Condition => '$$valPt =~ /^PENTAX \0MM/',
2067        SubDirectory => {
2068            TagTable => 'Image::ExifTool::Pentax::Main',
2069            ProcessProc => \&Image::ExifTool::Exif::ProcessExif, # (because ProcessMOV is default)
2070            Start => 10,
2071            Base => '$start - 10',
2072            ByteOrder => 'BigEndian',
2073        },
2074    },{ #PH (Pentax 645Z)
2075        Name => 'MakerNotePentax5c',
2076        Condition => '$$valPt =~ /^PENTAX \0II/',
2077        SubDirectory => {
2078            TagTable => 'Image::ExifTool::Pentax::Main',
2079            ProcessProc => \&Image::ExifTool::Exif::ProcessExif, # (because ProcessMOV is default)
2080            Start => 10,
2081            Base => '$start - 10',
2082            ByteOrder => 'LittleEndian',
2083        },
2084    },{
2085        Name => 'MakerNotePentaxUnknown',
2086        Binary => 1,
2087    }],
2088    # ---- Ricoh ----
2089    RTHU => { #PH (GR)
2090        Name => 'PreviewImage',
2091        Groups => { 2 => 'Preview' },
2092        RawConv => '$self->ValidateImage(\$val, $tag)',
2093    },
2094    RMKN => { #PH (GR)
2095        Name => 'RicohRMKN',
2096        SubDirectory => {
2097            TagTable => 'Image::ExifTool::Exif::Main',
2098            ProcessProc => \&Image::ExifTool::ProcessTIFF, # (because ProcessMOV is default)
2099        },
2100    },
2101    '@mak' => { Name => 'Make',     Avoid => 1 },
2102    '@mod' => { Name => 'Model',    Avoid => 1 },
2103    '@swr' => { Name => 'SoftwareVersion', Avoid => 1 },
2104    '@day' => {
2105        Name => 'ContentCreateDate',
2106        Notes => q{
2107            some stupid Ricoh programmer used the '@' symbol instead of the copyright
2108            symbol in these tag ID's for the Ricoh Theta Z1 and maybe other models
2109        },
2110        Groups => { 2 => 'Time' },
2111        Shift => 'Time',
2112        Avoid => 1,
2113        # handle values in the form "2010-02-12T13:27:14-0800"
2114        ValueConv => q{
2115            require Image::ExifTool::XMP;
2116            $val =  Image::ExifTool::XMP::ConvertXMPDate($val);
2117            $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary
2118            return $val;
2119        },
2120        ValueConvInv => q{
2121            require Image::ExifTool::XMP;
2122            my $tmp = Image::ExifTool::XMP::FormatXMPDate($val);
2123            ($val = $tmp) =~ s/([-+]\d{2}):(\d{2})$/$1$2/ if defined $tmp; # remove time zone colon
2124            return $val;
2125        },
2126        PrintConv => '$self->ConvertDateTime($val)',
2127        PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist)
2128    },
2129    '@xyz' => { #PH (iPhone 3GS)
2130        Name => 'GPSCoordinates',
2131        Groups => { 2 => 'Location' },
2132        Avoid => 1,
2133        ValueConv => \&ConvertISO6709,
2134        ValueConvInv => \&ConvInvISO6709,
2135        PrintConv => \&PrintGPSCoordinates,
2136        PrintConvInv => \&PrintInvGPSCoordinates,
2137    },
2138    # RDT1 - pairs of int32u_BE, starting at byte 8: "458275 471846"
2139    # RDT2 - pairs of int32u_BE, starting at byte 8: "472276 468526"
2140    # RDT3 - pairs of int32u_BE, starting at byte 8: "876603 482191"
2141    # RDT4 - pairs of int32u_BE, starting at byte 8: "1955 484612"
2142    # RDT6 - empty
2143    # RDT7 - empty
2144    # RDT8 - empty
2145    # RDT9 - only 16-byte header?
2146    # the boxes below all have a similar header (little-endian):
2147    #  0 int32u - number of records
2148    #  4 ? - "1e 00"
2149    #  6 int16u - record length in bytes
2150    #  8 ? - "23 01 00 00 00 00 00 00"
2151    #  16 - start of records (each record ends in an int64u timestamp in ns)
2152    # RDTA - float[4],ts: "-0.31289672 -0.2245330 11.303817 0 775.780"
2153    # RDTB - float[4],ts: "-0.04841613 -0.2166595 0.0724792 0 775.780"
2154    # RDTC - float[4],ts: "27.60925 -27.10037 -13.27285 0 775.829"
2155    # RDTD - int16s[3],ts: "353 -914 16354 0 775.829"
2156    # RDTG - ts: "775.825"
2157    # RDTI - float[4],ts: "0.00165951 0.005770059 0.06838259 0.1744695 775.862"
2158    # ---- Samsung ----
2159    vndr => 'Vendor', #PH (Samsung PL70)
2160    SDLN => 'PlayMode', #PH (NC, Samsung ST80 "SEQ_PLAY")
2161    INFO => {
2162        Name => 'SamsungINFO',
2163        SubDirectory => { TagTable => 'Image::ExifTool::Samsung::INFO' },
2164    },
2165   '@sec' => { #PH (Samsung WB30F)
2166        Name => 'SamsungSec',
2167        SubDirectory => { TagTable => 'Image::ExifTool::Samsung::sec' },
2168    },
2169    'smta' => { #PH (Samsung SM-C101)
2170        Name => 'SamsungSmta',
2171        SubDirectory => {
2172            TagTable => 'Image::ExifTool::Samsung::smta',
2173            Start => 4,
2174        },
2175    },
2176    cver => 'CodeVersion', #PH (guess, Samsung MV900F)
2177    # ducp - 4 bytes all zero (Samsung ST96,WB750), 52 bytes all zero (Samsung WB30F)
2178    # edli - 52 bytes all zero (Samsung WB30F)
2179    # @etc - 4 bytes all zero (Samsung WB30F)
2180    # saut - 4 bytes all zero (Samsung SM-N900T)
2181    # smrd - string "TRUEBLUE" (Samsung SM-C101)
2182    # ---- TomTom Bandit Action Cam ----
2183    TTMD => {
2184        Name => 'TomTomMetaData',
2185        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TomTom' },
2186    },
2187    # ---- Samsung Gear 360 ----
2188    vrot => {
2189        Name => 'AccelerometerData',
2190        Notes => q{
2191            accelerometer readings for each frame of the video, expressed as sets of
2192            yaw, pitch and roll angles in degrees
2193        },
2194        Format => 'rational64s',
2195        ValueConv => '$val =~ s/^-?\d+ //; \$val', # (ignore leading version/size words)
2196    },
2197    # m360 - 8 bytes "0 0 0 0 0 0 0 1"
2198    # opax - 164 bytes unknown (center and affine arrays? ref 26)
2199    # opai - 32 bytes (maybe contains a serial number starting at byte 16? - PH) (rgb gains, degamma, gamma? ref 26)
2200    # intv - 16 bytes all zero
2201    # ---- Unknown ----
2202    # CDET - 128 bytes (unknown origin)
2203    # mtyp - 4 bytes all zero (some drone video)
2204    # kgrf - 8 bytes all zero ? (in udta inside trak atom)
2205    # kgcg - 128 bytes 0's and 1's
2206    # kgsi - 4 bytes "00 00 00 80"
2207    # FIEL - 18 bytes "FIEL\0\x01\0\0\0..."
2208#
2209# other 3rd-party tags
2210# (ref http://code.google.com/p/mp4parser/source/browse/trunk/isoparser/src/main/resources/isoparser-default.properties?r=814)
2211#
2212    ccid => 'ContentID',
2213    icnu => 'IconURI',
2214    infu => 'InfoURL',
2215    cdis => 'ContentDistributorID',
2216    albr => { Name => 'AlbumArtist', Groups => { 2 => 'Author' } },
2217    cvru => 'CoverURI',
2218    lrcu => 'LyricsURI',
2219
2220    tags => {   # found in Audible .m4b audio books (ref PH)
2221        Name => 'Audible_tags',
2222        SubDirectory => { TagTable => 'Image::ExifTool::Audible::tags' },
2223    },
2224);
2225
2226# Unknown information stored in HTC One (M8) videos - PH
2227%Image::ExifTool::QuickTime::HTCBinary = (
2228    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
2229    GROUPS => { 0 => 'MakerNotes', 1 => 'HTC', 2 => 'Video' },
2230    TAG_PREFIX => 'HTCBinary',
2231    FORMAT => 'int32u',
2232    FIRST_ENTRY => 0,
2233    # 0 - values: 1
2234    # 1 - values: 0
2235    # 2 - values: 0
2236    # 3 - values: FileSize minus 12 (why?)
2237    # 4 - values: 12
2238);
2239
2240# TomTom Bandit Action Cam metadata (ref PH)
2241%Image::ExifTool::QuickTime::TomTom = (
2242    PROCESS_PROC => \&ProcessMOV,
2243    GROUPS => { 2 => 'Video' },
2244    NOTES => 'Tags found in TomTom Bandit Action Cam MP4 videos.',
2245    TTAD => {
2246        Name => 'TomTomAD',
2247        SubDirectory => {
2248            TagTable => 'Image::ExifTool::QuickTime::Stream',
2249            ProcessProc => \&Image::ExifTool::QuickTime::ProcessTTAD,
2250        },
2251    },
2252    TTHL => { Name => 'TomTomHL', Binary => 1, Unknown => 1 }, # (mostly zeros)
2253    # (TTID values are different for each video)
2254    TTID => { Name => 'TomTomID', ValueConv => 'unpack("x4H*",$val)' },
2255    TTVI => { Name => 'TomTomVI', Format => 'int32u', Unknown => 1 }, # seen: "0 1 61 508 508"
2256    # TTVD seen: "normal 720p 60fps 60fps 16/9 wide 1x"
2257    TTVD => { Name => 'TomTomVD', ValueConv => 'my @a = ($val =~ /[\x20-\x7f]+/g); "@a"' },
2258);
2259
2260# User-specific media data atoms (ref 11)
2261%Image::ExifTool::QuickTime::UserMedia = (
2262    PROCESS_PROC => \&ProcessMOV,
2263    GROUPS => { 2 => 'Video' },
2264    MTDT => {
2265        Name => 'MetaData',
2266        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MetaData' },
2267    },
2268);
2269
2270# User-specific media data atoms (ref 11)
2271%Image::ExifTool::QuickTime::MetaData = (
2272    PROCESS_PROC => \&ProcessMetaData,
2273    GROUPS => { 2 => 'Video' },
2274    TAG_PREFIX => 'MetaData',
2275    0x01 => 'Title',
2276    0x03 => {
2277        Name => 'ProductionDate',
2278        Groups => { 2 => 'Time' },
2279        Shift => 'Time',
2280        Writable => 1,
2281        Permanent => 1,
2282        DelValue => '0000/00/00 00:00:00',
2283        # translate from format "YYYY/mm/dd HH:MM:SS"
2284        ValueConv => '$val=~tr{/}{:}; $val',
2285        ValueConvInv => '$val=~s[^(\d{4}):(\d{2}):][$1/$2/]; $val',
2286        PrintConv => '$self->ConvertDateTime($val)',
2287        PrintConvInv => '$self->InverseDateTime($val)',
2288    },
2289    0x04 => 'Software',
2290    0x05 => 'Product',
2291    0x0a => {
2292        Name => 'TrackProperty',
2293        RawConv => 'my @a=unpack("Nnn",$val); "@a"',
2294        PrintConv => [
2295            { 0 => 'No presentation', BITMASK => { 0 => 'Main track' } },
2296            { 0 => 'No attributes',   BITMASK => { 15 => 'Read only' } },
2297            '"Priority $val"',
2298        ],
2299    },
2300    0x0b => {
2301        Name => 'TimeZone',
2302        Groups => { 2 => 'Time' },
2303        Writable => 1,
2304        Permanent => 1,
2305        DelValue => 0,
2306        RawConv => 'Get16s(\$val,0)',
2307        RawConvInv => 'Set16s($val)',
2308        PrintConv => 'TimeZoneString($val)',
2309        PrintConvInv => q{
2310            return undef unless $val =~ /^([-+])(\d{1,2}):?(\d{2})$/'
2311            my $tzmin = $2 * 60 + $3;
2312            $tzmin = -$tzmin if $1 eq '-';
2313            return $tzmin;
2314        }
2315    },
2316    0x0c => {
2317        Name => 'ModifyDate',
2318        Groups => { 2 => 'Time' },
2319        Shift => 'Time',
2320        Writable => 1,
2321        Permanent => 1,
2322        DelValue => '0000/00/00 00:00:00',
2323        # translate from format "YYYY/mm/dd HH:MM:SS"
2324        ValueConv => '$val=~tr{/}{:}; $val',
2325        ValueConvInv => '$val=~s[^(\d{4}):(\d{2}):][$1/$2/]; $val',
2326        PrintConv => '$self->ConvertDateTime($val)',
2327        PrintConvInv => '$self->InverseDateTime($val)',
2328    },
2329);
2330
2331# compressed movie atoms (ref http://wiki.multimedia.cx/index.php?title=QuickTime_container#cmov)
2332%Image::ExifTool::QuickTime::CMovie = (
2333    PROCESS_PROC => \&ProcessMOV,
2334    GROUPS => { 2 => 'Video' },
2335    dcom => 'Compression',
2336    # cmvd - compressed moov atom data
2337);
2338
2339# Profile atoms (ref 11)
2340%Image::ExifTool::QuickTime::Profile = (
2341    PROCESS_PROC => \&ProcessMOV,
2342    GROUPS => { 2 => 'Video' },
2343    FPRF => {
2344        Name => 'FileGlobalProfile',
2345        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::FileProf' },
2346    },
2347    APRF => {
2348        Name => 'AudioProfile',
2349        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::AudioProf' },
2350    },
2351    VPRF => {
2352        Name => 'VideoProfile',
2353        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::VideoProf' },
2354    },
2355    OLYM => { #PH
2356        Name => 'OlympusOLYM',
2357        SubDirectory => {
2358            TagTable => 'Image::ExifTool::Olympus::OLYM',
2359            ByteOrder => 'BigEndian',
2360        },
2361    },
2362);
2363
2364# FPRF atom information (ref 11)
2365%Image::ExifTool::QuickTime::FileProf = (
2366    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
2367    GROUPS => { 2 => 'Video' },
2368    FORMAT => 'int32u',
2369    0 => { Name => 'FileProfileVersion', Unknown => 1 }, # unknown = uninteresting
2370    1 => {
2371        Name => 'FileFunctionFlags',
2372        PrintConv => { BITMASK => {
2373            28 => 'Fragmented',
2374            29 => 'Additional tracks',
2375            30 => 'Edited', # (main AV track is edited)
2376        }},
2377    },
2378    # 2 - reserved
2379);
2380
2381# APRF atom information (ref 11)
2382%Image::ExifTool::QuickTime::AudioProf = (
2383    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
2384    GROUPS => { 2 => 'Audio' },
2385    FORMAT => 'int32u',
2386    0 => { Name => 'AudioProfileVersion', Unknown => 1 },
2387    1 => 'AudioTrackID',
2388    2 => {
2389        Name => 'AudioCodec',
2390        Format => 'undef[4]',
2391    },
2392    3 => {
2393        Name => 'AudioCodecInfo',
2394        Unknown => 1,
2395        PrintConv => 'sprintf("0x%.4x", $val)',
2396    },
2397    4 => {
2398        Name => 'AudioAttributes',
2399        PrintConv => { BITMASK => {
2400            0 => 'Encrypted',
2401            1 => 'Variable bitrate',
2402            2 => 'Dual mono',
2403        }},
2404    },
2405    5 => {
2406        Name => 'AudioAvgBitrate',
2407        ValueConv => '$val * 1000',
2408        PrintConv => 'ConvertBitrate($val)',
2409    },
2410    6 => {
2411        Name => 'AudioMaxBitrate',
2412        ValueConv => '$val * 1000',
2413        PrintConv => 'ConvertBitrate($val)',
2414    },
2415    7 => 'AudioSampleRate',
2416    8 => 'AudioChannels',
2417);
2418
2419# VPRF atom information (ref 11)
2420%Image::ExifTool::QuickTime::VideoProf = (
2421    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
2422    GROUPS => { 2 => 'Video' },
2423    FORMAT => 'int32u',
2424    0 => { Name => 'VideoProfileVersion', Unknown => 1 },
2425    1 => 'VideoTrackID',
2426    2 => {
2427        Name => 'VideoCodec',
2428        Format => 'undef[4]',
2429    },
2430    3 => {
2431        Name => 'VideoCodecInfo',
2432        Unknown => 1,
2433        PrintConv => 'sprintf("0x%.4x", $val)',
2434    },
2435    4 => {
2436        Name => 'VideoAttributes',
2437        PrintConv => { BITMASK => {
2438            0 => 'Encrypted',
2439            1 => 'Variable bitrate',
2440            2 => 'Variable frame rate',
2441            3 => 'Interlaced',
2442        }},
2443    },
2444    5 => {
2445        Name => 'VideoAvgBitrate',
2446        ValueConv => '$val * 1000',
2447        PrintConv => 'ConvertBitrate($val)',
2448    },
2449    6 => {
2450        Name => 'VideoMaxBitrate',
2451        ValueConv => '$val * 1000',
2452        PrintConv => 'ConvertBitrate($val)',
2453    },
2454    7 => {
2455        Name => 'VideoAvgFrameRate',
2456        Format => 'fixed32u',
2457        PrintConv => 'int($val * 1000 + 0.5) / 1000',
2458    },
2459    8 => {
2460        Name => 'VideoMaxFrameRate',
2461        Format => 'fixed32u',
2462        PrintConv => 'int($val * 1000 + 0.5) / 1000',
2463    },
2464    9 => {
2465        Name => 'VideoSize',
2466        Format => 'int16u[2]',
2467        PrintConv => '$val=~tr/ /x/; $val',
2468    },
2469    10 => {
2470        Name => 'PixelAspectRatio',
2471        Format => 'int16u[2]',
2472        PrintConv => '$val=~tr/ /:/; $val',
2473    },
2474);
2475
2476# meta atoms
2477%Image::ExifTool::QuickTime::Meta = (
2478    PROCESS_PROC => \&ProcessMOV,
2479    WRITE_PROC => \&WriteQuickTime,
2480    GROUPS => { 1 => 'Meta', 2 => 'Video' },
2481    ilst => {
2482        Name => 'ItemList',
2483        SubDirectory => {
2484            TagTable => 'Image::ExifTool::QuickTime::ItemList',
2485            HasData => 1, # process atoms as containers with 'data' elements
2486        },
2487    },
2488    # MP4 tags (ref 5)
2489    hdlr => {
2490        Name => 'Handler',
2491        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Handler' },
2492    },
2493    dinf => {
2494        Name => 'DataInfo', # (don't change this name -- used to recognize directory when writing)
2495        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::DataInfo' },
2496    },
2497    ipmc => {
2498        Name => 'IPMPControl',
2499        Flags => ['Binary','Unknown'],
2500    },
2501    iloc => {
2502        Name => 'ItemLocation',
2503        RawConv => \&ParseItemLocation,
2504        WriteHook => \&ParseItemLocation,
2505        Notes => 'parsed, but not extracted as a tag',
2506    },
2507    ipro => {
2508        Name => 'ItemProtection',
2509        Flags => ['Binary','Unknown'],
2510    },
2511    iinf => [{
2512        Name => 'ItemInformation',
2513        Condition => '$$valPt =~ /^\0/', # (check for version 0)
2514        SubDirectory => {
2515            TagTable => 'Image::ExifTool::QuickTime::ItemInfo',
2516            Start => 6, # (4-byte version/flags + 2-byte count)
2517        },
2518    },{
2519        Name => 'ItemInformation',
2520        SubDirectory => {
2521            TagTable => 'Image::ExifTool::QuickTime::ItemInfo',
2522            Start => 8, # (4-byte version/flags + 4-byte count)
2523        },
2524    }],
2525   'xml ' => {
2526        Name => 'XML',
2527        Flags => [ 'Binary', 'Protected' ],
2528        SubDirectory => {
2529            TagTable => 'Image::ExifTool::XMP::XML',
2530            IgnoreProp => { NonRealTimeMeta => 1 }, # ignore container for Sony 'nrtm'
2531        },
2532    },
2533   'keys' => {
2534        Name => 'Keys',
2535        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Keys' },
2536    },
2537    bxml => {
2538        Name => 'BinaryXML',
2539        Flags => ['Binary','Unknown'],
2540    },
2541    pitm => [{
2542        Name => 'PrimaryItemReference',
2543        Condition => '$$valPt =~ /^\0/', # (version 0?)
2544        RawConv => '$$self{PrimaryItem} = unpack("x4n",$val)',
2545        WriteHook => sub { my ($val,$et) = @_; $$et{PrimaryItem} = unpack("x4n",$val); },
2546    },{
2547        Name => 'PrimaryItemReference',
2548        RawConv => '$$self{PrimaryItem} = unpack("x4N",$val)',
2549        WriteHook => sub { my ($val,$et) = @_; $$et{PrimaryItem} = unpack("x4N",$val); },
2550    }],
2551    free => { #PH
2552        Name => 'Free',
2553        Flags => ['Binary','Unknown'],
2554    },
2555    iprp => {
2556        Name => 'ItemProperties',
2557        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ItemProp' },
2558    },
2559    iref => {
2560        Name => 'ItemReference',
2561        # the version is needed to parse some of the item references
2562        Condition => '$$self{ItemRefVersion} = ord($$valPt); 1',
2563        SubDirectory => {
2564            TagTable => 'Image::ExifTool::QuickTime::ItemRef',
2565            Start => 4,
2566        },
2567    },
2568    idat => {
2569        Name => 'MetaImageSize', #PH (NC)
2570        Format => 'int16u',
2571        # (don't know what the first two numbers are for)
2572        PrintConv => '$val =~ s/^(\d+) (\d+) (\d+) (\d+)/${3}x$4/; $val',
2573    },
2574    uuid => [
2575        { #PH (Canon R5/R6 HIF)
2576            Name => 'MetaVersion', # (NC)
2577            Condition => '$$valPt=~/^\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48/',
2578            RawConv => 'substr($val, 0x14)',
2579        },
2580        {
2581            Name => 'UUID-Unknown',
2582            %unknownInfo,
2583        },
2584    ],
2585);
2586
2587# additional metadata container (ref ISO14496-12:2015)
2588%Image::ExifTool::QuickTime::OtherMeta = (
2589    PROCESS_PROC => \&ProcessMOV,
2590    WRITE_PROC => \&WriteQuickTime,
2591    GROUPS => { 2 => 'Video' },
2592    mere => {
2593        Name => 'MetaRelation',
2594        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MetaRelation' },
2595    },
2596    meta => {
2597        Name => 'Meta',
2598        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' },
2599    },
2600);
2601
2602# metabox relation (ref ISO14496-12:2015)
2603%Image::ExifTool::QuickTime::MetaRelation = (
2604    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
2605    GROUPS => { 2 => 'Video' },
2606    FORMAT => 'int32u',
2607    # 0 => 'MetaRelationVersion',
2608    # 1 => 'FirstMetaboxHandlerType',
2609    # 2 => 'FirstMetaboxHandlerType',
2610    # 3 => { Name => 'MetaboxRelation', Format => 'int8u' },
2611);
2612
2613%Image::ExifTool::QuickTime::ItemProp = (
2614    PROCESS_PROC => \&ProcessMOV,
2615    WRITE_PROC => \&WriteQuickTime,
2616    GROUPS => { 2 => 'Image' },
2617    ipco => {
2618        Name => 'ItemPropertyContainer',
2619        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ItemPropCont' },
2620    },
2621    ipma => {
2622        Name => 'ItemPropertyAssociation',
2623        RawConv => \&ParseItemPropAssoc,
2624        WriteHook => \&ParseItemPropAssoc,
2625        Notes => 'parsed, but not extracted as a tag',
2626    },
2627);
2628
2629%Image::ExifTool::QuickTime::ItemPropCont = (
2630    PROCESS_PROC => \&ProcessMOV,
2631    WRITE_PROC => \&WriteQuickTime,
2632    PERMANENT => 1, # (can't be deleted)
2633    GROUPS => { 2 => 'Image' },
2634    VARS => { START_INDEX => 1 },   # show verbose indices starting at 1
2635    colr => [{
2636        Name => 'ICC_Profile',
2637        Condition => '$$valPt =~ /^(prof|rICC)/',
2638        SubDirectory => {
2639            TagTable => 'Image::ExifTool::ICC_Profile::Main',
2640            Start => 4,
2641        },
2642    },{
2643        Name => 'ColorRepresentation',
2644        ValueConv => 'join(" ", substr($val,0,4), unpack("x4n*",$val))',
2645    }],
2646    irot => {
2647        Name => 'Rotation',
2648        Format => 'int8u',
2649        Writable => 'int8u',
2650        Protected => 1,
2651        ValueConv => '$val * 90',
2652        ValueConvInv => 'int($val / 90 + 0.5)',
2653    },
2654    ispe => {
2655        Name => 'ImageSpatialExtent',
2656        Condition => '$$valPt =~ /^\0{4}/',     # (version/flags == 0/0)
2657        RawConv => q{
2658            my @dim = unpack("x4N*", $val);
2659            return undef if @dim < 2;
2660            unless ($$self{DOC_NUM}) {
2661                $self->FoundTag(ImageWidth => $dim[0]);
2662                $self->FoundTag(ImageHeight => $dim[1]);
2663            }
2664            return join ' ', @dim;
2665        },
2666        PrintConv => '$val =~ tr/ /x/; $val',
2667    },
2668    pixi => {
2669        Name => 'ImagePixelDepth',
2670        Condition => '$$valPt =~ /^\0{4}./s',   # (version/flags == 0/0 and count)
2671        RawConv => 'join " ", unpack("x5C*", $val)',
2672    },
2673    auxC => {
2674        Name => 'AuxiliaryImageType',
2675        Format => 'undef',
2676        RawConv => '$val = substr($val, 4); $val =~ s/\0.*//s; $val',
2677    },
2678    pasp => {
2679        Name => 'PixelAspectRatio',
2680        Format => 'int32u',
2681        Writable => 'int32u',
2682        Protected => 1,
2683    },
2684    rloc => {
2685        Name => 'RelativeLocation',
2686        Format => 'int32u',
2687        RawConv => '$val =~ s/^\S+\s+//; $val', # remove version/flags
2688    },
2689    clap => {
2690        Name => 'CleanAperture',
2691        Format => 'rational64s',
2692        Notes => '4 numbers: width, height, left and top',
2693    },
2694    hvcC => {
2695        Name => 'HEVCConfiguration',
2696        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HEVCConfig' },
2697    },
2698    av1C => {
2699        Name => 'AV1Configuration',
2700        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::AV1Config' },
2701    },
2702);
2703
2704# HEVC configuration (ref https://github.com/MPEGGroup/isobmff/blob/master/IsoLib/libisomediafile/src/HEVCConfigAtom.c)
2705%Image::ExifTool::QuickTime::HEVCConfig = (
2706    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
2707    GROUPS => { 2 => 'Video' },
2708    FIRST_ENTRY => 0,
2709    0 => 'HEVCConfigurationVersion',
2710    1 => {
2711        Name => 'GeneralProfileSpace',
2712        Mask => 0xc0,
2713        PrintConv => { 0 => 'Conforming' },
2714    },
2715    1.1 => {
2716        Name => 'GeneralTierFlag',
2717        Mask => 0x20,
2718        PrintConv => {
2719            0 => 'Main Tier',
2720            1 => 'High Tier',
2721        },
2722    },
2723    1.2 => {
2724        Name => 'GeneralProfileIDC',
2725        Mask => 0x1f,
2726        PrintConv => {
2727            0 => 'No Profile',
2728            1 => 'Main',
2729            2 => 'Main 10',
2730            3 => 'Main Still Picture',
2731            4 => 'Format Range Extensions',
2732            5 => 'High Throughput',
2733            6 => 'Multiview Main',
2734            7 => 'Scalable Main',
2735            8 => '3D Main',
2736            9 => 'Screen Content Coding Extensions',
2737            10 => 'Scalable Format Range Extensions',
2738            11 => 'High Throughput Screen Content Coding Extensions',
2739        },
2740    },
2741    2 => {
2742        Name => 'GenProfileCompatibilityFlags',
2743        Format => 'int32u',
2744        PrintConv => { BITMASK => {
2745            31 => 'No Profile',             # (bit 0 in stream)
2746            30 => 'Main',                   # (bit 1 in stream)
2747            29 => 'Main 10',                # (bit 2 in stream)
2748            28 => 'Main Still Picture',     # (bit 3 in stream)
2749            27 => 'Format Range Extensions',# (...)
2750            26 => 'High Throughput',
2751            25 => 'Multiview Main',
2752            24 => 'Scalable Main',
2753            23 => '3D Main',
2754            22 => 'Screen Content Coding Extensions',
2755            21 => 'Scalable Format Range Extensions',
2756            20 => 'High Throughput Screen Content Coding Extensions',
2757        }},
2758    },
2759    6 => {
2760        Name => 'ConstraintIndicatorFlags',
2761        Format => 'int8u[6]',
2762    },
2763    12 => {
2764        Name => 'GeneralLevelIDC',
2765        PrintConv => 'sprintf("%d (level %.1f)", $val, $val/30)',
2766    },
2767    13 => {
2768        Name => 'MinSpatialSegmentationIDC',
2769        Format => 'int16u',
2770        Mask => 0x0fff,
2771    },
2772    15 => {
2773        Name => 'ParallelismType',
2774        Mask => 0x03,
2775    },
2776    16 => {
2777        Name => 'ChromaFormat',
2778        Mask => 0x03,
2779        PrintConv => {
2780            0 => 'Monochrome',
2781            1 => '4:2:0',
2782            2 => '4:2:2',
2783            3 => '4:4:4',
2784        },
2785    },
2786    17 => {
2787        Name => 'BitDepthLuma',
2788        Mask => 0x07,
2789        ValueConv => '$val + 8',
2790    },
2791    18 => {
2792        Name => 'BitDepthChroma',
2793        Mask => 0x07,
2794        ValueConv => '$val + 8',
2795    },
2796    19 => {
2797        Name => 'AverageFrameRate',
2798        Format => 'int16u',
2799        ValueConv => '$val / 256',
2800    },
2801    21 => {
2802        Name => 'ConstantFrameRate',
2803        Mask => 0xc0,
2804        PrintConv => {
2805            0 => 'Unknown',
2806            1 => 'Constant Frame Rate',
2807            2 => 'Each Temporal Layer is Constant Frame Rate',
2808        },
2809    },
2810    21.1 => {
2811        Name => 'NumTemporalLayers',
2812        Mask => 0x38,
2813    },
2814    21.2 => {
2815        Name => 'TemporalIDNested',
2816        Mask => 0x04,
2817        PrintConv => { 0 => 'No', 1 => 'Yes' },
2818    },
2819    #21.3 => {
2820    #    Name => 'NALUnitLengthSize',
2821    #    Mask => 0x03,
2822    #    ValueConv => '$val + 1',
2823    #    PrintConv => { 1 => '8-bit', 2 => '16-bit', 4 => '32-bit' },
2824    #},
2825    #22 => 'NumberOfNALUnitArrays',
2826    # (don't decode the NAL unit arrays)
2827);
2828
2829# HEVC configuration (ref https://aomediacodec.github.io/av1-isobmff/#av1codecconfigurationbox)
2830%Image::ExifTool::QuickTime::AV1Config = (
2831    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
2832    GROUPS => { 2 => 'Video' },
2833    FIRST_ENTRY => 0,
2834    0 => {
2835        Name => 'AV1ConfigurationVersion',
2836        Mask => 0x7f,
2837    },
2838    1.0 => {
2839        Name => 'SeqProfile',
2840        Mask => 0xe0,
2841        Unknown => 1,
2842    },
2843    1.1 => {
2844        Name => 'SeqLevelIdx0',
2845        Mask => 0x1f,
2846        Unknown => 1,
2847    },
2848    2.0 => {
2849        Name => 'SeqTier0',
2850        Mask => 0x80,
2851        Unknown => 1,
2852    },
2853    2.1 => {
2854        Name => 'HighBitDepth',
2855        Mask => 0x40,
2856        Unknown => 1,
2857    },
2858    2.2 => {
2859        Name => 'TwelveBit',
2860        Mask => 0x20,
2861        Unknown => 1,
2862    },
2863    2.3 => {
2864        Name => 'ChromaFormat', # (Monochrome+SubSamplingX+SubSamplingY)
2865        Notes => 'bits: 0x04 = Monochrome, 0x02 = SubSamplingX, 0x01 = SubSamplingY',
2866        Mask => 0x1c,
2867        PrintConv => {
2868            0x00 => 'YUV 4:4:4',
2869            0x02 => 'YUV 4:2:2',
2870            0x03 => 'YUV 4:2:0',
2871            0x07 => 'Monochrome 4:0:0',
2872        },
2873    },
2874    2.4 => {
2875        Name => 'ChromaSamplePosition',
2876        Mask => 0x03,
2877        PrintConv => {
2878            0 => 'Unknown',
2879            1 => 'Vertical',
2880            2 => 'Colocated',
2881            3 => '(reserved)',
2882        },
2883    },
2884    3 => {
2885        Name => 'InitialDelaySamples',
2886        RawConv => '$val & 0x10 ? undef : ($val & 0x0f) + 1',
2887        Unknown => 1,
2888    },
2889);
2890
2891%Image::ExifTool::QuickTime::ItemRef = (
2892    PROCESS_PROC => \&ProcessMOV,
2893    WRITE_PROC => \&WriteQuickTime,
2894    GROUPS => { 2 => 'Image' },
2895    # (Note: ExifTool's ItemRefVersion may be used to test the iref version number)
2896    NOTES => q{
2897        The Item reference entries listed in the table below contain information about
2898        the associations between items in the file.  This information is used by
2899        ExifTool, but these entries are not extracted as tags.
2900    },
2901    dimg => { Name => 'DerivedImageRef',   RawConv => 'undef' },
2902    thmb => { Name => 'ThumbnailRef',      RawConv => 'undef' },
2903    auxl => { Name => 'AuxiliaryImageRef', RawConv => 'undef' },
2904    cdsc => {
2905        Name => 'ContentDescribes',
2906        RawConv => \&ParseContentDescribes,
2907        WriteHook => \&ParseContentDescribes,
2908    },
2909);
2910
2911%Image::ExifTool::QuickTime::ItemInfo = (
2912    PROCESS_PROC => \&ProcessMOV,
2913    WRITE_PROC => \&WriteQuickTime,
2914    GROUPS => { 2 => 'Image' },
2915    # avc1 - AVC image
2916    # hvc1 - HEVC image
2917    # lhv1 - L-HEVC image
2918    # infe - ItemInformationEntry
2919    # infe types: avc1,hvc1,lhv1,Exif,xml1,iovl(overlay image),grid,mime,hvt1(tile image)
2920    infe => {
2921        Name => 'ItemInfoEntry',
2922        RawConv => \&ParseItemInfoEntry,
2923        WriteHook => \&ParseItemInfoEntry,
2924        Notes => 'parsed, but not extracted as a tag',
2925    },
2926);
2927
2928# track reference atoms
2929%Image::ExifTool::QuickTime::TrackRef = (
2930    PROCESS_PROC => \&ProcessMOV,
2931    GROUPS => { 1 => 'Track#', 2 => 'Video' },
2932    chap => { Name => 'ChapterListTrackID', Format => 'int32u' },
2933    tmcd => { Name => 'TimeCode', Format => 'int32u' },
2934    mpod => { #PH (FLIR MP4)
2935        Name => 'ElementaryStreamTrack',
2936        Format => 'int32u',
2937        ValueConv => '$val =~ s/^1 //; $val',  # (why 2 numbers? -- ignore the first if "1")
2938    },
2939    # also: sync, scpt, ssrc, iTunesInfo
2940    cdsc => {
2941        Name => 'ContentDescribes',
2942        Format => 'int32u',
2943        PrintConv => '"Track $val"',
2944    },
2945    # cdep (Structural Dependency QT tag?)
2946);
2947
2948# track aperture mode dimensions atoms
2949# (ref https://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap2/qtff2.html)
2950%Image::ExifTool::QuickTime::TrackAperture = (
2951    PROCESS_PROC => \&ProcessMOV,
2952    GROUPS => { 1 => 'Track#', 2 => 'Video' },
2953    clef => {
2954        Name => 'CleanApertureDimensions',
2955        Format => 'fixed32u',
2956        Count => 3,
2957        ValueConv => '$val =~ s/^.*? //; $val', # remove flags word
2958        PrintConv => '$val =~ tr/ /x/; $val',
2959    },
2960    prof => {
2961        Name => 'ProductionApertureDimensions',
2962        Format => 'fixed32u',
2963        Count => 3,
2964        ValueConv => '$val =~ s/^.*? //; $val',
2965        PrintConv => '$val =~ tr/ /x/; $val',
2966    },
2967    enof => {
2968        Name => 'EncodedPixelsDimensions',
2969        Format => 'fixed32u',
2970        Count => 3,
2971        ValueConv => '$val =~ s/^.*? //; $val',
2972        PrintConv => '$val =~ tr/ /x/; $val',
2973    },
2974);
2975
2976# item list atoms
2977# -> these atoms are unique, and contain one or more 'data' atoms
2978%Image::ExifTool::QuickTime::ItemList = (
2979    PROCESS_PROC => \&ProcessMOV,
2980    WRITE_PROC => \&WriteQuickTime,
2981    CHECK_PROC => \&CheckQTValue,
2982    WRITABLE => 1,
2983    PREFERRED => 2, # (preferred over UserData and Keys tags when writing)
2984    FORMAT => 'string',
2985    GROUPS => { 1 => 'ItemList', 2 => 'Audio' },
2986    WRITE_GROUP => 'ItemList',
2987    LANG_INFO => \&GetLangInfo,
2988    NOTES => q{
2989        This is the preferred location for creating new QuickTime tags.  Tags in
2990        this table support alternate languages which are accessed by adding a
2991        3-character ISO 639-2 language code and an optional ISO 3166-1 alpha 2
2992        country code to the tag name (eg. "ItemList:Title-fra" or
2993        "ItemList::Title-fra-FR").  When creating a new Meta box to contain the
2994        ItemList directory, by default ExifTool does not specify a
2995        L<Handler|Image::ExifTool::TagNames/QuickTime Handler Tags>, but the
2996        API L<QuickTimeHandler|../ExifTool.html#QuickTimeHandler> option may be used to include an 'mdir' Handler box.
2997    },
2998    # in this table, binary 1 and 2-byte "data"-type tags are interpreted as
2999    # int8u and int16u.  Multi-byte binary "data" tags are extracted as binary data.
3000    # (Note that the Preferred property is set to 0 for some tags to prevent them
3001    #  from being created when a same-named tag already exists in the table)
3002    "\xa9ART" => 'Artist',
3003    "\xa9alb" => 'Album',
3004    "\xa9aut" => { Name => 'Author', Avoid => 1, Groups => { 2 => 'Author' } }, #forum10091 ('auth' is preferred)
3005    "\xa9cmt" => 'Comment',
3006    "\xa9com" => { Name => 'Composer', Avoid => 1, }, # ("\xa9wrt" is preferred in ItemList)
3007    "\xa9day" => {
3008        Name => 'ContentCreateDate',
3009        Groups => { 2 => 'Time' },
3010        Shift => 'Time',
3011        # handle values in the form "2010-02-12T13:27:14-0800"
3012        ValueConv => q{
3013            require Image::ExifTool::XMP;
3014            $val =  Image::ExifTool::XMP::ConvertXMPDate($val);
3015            $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary
3016            return $val;
3017        },
3018        ValueConvInv => q{
3019            require Image::ExifTool::XMP;
3020            $val =  Image::ExifTool::XMP::FormatXMPDate($val);
3021            $val =~ s/([-+]\d{2}):(\d{2})$/$1$2/; # remove time zone colon
3022            return $val;
3023        },
3024        PrintConv => '$self->ConvertDateTime($val)',
3025        PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist)
3026    },
3027    "\xa9des" => 'Description', #4
3028    "\xa9enc" => 'EncodedBy', #10
3029    "\xa9gen" => 'Genre',
3030    "\xa9grp" => 'Grouping',
3031    "\xa9lyr" => 'Lyrics',
3032    "\xa9nam" => 'Title',
3033    "\xa9too" => 'Encoder',
3034    "\xa9trk" => 'Track',
3035    "\xa9wrt" => 'Composer',
3036#
3037# the following tags written by AtomicParsley 0.9.6
3038# (ref https://exiftool.org/forum/index.php?topic=11455.0)
3039#
3040    "\xa9st3" => 'Subtitle',
3041    "\xa9con" => 'Conductor',
3042    "\xa9sol" => 'Soloist',
3043    "\xa9arg" => 'Arranger',
3044    "\xa9ope" => 'OriginalArtist',
3045    "\xa9dir" => 'Director',
3046    "\xa9ard" => 'ArtDirector',
3047    "\xa9sne" => 'SoundEngineer',
3048    "\xa9prd" => 'Producer',
3049    "\xa9xpd" => 'ExecutiveProducer',
3050    sdes      => 'StoreDescription',
3051#
3052    '----' => {
3053        Name => 'iTunesInfo',
3054        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::iTunesInfo' },
3055    },
3056    aART => { Name => 'AlbumArtist', Groups => { 2 => 'Author' } },
3057    covr => { Name => 'CoverArt',    Groups => { 2 => 'Preview' } },
3058    cpil => { #10
3059        Name => 'Compilation',
3060        Format => 'int8u', #27 (ref 23 contradicts what AtomicParsley actually writes, which is int8s)
3061        Writable => 'int8s',
3062        PrintConv => { 0 => 'No', 1 => 'Yes' },
3063    },
3064    disk => {
3065        Name => 'DiskNumber',
3066        Format => 'undef',  # (necessary to prevent decoding as string!)
3067        ValueConv => q{
3068            return \$val unless length($val) >= 6;
3069            my @a = unpack 'x2nn', $val;
3070            return $a[1] ? join(' of ', @a) : $a[0];
3071        },
3072        ValueConvInv => q{
3073            my @a = $val =~ /\d+/g;
3074            return undef if @a == 0 or @a > 2;
3075            push @a, 0 if @a == 1;
3076            return pack('n3', 0, @a);
3077        },
3078    },
3079    pgap => { #10
3080        Name => 'PlayGap',
3081        Format => 'int8u', #23
3082        Writable => 'int8s', #27
3083        PrintConv => {
3084            0 => 'Insert Gap',
3085            1 => 'No Gap',
3086        },
3087    },
3088    tmpo => {
3089        Name => 'BeatsPerMinute',
3090        # marked as boolean but really int16u in my sample
3091        # (but written as int16s by iTunes and AtomicParsley, ref forum11506)
3092        Format => 'int16u',
3093        Writable => 'int16s',
3094    },
3095    trkn => {
3096        Name => 'TrackNumber',
3097        Format => 'undef',  # (necessary to prevent decoding as string!)
3098        ValueConv => q{
3099            return \$val unless length($val) >= 6;
3100            my @a = unpack 'x2nn', $val;
3101            return $a[1] ? join(' of ', @a) : $a[0];
3102        },
3103        # (see forum11501 for discussion about the format used)
3104        ValueConvInv => q{
3105            my @a = $val =~ /\d+/g;
3106            return undef if @a == 0 or @a > 2;
3107            push @a, 0 if @a == 1;
3108            return pack('n4', 0, @a, 0);
3109        },
3110    },
3111#
3112# Note: it is possible that the tags below are not being decoded properly
3113# because I don't have samples to verify many of these - PH
3114#
3115    akID => { #10
3116        Name => 'AppleStoreAccountType',
3117        Format => 'int8u', #24
3118        Writable => 'int8s', #27
3119        PrintConv => {
3120            0 => 'iTunes',
3121            1 => 'AOL',
3122        },
3123    },
3124    albm => { Name => 'Album', Avoid => 1 }, #(ffmpeg source)
3125    apID => 'AppleStoreAccount',
3126    atID => { #10 (or TV series)
3127        Name => 'AlbumTitleID',
3128        Format => 'int32u',
3129        Writable => 'int32s', #27
3130    },
3131    auth => { Name => 'Author', Groups => { 2 => 'Author' } },
3132    catg => 'Category', #7
3133    cnID => { #10
3134        Name => 'AppleStoreCatalogID',
3135        Format => 'int32u',
3136        Writable => 'int32s', #27
3137    },
3138    cprt => { Name => 'Copyright', Groups => { 2 => 'Author' } },
3139    dscp => { Name => 'Description', Avoid => 1 },
3140    desc => { Name => 'Description', Avoid => 1 }, #7
3141    gnre => { #10
3142        Name => 'Genre',
3143        Avoid => 1,
3144        # (Note: see https://exiftool.org/forum/index.php?topic=11537.0)
3145        Format => 'undef',
3146        ValueConv => 'unpack("n",$val)',
3147        ValueConvInv => '$val =~ /^\d+$/ ? pack("n",$val) : undef',
3148        PrintConv => q{
3149            return $val unless $val =~ /^\d+$/;
3150            require Image::ExifTool::ID3;
3151            Image::ExifTool::ID3::PrintGenre($val - 1); # note the "- 1"
3152        },
3153        PrintConvInv => q{
3154            return $val if $val =~ /^[0-9]+$/;
3155            require Image::ExifTool::ID3;
3156            my $id = Image::ExifTool::ID3::GetGenreID($val);
3157            return unless defined $id and $id =~ /^\d+$/;
3158            return $id + 1;
3159        },
3160    },
3161    egid => 'EpisodeGlobalUniqueID', #7
3162    geID => { #10
3163        Name => 'GenreID',
3164        Format => 'int32u',
3165        Writable => 'int32s', #27
3166        SeparateTable => 1,
3167        # the following lookup is based on http://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/genres
3168        # (see scripts/parse_genre to parse genre JSON file from above)
3169        PrintConv => { #21/PH
3170            2 => 'Music|Blues',
3171            3 => 'Music|Comedy',
3172            4 => "Music|Children's Music",
3173            5 => 'Music|Classical',
3174            6 => 'Music|Country',
3175            7 => 'Music|Electronic',
3176            8 => 'Music|Holiday',
3177            9 => 'Music|Classical|Opera',
3178            10 => 'Music|Singer/Songwriter',
3179            11 => 'Music|Jazz',
3180            12 => 'Music|Latino',
3181            13 => 'Music|New Age',
3182            14 => 'Music|Pop',
3183            15 => 'Music|R&B/Soul',
3184            16 => 'Music|Soundtrack',
3185            17 => 'Music|Dance',
3186            18 => 'Music|Hip-Hop/Rap',
3187            19 => 'Music|World',
3188            20 => 'Music|Alternative',
3189            21 => 'Music|Rock',
3190            22 => 'Music|Christian & Gospel',
3191            23 => 'Music|Vocal',
3192            24 => 'Music|Reggae',
3193            25 => 'Music|Easy Listening',
3194            26 => 'Podcasts',
3195            27 => 'Music|J-Pop',
3196            28 => 'Music|Enka',
3197            29 => 'Music|Anime',
3198            30 => 'Music|Kayokyoku',
3199            31 => 'Music Videos',
3200            32 => 'TV Shows',
3201            33 => 'Movies',
3202            34 => 'Music',
3203            35 => 'iPod Games',
3204            36 => 'App Store',
3205            37 => 'Tones',
3206            38 => 'Books',
3207            39 => 'Mac App Store',
3208            40 => 'Textbooks',
3209            50 => 'Music|Fitness & Workout',
3210            51 => 'Music|Pop|K-Pop',
3211            52 => 'Music|Karaoke',
3212            53 => 'Music|Instrumental',
3213            74 => 'Audiobooks|News',
3214            75 => 'Audiobooks|Programs & Performances',
3215            500 => 'Fitness Music',
3216            501 => 'Fitness Music|Pop',
3217            502 => 'Fitness Music|Dance',
3218            503 => 'Fitness Music|Hip-Hop',
3219            504 => 'Fitness Music|Rock',
3220            505 => 'Fitness Music|Alt/Indie',
3221            506 => 'Fitness Music|Latino',
3222            507 => 'Fitness Music|Country',
3223            508 => 'Fitness Music|World',
3224            509 => 'Fitness Music|New Age',
3225            510 => 'Fitness Music|Classical',
3226            1001 => 'Music|Alternative|College Rock',
3227            1002 => 'Music|Alternative|Goth Rock',
3228            1003 => 'Music|Alternative|Grunge',
3229            1004 => 'Music|Alternative|Indie Rock',
3230            1005 => 'Music|Alternative|New Wave',
3231            1006 => 'Music|Alternative|Punk',
3232            1007 => 'Music|Blues|Chicago Blues',
3233            1009 => 'Music|Blues|Classic Blues',
3234            1010 => 'Music|Blues|Contemporary Blues',
3235            1011 => 'Music|Blues|Country Blues',
3236            1012 => 'Music|Blues|Delta Blues',
3237            1013 => 'Music|Blues|Electric Blues',
3238            1014 => "Music|Children's Music|Lullabies",
3239            1015 => "Music|Children's Music|Sing-Along",
3240            1016 => "Music|Children's Music|Stories",
3241            1017 => 'Music|Classical|Avant-Garde',
3242            1018 => 'Music|Classical|Baroque Era',
3243            1019 => 'Music|Classical|Chamber Music',
3244            1020 => 'Music|Classical|Chant',
3245            1021 => 'Music|Classical|Choral',
3246            1022 => 'Music|Classical|Classical Crossover',
3247            1023 => 'Music|Classical|Early Music',
3248            1024 => 'Music|Classical|Impressionist',
3249            1025 => 'Music|Classical|Medieval Era',
3250            1026 => 'Music|Classical|Minimalism',
3251            1027 => 'Music|Classical|Modern Era',
3252            1028 => 'Music|Classical|Opera',
3253            1029 => 'Music|Classical|Orchestral',
3254            1030 => 'Music|Classical|Renaissance',
3255            1031 => 'Music|Classical|Romantic Era',
3256            1032 => 'Music|Classical|Wedding Music',
3257            1033 => 'Music|Country|Alternative Country',
3258            1034 => 'Music|Country|Americana',
3259            1035 => 'Music|Country|Bluegrass',
3260            1036 => 'Music|Country|Contemporary Bluegrass',
3261            1037 => 'Music|Country|Contemporary Country',
3262            1038 => 'Music|Country|Country Gospel',
3263            1039 => 'Music|Country|Honky Tonk',
3264            1040 => 'Music|Country|Outlaw Country',
3265            1041 => 'Music|Country|Traditional Bluegrass',
3266            1042 => 'Music|Country|Traditional Country',
3267            1043 => 'Music|Country|Urban Cowboy',
3268            1044 => 'Music|Dance|Breakbeat',
3269            1045 => 'Music|Dance|Exercise',
3270            1046 => 'Music|Dance|Garage',
3271            1047 => 'Music|Dance|Hardcore',
3272            1048 => 'Music|Dance|House',
3273            1049 => "Music|Dance|Jungle/Drum'n'bass",
3274            1050 => 'Music|Dance|Techno',
3275            1051 => 'Music|Dance|Trance',
3276            1052 => 'Music|Jazz|Big Band',
3277            1053 => 'Music|Jazz|Bop',
3278            1054 => 'Music|Easy Listening|Lounge',
3279            1055 => 'Music|Easy Listening|Swing',
3280            1056 => 'Music|Electronic|Ambient',
3281            1057 => 'Music|Electronic|Downtempo',
3282            1058 => 'Music|Electronic|Electronica',
3283            1060 => 'Music|Electronic|IDM/Experimental',
3284            1061 => 'Music|Electronic|Industrial',
3285            1062 => 'Music|Singer/Songwriter|Alternative Folk',
3286            1063 => 'Music|Singer/Songwriter|Contemporary Folk',
3287            1064 => 'Music|Singer/Songwriter|Contemporary Singer/Songwriter',
3288            1065 => 'Music|Singer/Songwriter|Folk-Rock',
3289            1066 => 'Music|Singer/Songwriter|New Acoustic',
3290            1067 => 'Music|Singer/Songwriter|Traditional Folk',
3291            1068 => 'Music|Hip-Hop/Rap|Alternative Rap',
3292            1069 => 'Music|Hip-Hop/Rap|Dirty South',
3293            1070 => 'Music|Hip-Hop/Rap|East Coast Rap',
3294            1071 => 'Music|Hip-Hop/Rap|Gangsta Rap',
3295            1072 => 'Music|Hip-Hop/Rap|Hardcore Rap',
3296            1073 => 'Music|Hip-Hop/Rap|Hip-Hop',
3297            1074 => 'Music|Hip-Hop/Rap|Latin Rap',
3298            1075 => 'Music|Hip-Hop/Rap|Old School Rap',
3299            1076 => 'Music|Hip-Hop/Rap|Rap',
3300            1077 => 'Music|Hip-Hop/Rap|Underground Rap',
3301            1078 => 'Music|Hip-Hop/Rap|West Coast Rap',
3302            1079 => 'Music|Holiday|Chanukah',
3303            1080 => 'Music|Holiday|Christmas',
3304            1081 => "Music|Holiday|Christmas: Children's",
3305            1082 => 'Music|Holiday|Christmas: Classic',
3306            1083 => 'Music|Holiday|Christmas: Classical',
3307            1084 => 'Music|Holiday|Christmas: Jazz',
3308            1085 => 'Music|Holiday|Christmas: Modern',
3309            1086 => 'Music|Holiday|Christmas: Pop',
3310            1087 => 'Music|Holiday|Christmas: R&B',
3311            1088 => 'Music|Holiday|Christmas: Religious',
3312            1089 => 'Music|Holiday|Christmas: Rock',
3313            1090 => 'Music|Holiday|Easter',
3314            1091 => 'Music|Holiday|Halloween',
3315            1092 => 'Music|Holiday|Holiday: Other',
3316            1093 => 'Music|Holiday|Thanksgiving',
3317            1094 => 'Music|Christian & Gospel|CCM',
3318            1095 => 'Music|Christian & Gospel|Christian Metal',
3319            1096 => 'Music|Christian & Gospel|Christian Pop',
3320            1097 => 'Music|Christian & Gospel|Christian Rap',
3321            1098 => 'Music|Christian & Gospel|Christian Rock',
3322            1099 => 'Music|Christian & Gospel|Classic Christian',
3323            1100 => 'Music|Christian & Gospel|Contemporary Gospel',
3324            1101 => 'Music|Christian & Gospel|Gospel',
3325            1103 => 'Music|Christian & Gospel|Praise & Worship',
3326            1104 => 'Music|Christian & Gospel|Southern Gospel',
3327            1105 => 'Music|Christian & Gospel|Traditional Gospel',
3328            1106 => 'Music|Jazz|Avant-Garde Jazz',
3329            1107 => 'Music|Jazz|Contemporary Jazz',
3330            1108 => 'Music|Jazz|Crossover Jazz',
3331            1109 => 'Music|Jazz|Dixieland',
3332            1110 => 'Music|Jazz|Fusion',
3333            1111 => 'Music|Jazz|Latin Jazz',
3334            1112 => 'Music|Jazz|Mainstream Jazz',
3335            1113 => 'Music|Jazz|Ragtime',
3336            1114 => 'Music|Jazz|Smooth Jazz',
3337            1115 => 'Music|Latino|Latin Jazz',
3338            1116 => 'Music|Latino|Contemporary Latin',
3339            1117 => 'Music|Latino|Pop Latino',
3340            1118 => 'Music|Latino|Raices', # (Ra&iacute;ces)
3341            1119 => 'Music|Latino|Urbano latino',
3342            1120 => 'Music|Latino|Baladas y Boleros',
3343            1121 => 'Music|Latino|Rock y Alternativo',
3344            1122 => 'Music|Brazilian',
3345            1123 => 'Music|Latino|Musica Mexicana', # (M&uacute;sica Mexicana)
3346            1124 => 'Music|Latino|Musica tropical', # (M&uacute;sica tropical)
3347            1125 => 'Music|New Age|Environmental',
3348            1126 => 'Music|New Age|Healing',
3349            1127 => 'Music|New Age|Meditation',
3350            1128 => 'Music|New Age|Nature',
3351            1129 => 'Music|New Age|Relaxation',
3352            1130 => 'Music|New Age|Travel',
3353            1131 => 'Music|Pop|Adult Contemporary',
3354            1132 => 'Music|Pop|Britpop',
3355            1133 => 'Music|Pop|Pop/Rock',
3356            1134 => 'Music|Pop|Soft Rock',
3357            1135 => 'Music|Pop|Teen Pop',
3358            1136 => 'Music|R&B/Soul|Contemporary R&B',
3359            1137 => 'Music|R&B/Soul|Disco',
3360            1138 => 'Music|R&B/Soul|Doo Wop',
3361            1139 => 'Music|R&B/Soul|Funk',
3362            1140 => 'Music|R&B/Soul|Motown',
3363            1141 => 'Music|R&B/Soul|Neo-Soul',
3364            1142 => 'Music|R&B/Soul|Quiet Storm',
3365            1143 => 'Music|R&B/Soul|Soul',
3366            1144 => 'Music|Rock|Adult Alternative',
3367            1145 => 'Music|Rock|American Trad Rock',
3368            1146 => 'Music|Rock|Arena Rock',
3369            1147 => 'Music|Rock|Blues-Rock',
3370            1148 => 'Music|Rock|British Invasion',
3371            1149 => 'Music|Rock|Death Metal/Black Metal',
3372            1150 => 'Music|Rock|Glam Rock',
3373            1151 => 'Music|Rock|Hair Metal',
3374            1152 => 'Music|Rock|Hard Rock',
3375            1153 => 'Music|Rock|Metal',
3376            1154 => 'Music|Rock|Jam Bands',
3377            1155 => 'Music|Rock|Prog-Rock/Art Rock',
3378            1156 => 'Music|Rock|Psychedelic',
3379            1157 => 'Music|Rock|Rock & Roll',
3380            1158 => 'Music|Rock|Rockabilly',
3381            1159 => 'Music|Rock|Roots Rock',
3382            1160 => 'Music|Rock|Singer/Songwriter',
3383            1161 => 'Music|Rock|Southern Rock',
3384            1162 => 'Music|Rock|Surf',
3385            1163 => 'Music|Rock|Tex-Mex',
3386            1165 => 'Music|Soundtrack|Foreign Cinema',
3387            1166 => 'Music|Soundtrack|Musicals',
3388            1167 => 'Music|Comedy|Novelty',
3389            1168 => 'Music|Soundtrack|Original Score',
3390            1169 => 'Music|Soundtrack|Soundtrack',
3391            1171 => 'Music|Comedy|Standup Comedy',
3392            1172 => 'Music|Soundtrack|TV Soundtrack',
3393            1173 => 'Music|Vocal|Standards',
3394            1174 => 'Music|Vocal|Traditional Pop',
3395            1175 => 'Music|Jazz|Vocal Jazz',
3396            1176 => 'Music|Vocal|Vocal Pop',
3397            1177 => 'Music|African|Afro-Beat',
3398            1178 => 'Music|African|Afro-Pop',
3399            1179 => 'Music|World|Cajun',
3400            1180 => 'Music|World|Celtic',
3401            1181 => 'Music|World|Celtic Folk',
3402            1182 => 'Music|World|Contemporary Celtic',
3403            1183 => 'Music|Reggae|Modern Dancehall',
3404            1184 => 'Music|World|Drinking Songs',
3405            1185 => 'Music|Indian|Indian Pop',
3406            1186 => 'Music|World|Japanese Pop',
3407            1187 => 'Music|World|Klezmer',
3408            1188 => 'Music|World|Polka',
3409            1189 => 'Music|World|Traditional Celtic',
3410            1190 => 'Music|World|Worldbeat',
3411            1191 => 'Music|World|Zydeco',
3412            1192 => 'Music|Reggae|Roots Reggae',
3413            1193 => 'Music|Reggae|Dub',
3414            1194 => 'Music|Reggae|Ska',
3415            1195 => 'Music|World|Caribbean',
3416            1196 => 'Music|World|South America',
3417            1197 => 'Music|Arabic',
3418            1198 => 'Music|World|North America',
3419            1199 => 'Music|World|Hawaii',
3420            1200 => 'Music|World|Australia',
3421            1201 => 'Music|World|Japan',
3422            1202 => 'Music|World|France',
3423            1203 => 'Music|African',
3424            1204 => 'Music|World|Asia',
3425            1205 => 'Music|World|Europe',
3426            1206 => 'Music|World|South Africa',
3427            1207 => 'Music|Jazz|Hard Bop',
3428            1208 => 'Music|Jazz|Trad Jazz',
3429            1209 => 'Music|Jazz|Cool Jazz',
3430            1210 => 'Music|Blues|Acoustic Blues',
3431            1211 => 'Music|Classical|High Classical',
3432            1220 => 'Music|Brazilian|Axe', # (Ax&eacute;)
3433            1221 => 'Music|Brazilian|Bossa Nova',
3434            1222 => 'Music|Brazilian|Choro',
3435            1223 => 'Music|Brazilian|Forro', # (Forr&oacute;)
3436            1224 => 'Music|Brazilian|Frevo',
3437            1225 => 'Music|Brazilian|MPB',
3438            1226 => 'Music|Brazilian|Pagode',
3439            1227 => 'Music|Brazilian|Samba',
3440            1228 => 'Music|Brazilian|Sertanejo',
3441            1229 => 'Music|Brazilian|Baile Funk',
3442            1230 => 'Music|Alternative|Chinese Alt',
3443            1231 => 'Music|Alternative|Korean Indie',
3444            1232 => 'Music|Chinese',
3445            1233 => 'Music|Chinese|Chinese Classical',
3446            1234 => 'Music|Chinese|Chinese Flute',
3447            1235 => 'Music|Chinese|Chinese Opera',
3448            1236 => 'Music|Chinese|Chinese Orchestral',
3449            1237 => 'Music|Chinese|Chinese Regional Folk',
3450            1238 => 'Music|Chinese|Chinese Strings',
3451            1239 => 'Music|Chinese|Taiwanese Folk',
3452            1240 => 'Music|Chinese|Tibetan Native Music',
3453            1241 => 'Music|Hip-Hop/Rap|Chinese Hip-Hop',
3454            1242 => 'Music|Hip-Hop/Rap|Korean Hip-Hop',
3455            1243 => 'Music|Korean',
3456            1244 => 'Music|Korean|Korean Classical',
3457            1245 => 'Music|Korean|Korean Trad Song',
3458            1246 => 'Music|Korean|Korean Trad Instrumental',
3459            1247 => 'Music|Korean|Korean Trad Theater',
3460            1248 => 'Music|Rock|Chinese Rock',
3461            1249 => 'Music|Rock|Korean Rock',
3462            1250 => 'Music|Pop|C-Pop',
3463            1251 => 'Music|Pop|Cantopop/HK-Pop',
3464            1252 => 'Music|Pop|Korean Folk-Pop',
3465            1253 => 'Music|Pop|Mandopop',
3466            1254 => 'Music|Pop|Tai-Pop',
3467            1255 => 'Music|Pop|Malaysian Pop',
3468            1256 => 'Music|Pop|Pinoy Pop',
3469            1257 => 'Music|Pop|Original Pilipino Music',
3470            1258 => 'Music|Pop|Manilla Sound',
3471            1259 => 'Music|Pop|Indo Pop',
3472            1260 => 'Music|Pop|Thai Pop',
3473            1261 => 'Music|Vocal|Trot',
3474            1262 => 'Music|Indian',
3475            1263 => 'Music|Indian|Bollywood',
3476            1264 => 'Music|Indian|Regional Indian|Tamil',
3477            1265 => 'Music|Indian|Regional Indian|Telugu',
3478            1266 => 'Music|Indian|Regional Indian',
3479            1267 => 'Music|Indian|Devotional & Spiritual',
3480            1268 => 'Music|Indian|Sufi',
3481            1269 => 'Music|Indian|Indian Classical',
3482            1270 => 'Music|Russian|Russian Chanson',
3483            1271 => 'Music|World|Dini',
3484            1272 => 'Music|Turkish|Halk',
3485            1273 => 'Music|Turkish|Sanat',
3486            1274 => 'Music|World|Dangdut',
3487            1275 => 'Music|World|Indonesian Religious',
3488            1276 => 'Music|World|Calypso',
3489            1277 => 'Music|World|Soca',
3490            1278 => 'Music|Indian|Ghazals',
3491            1279 => 'Music|Indian|Indian Folk',
3492            1280 => 'Music|Turkish|Arabesque',
3493            1281 => 'Music|African|Afrikaans',
3494            1282 => 'Music|World|Farsi',
3495            1283 => 'Music|World|Israeli',
3496            1284 => 'Music|Arabic|Khaleeji',
3497            1285 => 'Music|Arabic|North African',
3498            1286 => 'Music|Arabic|Arabic Pop',
3499            1287 => 'Music|Arabic|Islamic',
3500            1288 => 'Music|Soundtrack|Sound Effects',
3501            1289 => 'Music|Folk',
3502            1290 => 'Music|Orchestral',
3503            1291 => 'Music|Marching',
3504            1293 => 'Music|Pop|Oldies',
3505            1294 => 'Music|Country|Thai Country',
3506            1295 => 'Music|World|Flamenco',
3507            1296 => 'Music|World|Tango',
3508            1297 => 'Music|World|Fado',
3509            1298 => 'Music|World|Iberia',
3510            1299 => 'Music|Russian',
3511            1300 => 'Music|Turkish',
3512            1301 => 'Podcasts|Arts',
3513            1302 => 'Podcasts|Society & Culture|Personal Journals',
3514            1303 => 'Podcasts|Comedy',
3515            1304 => 'Podcasts|Education',
3516            1305 => 'Podcasts|Kids & Family',
3517            1306 => 'Podcasts|Arts|Food',
3518            1307 => 'Podcasts|Health',
3519            1309 => 'Podcasts|TV & Film',
3520            1310 => 'Podcasts|Music',
3521            1311 => 'Podcasts|News & Politics',
3522            1314 => 'Podcasts|Religion & Spirituality',
3523            1315 => 'Podcasts|Science & Medicine',
3524            1316 => 'Podcasts|Sports & Recreation',
3525            1318 => 'Podcasts|Technology',
3526            1320 => 'Podcasts|Society & Culture|Places & Travel',
3527            1321 => 'Podcasts|Business',
3528            1323 => 'Podcasts|Games & Hobbies',
3529            1324 => 'Podcasts|Society & Culture',
3530            1325 => 'Podcasts|Government & Organizations',
3531            1337 => 'Music Videos|Classical|Piano',
3532            1401 => 'Podcasts|Arts|Literature',
3533            1402 => 'Podcasts|Arts|Design',
3534            1404 => 'Podcasts|Games & Hobbies|Video Games',
3535            1405 => 'Podcasts|Arts|Performing Arts',
3536            1406 => 'Podcasts|Arts|Visual Arts',
3537            1410 => 'Podcasts|Business|Careers',
3538            1412 => 'Podcasts|Business|Investing',
3539            1413 => 'Podcasts|Business|Management & Marketing',
3540            1415 => 'Podcasts|Education|K-12',
3541            1416 => 'Podcasts|Education|Higher Education',
3542            1417 => 'Podcasts|Health|Fitness & Nutrition',
3543            1420 => 'Podcasts|Health|Self-Help',
3544            1421 => 'Podcasts|Health|Sexuality',
3545            1438 => 'Podcasts|Religion & Spirituality|Buddhism',
3546            1439 => 'Podcasts|Religion & Spirituality|Christianity',
3547            1440 => 'Podcasts|Religion & Spirituality|Islam',
3548            1441 => 'Podcasts|Religion & Spirituality|Judaism',
3549            1443 => 'Podcasts|Society & Culture|Philosophy',
3550            1444 => 'Podcasts|Religion & Spirituality|Spirituality',
3551            1446 => 'Podcasts|Technology|Gadgets',
3552            1448 => 'Podcasts|Technology|Tech News',
3553            1450 => 'Podcasts|Technology|Podcasting',
3554            1454 => 'Podcasts|Games & Hobbies|Automotive',
3555            1455 => 'Podcasts|Games & Hobbies|Aviation',
3556            1456 => 'Podcasts|Sports & Recreation|Outdoor',
3557            1459 => 'Podcasts|Arts|Fashion & Beauty',
3558            1460 => 'Podcasts|Games & Hobbies|Hobbies',
3559            1461 => 'Podcasts|Games & Hobbies|Other Games',
3560            1462 => 'Podcasts|Society & Culture|History',
3561            1463 => 'Podcasts|Religion & Spirituality|Hinduism',
3562            1464 => 'Podcasts|Religion & Spirituality|Other',
3563            1465 => 'Podcasts|Sports & Recreation|Professional',
3564            1466 => 'Podcasts|Sports & Recreation|College & High School',
3565            1467 => 'Podcasts|Sports & Recreation|Amateur',
3566            1468 => 'Podcasts|Education|Educational Technology',
3567            1469 => 'Podcasts|Education|Language Courses',
3568            1470 => 'Podcasts|Education|Training',
3569            1471 => 'Podcasts|Business|Business News',
3570            1472 => 'Podcasts|Business|Shopping',
3571            1473 => 'Podcasts|Government & Organizations|National',
3572            1474 => 'Podcasts|Government & Organizations|Regional',
3573            1475 => 'Podcasts|Government & Organizations|Local',
3574            1476 => 'Podcasts|Government & Organizations|Non-Profit',
3575            1477 => 'Podcasts|Science & Medicine|Natural Sciences',
3576            1478 => 'Podcasts|Science & Medicine|Medicine',
3577            1479 => 'Podcasts|Science & Medicine|Social Sciences',
3578            1480 => 'Podcasts|Technology|Software How-To',
3579            1481 => 'Podcasts|Health|Alternative Health',
3580            1482 => 'Podcasts|Arts|Books',
3581            1483 => 'Podcasts|Fiction',
3582            1484 => 'Podcasts|Fiction|Drama',
3583            1485 => 'Podcasts|Fiction|Science Fiction',
3584            1486 => 'Podcasts|Fiction|Comedy Fiction',
3585            1487 => 'Podcasts|History',
3586            1488 => 'Podcasts|True Crime',
3587            1489 => 'Podcasts|News',
3588            1490 => 'Podcasts|News|Business News',
3589            1491 => 'Podcasts|Business|Management',
3590            1492 => 'Podcasts|Business|Marketing',
3591            1493 => 'Podcasts|Business|Entrepreneurship',
3592            1494 => 'Podcasts|Business|Non-Profit',
3593            1495 => 'Podcasts|Comedy|Improv',
3594            1496 => 'Podcasts|Comedy|Comedy Interviews',
3595            1497 => 'Podcasts|Comedy|Stand-Up',
3596            1498 => 'Podcasts|Education|Language Learning',
3597            1499 => 'Podcasts|Education|How To',
3598            1500 => 'Podcasts|Education|Self-Improvement',
3599            1501 => 'Podcasts|Education|Courses',
3600            1502 => 'Podcasts|Leisure',
3601            1503 => 'Podcasts|Leisure|Automotive',
3602            1504 => 'Podcasts|Leisure|Aviation',
3603            1505 => 'Podcasts|Leisure|Hobbies',
3604            1506 => 'Podcasts|Leisure|Crafts',
3605            1507 => 'Podcasts|Leisure|Games',
3606            1508 => 'Podcasts|Leisure|Home & Garden',
3607            1509 => 'Podcasts|Leisure|Video Games',
3608            1510 => 'Podcasts|Leisure|Animation & Manga',
3609            1511 => 'Podcasts|Government',
3610            1512 => 'Podcasts|Health & Fitness',
3611            1513 => 'Podcasts|Health & Fitness|Alternative Health',
3612            1514 => 'Podcasts|Health & Fitness|Fitness',
3613            1515 => 'Podcasts|Health & Fitness|Nutrition',
3614            1516 => 'Podcasts|Health & Fitness|Sexuality',
3615            1517 => 'Podcasts|Health & Fitness|Mental Health',
3616            1518 => 'Podcasts|Health & Fitness|Medicine',
3617            1519 => 'Podcasts|Kids & Family|Education for Kids',
3618            1520 => 'Podcasts|Kids & Family|Stories for Kids',
3619            1521 => 'Podcasts|Kids & Family|Parenting',
3620            1522 => 'Podcasts|Kids & Family|Pets & Animals',
3621            1523 => 'Podcasts|Music|Music Commentary',
3622            1524 => 'Podcasts|Music|Music History',
3623            1525 => 'Podcasts|Music|Music Interviews',
3624            1526 => 'Podcasts|News|Daily News',
3625            1527 => 'Podcasts|News|Politics',
3626            1528 => 'Podcasts|News|Tech News',
3627            1529 => 'Podcasts|News|Sports News',
3628            1530 => 'Podcasts|News|News Commentary',
3629            1531 => 'Podcasts|News|Entertainment News',
3630            1532 => 'Podcasts|Religion & Spirituality|Religion',
3631            1533 => 'Podcasts|Science',
3632            1534 => 'Podcasts|Science|Natural Sciences',
3633            1535 => 'Podcasts|Science|Social Sciences',
3634            1536 => 'Podcasts|Science|Mathematics',
3635            1537 => 'Podcasts|Science|Nature',
3636            1538 => 'Podcasts|Science|Astronomy',
3637            1539 => 'Podcasts|Science|Chemistry',
3638            1540 => 'Podcasts|Science|Earth Sciences',
3639            1541 => 'Podcasts|Science|Life Sciences',
3640            1542 => 'Podcasts|Science|Physics',
3641            1543 => 'Podcasts|Society & Culture|Documentary',
3642            1544 => 'Podcasts|Society & Culture|Relationships',
3643            1545 => 'Podcasts|Sports',
3644            1546 => 'Podcasts|Sports|Soccer',
3645            1547 => 'Podcasts|Sports|Football',
3646            1548 => 'Podcasts|Sports|Basketball',
3647            1549 => 'Podcasts|Sports|Baseball',
3648            1550 => 'Podcasts|Sports|Hockey',
3649            1551 => 'Podcasts|Sports|Running',
3650            1552 => 'Podcasts|Sports|Rugby',
3651            1553 => 'Podcasts|Sports|Golf',
3652            1554 => 'Podcasts|Sports|Cricket',
3653            1555 => 'Podcasts|Sports|Wrestling',
3654            1556 => 'Podcasts|Sports|Tennis',
3655            1557 => 'Podcasts|Sports|Volleyball',
3656            1558 => 'Podcasts|Sports|Swimming',
3657            1559 => 'Podcasts|Sports|Wilderness',
3658            1560 => 'Podcasts|Sports|Fantasy Sports',
3659            1561 => 'Podcasts|TV & Film|TV Reviews',
3660            1562 => 'Podcasts|TV & Film|After Shows',
3661            1563 => 'Podcasts|TV & Film|Film Reviews',
3662            1564 => 'Podcasts|TV & Film|Film History',
3663            1565 => 'Podcasts|TV & Film|Film Interviews',
3664            1602 => 'Music Videos|Blues',
3665            1603 => 'Music Videos|Comedy',
3666            1604 => "Music Videos|Children's Music",
3667            1605 => 'Music Videos|Classical',
3668            1606 => 'Music Videos|Country',
3669            1607 => 'Music Videos|Electronic',
3670            1608 => 'Music Videos|Holiday',
3671            1609 => 'Music Videos|Classical|Opera',
3672            1610 => 'Music Videos|Singer/Songwriter',
3673            1611 => 'Music Videos|Jazz',
3674            1612 => 'Music Videos|Latin',
3675            1613 => 'Music Videos|New Age',
3676            1614 => 'Music Videos|Pop',
3677            1615 => 'Music Videos|R&B/Soul',
3678            1616 => 'Music Videos|Soundtrack',
3679            1617 => 'Music Videos|Dance',
3680            1618 => 'Music Videos|Hip-Hop/Rap',
3681            1619 => 'Music Videos|World',
3682            1620 => 'Music Videos|Alternative',
3683            1621 => 'Music Videos|Rock',
3684            1622 => 'Music Videos|Christian & Gospel',
3685            1623 => 'Music Videos|Vocal',
3686            1624 => 'Music Videos|Reggae',
3687            1625 => 'Music Videos|Easy Listening',
3688            1626 => 'Music Videos|Podcasts',
3689            1627 => 'Music Videos|J-Pop',
3690            1628 => 'Music Videos|Enka',
3691            1629 => 'Music Videos|Anime',
3692            1630 => 'Music Videos|Kayokyoku',
3693            1631 => 'Music Videos|Disney',
3694            1632 => 'Music Videos|French Pop',
3695            1633 => 'Music Videos|German Pop',
3696            1634 => 'Music Videos|German Folk',
3697            1635 => 'Music Videos|Alternative|Chinese Alt',
3698            1636 => 'Music Videos|Alternative|Korean Indie',
3699            1637 => 'Music Videos|Chinese',
3700            1638 => 'Music Videos|Chinese|Chinese Classical',
3701            1639 => 'Music Videos|Chinese|Chinese Flute',
3702            1640 => 'Music Videos|Chinese|Chinese Opera',
3703            1641 => 'Music Videos|Chinese|Chinese Orchestral',
3704            1642 => 'Music Videos|Chinese|Chinese Regional Folk',
3705            1643 => 'Music Videos|Chinese|Chinese Strings',
3706            1644 => 'Music Videos|Chinese|Taiwanese Folk',
3707            1645 => 'Music Videos|Chinese|Tibetan Native Music',
3708            1646 => 'Music Videos|Hip-Hop/Rap|Chinese Hip-Hop',
3709            1647 => 'Music Videos|Hip-Hop/Rap|Korean Hip-Hop',
3710            1648 => 'Music Videos|Korean',
3711            1649 => 'Music Videos|Korean|Korean Classical',
3712            1650 => 'Music Videos|Korean|Korean Trad Song',
3713            1651 => 'Music Videos|Korean|Korean Trad Instrumental',
3714            1652 => 'Music Videos|Korean|Korean Trad Theater',
3715            1653 => 'Music Videos|Rock|Chinese Rock',
3716            1654 => 'Music Videos|Rock|Korean Rock',
3717            1655 => 'Music Videos|Pop|C-Pop',
3718            1656 => 'Music Videos|Pop|Cantopop/HK-Pop',
3719            1657 => 'Music Videos|Pop|Korean Folk-Pop',
3720            1658 => 'Music Videos|Pop|Mandopop',
3721            1659 => 'Music Videos|Pop|Tai-Pop',
3722            1660 => 'Music Videos|Pop|Malaysian Pop',
3723            1661 => 'Music Videos|Pop|Pinoy Pop',
3724            1662 => 'Music Videos|Pop|Original Pilipino Music',
3725            1663 => 'Music Videos|Pop|Manilla Sound',
3726            1664 => 'Music Videos|Pop|Indo Pop',
3727            1665 => 'Music Videos|Pop|Thai Pop',
3728            1666 => 'Music Videos|Vocal|Trot',
3729            1671 => 'Music Videos|Brazilian',
3730            1672 => 'Music Videos|Brazilian|Axe', # (Ax&eacute;)
3731            1673 => 'Music Videos|Brazilian|Baile Funk',
3732            1674 => 'Music Videos|Brazilian|Bossa Nova',
3733            1675 => 'Music Videos|Brazilian|Choro',
3734            1676 => 'Music Videos|Brazilian|Forro',
3735            1677 => 'Music Videos|Brazilian|Frevo',
3736            1678 => 'Music Videos|Brazilian|MPB',
3737            1679 => 'Music Videos|Brazilian|Pagode',
3738            1680 => 'Music Videos|Brazilian|Samba',
3739            1681 => 'Music Videos|Brazilian|Sertanejo',
3740            1682 => 'Music Videos|Classical|High Classical',
3741            1683 => 'Music Videos|Fitness & Workout',
3742            1684 => 'Music Videos|Instrumental',
3743            1685 => 'Music Videos|Jazz|Big Band',
3744            1686 => 'Music Videos|Pop|K-Pop',
3745            1687 => 'Music Videos|Karaoke',
3746            1688 => 'Music Videos|Rock|Heavy Metal',
3747            1689 => 'Music Videos|Spoken Word',
3748            1690 => 'Music Videos|Indian',
3749            1691 => 'Music Videos|Indian|Bollywood',
3750            1692 => 'Music Videos|Indian|Regional Indian|Tamil',
3751            1693 => 'Music Videos|Indian|Regional Indian|Telugu',
3752            1694 => 'Music Videos|Indian|Regional Indian',
3753            1695 => 'Music Videos|Indian|Devotional & Spiritual',
3754            1696 => 'Music Videos|Indian|Sufi',
3755            1697 => 'Music Videos|Indian|Indian Classical',
3756            1698 => 'Music Videos|Russian|Russian Chanson',
3757            1699 => 'Music Videos|World|Dini',
3758            1700 => 'Music Videos|Turkish|Halk',
3759            1701 => 'Music Videos|Turkish|Sanat',
3760            1702 => 'Music Videos|World|Dangdut',
3761            1703 => 'Music Videos|World|Indonesian Religious',
3762            1704 => 'Music Videos|Indian|Indian Pop',
3763            1705 => 'Music Videos|World|Calypso',
3764            1706 => 'Music Videos|World|Soca',
3765            1707 => 'Music Videos|Indian|Ghazals',
3766            1708 => 'Music Videos|Indian|Indian Folk',
3767            1709 => 'Music Videos|Turkish|Arabesque',
3768            1710 => 'Music Videos|African|Afrikaans',
3769            1711 => 'Music Videos|World|Farsi',
3770            1712 => 'Music Videos|World|Israeli',
3771            1713 => 'Music Videos|Arabic',
3772            1714 => 'Music Videos|Arabic|Khaleeji',
3773            1715 => 'Music Videos|Arabic|North African',
3774            1716 => 'Music Videos|Arabic|Arabic Pop',
3775            1717 => 'Music Videos|Arabic|Islamic',
3776            1718 => 'Music Videos|Soundtrack|Sound Effects',
3777            1719 => 'Music Videos|Folk',
3778            1720 => 'Music Videos|Orchestral',
3779            1721 => 'Music Videos|Marching',
3780            1723 => 'Music Videos|Pop|Oldies',
3781            1724 => 'Music Videos|Country|Thai Country',
3782            1725 => 'Music Videos|World|Flamenco',
3783            1726 => 'Music Videos|World|Tango',
3784            1727 => 'Music Videos|World|Fado',
3785            1728 => 'Music Videos|World|Iberia',
3786            1729 => 'Music Videos|Russian',
3787            1730 => 'Music Videos|Turkish',
3788            1731 => 'Music Videos|Alternative|College Rock',
3789            1732 => 'Music Videos|Alternative|Goth Rock',
3790            1733 => 'Music Videos|Alternative|Grunge',
3791            1734 => 'Music Videos|Alternative|Indie Rock',
3792            1735 => 'Music Videos|Alternative|New Wave',
3793            1736 => 'Music Videos|Alternative|Punk',
3794            1737 => 'Music Videos|Blues|Acoustic Blues',
3795            1738 => 'Music Videos|Blues|Chicago Blues',
3796            1739 => 'Music Videos|Blues|Classic Blues',
3797            1740 => 'Music Videos|Blues|Contemporary Blues',
3798            1741 => 'Music Videos|Blues|Country Blues',
3799            1742 => 'Music Videos|Blues|Delta Blues',
3800            1743 => 'Music Videos|Blues|Electric Blues',
3801            1744 => "Music Videos|Children's Music|Lullabies",
3802            1745 => "Music Videos|Children's Music|Sing-Along",
3803            1746 => "Music Videos|Children's Music|Stories",
3804            1747 => 'Music Videos|Christian & Gospel|CCM',
3805            1748 => 'Music Videos|Christian & Gospel|Christian Metal',
3806            1749 => 'Music Videos|Christian & Gospel|Christian Pop',
3807            1750 => 'Music Videos|Christian & Gospel|Christian Rap',
3808            1751 => 'Music Videos|Christian & Gospel|Christian Rock',
3809            1752 => 'Music Videos|Christian & Gospel|Classic Christian',
3810            1753 => 'Music Videos|Christian & Gospel|Contemporary Gospel',
3811            1754 => 'Music Videos|Christian & Gospel|Gospel',
3812            1755 => 'Music Videos|Christian & Gospel|Praise & Worship',
3813            1756 => 'Music Videos|Christian & Gospel|Southern Gospel',
3814            1757 => 'Music Videos|Christian & Gospel|Traditional Gospel',
3815            1758 => 'Music Videos|Classical|Avant-Garde',
3816            1759 => 'Music Videos|Classical|Baroque Era',
3817            1760 => 'Music Videos|Classical|Chamber Music',
3818            1761 => 'Music Videos|Classical|Chant',
3819            1762 => 'Music Videos|Classical|Choral',
3820            1763 => 'Music Videos|Classical|Classical Crossover',
3821            1764 => 'Music Videos|Classical|Early Music',
3822            1765 => 'Music Videos|Classical|Impressionist',
3823            1766 => 'Music Videos|Classical|Medieval Era',
3824            1767 => 'Music Videos|Classical|Minimalism',
3825            1768 => 'Music Videos|Classical|Modern Era',
3826            1769 => 'Music Videos|Classical|Orchestral',
3827            1770 => 'Music Videos|Classical|Renaissance',
3828            1771 => 'Music Videos|Classical|Romantic Era',
3829            1772 => 'Music Videos|Classical|Wedding Music',
3830            1773 => 'Music Videos|Comedy|Novelty',
3831            1774 => 'Music Videos|Comedy|Standup Comedy',
3832            1775 => 'Music Videos|Country|Alternative Country',
3833            1776 => 'Music Videos|Country|Americana',
3834            1777 => 'Music Videos|Country|Bluegrass',
3835            1778 => 'Music Videos|Country|Contemporary Bluegrass',
3836            1779 => 'Music Videos|Country|Contemporary Country',
3837            1780 => 'Music Videos|Country|Country Gospel',
3838            1781 => 'Music Videos|Country|Honky Tonk',
3839            1782 => 'Music Videos|Country|Outlaw Country',
3840            1783 => 'Music Videos|Country|Traditional Bluegrass',
3841            1784 => 'Music Videos|Country|Traditional Country',
3842            1785 => 'Music Videos|Country|Urban Cowboy',
3843            1786 => 'Music Videos|Dance|Breakbeat',
3844            1787 => 'Music Videos|Dance|Exercise',
3845            1788 => 'Music Videos|Dance|Garage',
3846            1789 => 'Music Videos|Dance|Hardcore',
3847            1790 => 'Music Videos|Dance|House',
3848            1791 => "Music Videos|Dance|Jungle/Drum'n'bass",
3849            1792 => 'Music Videos|Dance|Techno',
3850            1793 => 'Music Videos|Dance|Trance',
3851            1794 => 'Music Videos|Easy Listening|Lounge',
3852            1795 => 'Music Videos|Easy Listening|Swing',
3853            1796 => 'Music Videos|Electronic|Ambient',
3854            1797 => 'Music Videos|Electronic|Downtempo',
3855            1798 => 'Music Videos|Electronic|Electronica',
3856            1799 => 'Music Videos|Electronic|IDM/Experimental',
3857            1800 => 'Music Videos|Electronic|Industrial',
3858            1801 => 'Music Videos|Hip-Hop/Rap|Alternative Rap',
3859            1802 => 'Music Videos|Hip-Hop/Rap|Dirty South',
3860            1803 => 'Music Videos|Hip-Hop/Rap|East Coast Rap',
3861            1804 => 'Music Videos|Hip-Hop/Rap|Gangsta Rap',
3862            1805 => 'Music Videos|Hip-Hop/Rap|Hardcore Rap',
3863            1806 => 'Music Videos|Hip-Hop/Rap|Hip-Hop',
3864            1807 => 'Music Videos|Hip-Hop/Rap|Latin Rap',
3865            1808 => 'Music Videos|Hip-Hop/Rap|Old School Rap',
3866            1809 => 'Music Videos|Hip-Hop/Rap|Rap',
3867            1810 => 'Music Videos|Hip-Hop/Rap|Underground Rap',
3868            1811 => 'Music Videos|Hip-Hop/Rap|West Coast Rap',
3869            1812 => 'Music Videos|Holiday|Chanukah',
3870            1813 => 'Music Videos|Holiday|Christmas',
3871            1814 => "Music Videos|Holiday|Christmas: Children's",
3872            1815 => 'Music Videos|Holiday|Christmas: Classic',
3873            1816 => 'Music Videos|Holiday|Christmas: Classical',
3874            1817 => 'Music Videos|Holiday|Christmas: Jazz',
3875            1818 => 'Music Videos|Holiday|Christmas: Modern',
3876            1819 => 'Music Videos|Holiday|Christmas: Pop',
3877            1820 => 'Music Videos|Holiday|Christmas: R&B',
3878            1821 => 'Music Videos|Holiday|Christmas: Religious',
3879            1822 => 'Music Videos|Holiday|Christmas: Rock',
3880            1823 => 'Music Videos|Holiday|Easter',
3881            1824 => 'Music Videos|Holiday|Halloween',
3882            1825 => 'Music Videos|Holiday|Thanksgiving',
3883            1826 => 'Music Videos|Jazz|Avant-Garde Jazz',
3884            1828 => 'Music Videos|Jazz|Bop',
3885            1829 => 'Music Videos|Jazz|Contemporary Jazz',
3886            1830 => 'Music Videos|Jazz|Cool Jazz',
3887            1831 => 'Music Videos|Jazz|Crossover Jazz',
3888            1832 => 'Music Videos|Jazz|Dixieland',
3889            1833 => 'Music Videos|Jazz|Fusion',
3890            1834 => 'Music Videos|Jazz|Hard Bop',
3891            1835 => 'Music Videos|Jazz|Latin Jazz',
3892            1836 => 'Music Videos|Jazz|Mainstream Jazz',
3893            1837 => 'Music Videos|Jazz|Ragtime',
3894            1838 => 'Music Videos|Jazz|Smooth Jazz',
3895            1839 => 'Music Videos|Jazz|Trad Jazz',
3896            1840 => 'Music Videos|Latin|Alternative & Rock in Spanish',
3897            1841 => 'Music Videos|Latin|Baladas y Boleros',
3898            1842 => 'Music Videos|Latin|Contemporary Latin',
3899            1843 => 'Music Videos|Latin|Latin Jazz',
3900            1844 => 'Music Videos|Latin|Latin Urban',
3901            1845 => 'Music Videos|Latin|Pop in Spanish',
3902            1846 => 'Music Videos|Latin|Raices',
3903            1847 => 'Music Videos|Latin|Musica Mexicana', # (M&uacute;sica Mexicana)
3904            1848 => 'Music Videos|Latin|Salsa y Tropical',
3905            1849 => 'Music Videos|New Age|Healing',
3906            1850 => 'Music Videos|New Age|Meditation',
3907            1851 => 'Music Videos|New Age|Nature',
3908            1852 => 'Music Videos|New Age|Relaxation',
3909            1853 => 'Music Videos|New Age|Travel',
3910            1854 => 'Music Videos|Pop|Adult Contemporary',
3911            1855 => 'Music Videos|Pop|Britpop',
3912            1856 => 'Music Videos|Pop|Pop/Rock',
3913            1857 => 'Music Videos|Pop|Soft Rock',
3914            1858 => 'Music Videos|Pop|Teen Pop',
3915            1859 => 'Music Videos|R&B/Soul|Contemporary R&B',
3916            1860 => 'Music Videos|R&B/Soul|Disco',
3917            1861 => 'Music Videos|R&B/Soul|Doo Wop',
3918            1862 => 'Music Videos|R&B/Soul|Funk',
3919            1863 => 'Music Videos|R&B/Soul|Motown',
3920            1864 => 'Music Videos|R&B/Soul|Neo-Soul',
3921            1865 => 'Music Videos|R&B/Soul|Soul',
3922            1866 => 'Music Videos|Reggae|Modern Dancehall',
3923            1867 => 'Music Videos|Reggae|Dub',
3924            1868 => 'Music Videos|Reggae|Roots Reggae',
3925            1869 => 'Music Videos|Reggae|Ska',
3926            1870 => 'Music Videos|Rock|Adult Alternative',
3927            1871 => 'Music Videos|Rock|American Trad Rock',
3928            1872 => 'Music Videos|Rock|Arena Rock',
3929            1873 => 'Music Videos|Rock|Blues-Rock',
3930            1874 => 'Music Videos|Rock|British Invasion',
3931            1875 => 'Music Videos|Rock|Death Metal/Black Metal',
3932            1876 => 'Music Videos|Rock|Glam Rock',
3933            1877 => 'Music Videos|Rock|Hair Metal',
3934            1878 => 'Music Videos|Rock|Hard Rock',
3935            1879 => 'Music Videos|Rock|Jam Bands',
3936            1880 => 'Music Videos|Rock|Prog-Rock/Art Rock',
3937            1881 => 'Music Videos|Rock|Psychedelic',
3938            1882 => 'Music Videos|Rock|Rock & Roll',
3939            1883 => 'Music Videos|Rock|Rockabilly',
3940            1884 => 'Music Videos|Rock|Roots Rock',
3941            1885 => 'Music Videos|Rock|Singer/Songwriter',
3942            1886 => 'Music Videos|Rock|Southern Rock',
3943            1887 => 'Music Videos|Rock|Surf',
3944            1888 => 'Music Videos|Rock|Tex-Mex',
3945            1889 => 'Music Videos|Singer/Songwriter|Alternative Folk',
3946            1890 => 'Music Videos|Singer/Songwriter|Contemporary Folk',
3947            1891 => 'Music Videos|Singer/Songwriter|Contemporary Singer/Songwriter',
3948            1892 => 'Music Videos|Singer/Songwriter|Folk-Rock',
3949            1893 => 'Music Videos|Singer/Songwriter|New Acoustic',
3950            1894 => 'Music Videos|Singer/Songwriter|Traditional Folk',
3951            1895 => 'Music Videos|Soundtrack|Foreign Cinema',
3952            1896 => 'Music Videos|Soundtrack|Musicals',
3953            1897 => 'Music Videos|Soundtrack|Original Score',
3954            1898 => 'Music Videos|Soundtrack|Soundtrack',
3955            1899 => 'Music Videos|Soundtrack|TV Soundtrack',
3956            1900 => 'Music Videos|Vocal|Standards',
3957            1901 => 'Music Videos|Vocal|Traditional Pop',
3958            1902 => 'Music Videos|Jazz|Vocal Jazz',
3959            1903 => 'Music Videos|Vocal|Vocal Pop',
3960            1904 => 'Music Videos|African',
3961            1905 => 'Music Videos|African|Afro-Beat',
3962            1906 => 'Music Videos|African|Afro-Pop',
3963            1907 => 'Music Videos|World|Asia',
3964            1908 => 'Music Videos|World|Australia',
3965            1909 => 'Music Videos|World|Cajun',
3966            1910 => 'Music Videos|World|Caribbean',
3967            1911 => 'Music Videos|World|Celtic',
3968            1912 => 'Music Videos|World|Celtic Folk',
3969            1913 => 'Music Videos|World|Contemporary Celtic',
3970            1914 => 'Music Videos|World|Europe',
3971            1915 => 'Music Videos|World|France',
3972            1916 => 'Music Videos|World|Hawaii',
3973            1917 => 'Music Videos|World|Japan',
3974            1918 => 'Music Videos|World|Klezmer',
3975            1919 => 'Music Videos|World|North America',
3976            1920 => 'Music Videos|World|Polka',
3977            1921 => 'Music Videos|World|South Africa',
3978            1922 => 'Music Videos|World|South America',
3979            1923 => 'Music Videos|World|Traditional Celtic',
3980            1924 => 'Music Videos|World|Worldbeat',
3981            1925 => 'Music Videos|World|Zydeco',
3982            1926 => 'Music Videos|Christian & Gospel',
3983            1928 => 'Music Videos|Classical|Art Song',
3984            1929 => 'Music Videos|Classical|Brass & Woodwinds',
3985            1930 => 'Music Videos|Classical|Solo Instrumental',
3986            1931 => 'Music Videos|Classical|Contemporary Era',
3987            1932 => 'Music Videos|Classical|Oratorio',
3988            1933 => 'Music Videos|Classical|Cantata',
3989            1934 => 'Music Videos|Classical|Electronic',
3990            1935 => 'Music Videos|Classical|Sacred',
3991            1936 => 'Music Videos|Classical|Guitar',
3992            1938 => 'Music Videos|Classical|Violin',
3993            1939 => 'Music Videos|Classical|Cello',
3994            1940 => 'Music Videos|Classical|Percussion',
3995            1941 => 'Music Videos|Electronic|Dubstep',
3996            1942 => 'Music Videos|Electronic|Bass',
3997            1943 => 'Music Videos|Hip-Hop/Rap|UK Hip-Hop',
3998            1944 => 'Music Videos|Reggae|Lovers Rock',
3999            1945 => 'Music Videos|Alternative|EMO',
4000            1946 => 'Music Videos|Alternative|Pop Punk',
4001            1947 => 'Music Videos|Alternative|Indie Pop',
4002            1948 => 'Music Videos|New Age|Yoga',
4003            1949 => 'Music Videos|Pop|Tribute',
4004            1950 => 'Music Videos|Pop|Shows',
4005            1951 => 'Music Videos|Cuban',
4006            1952 => 'Music Videos|Cuban|Mambo',
4007            1953 => 'Music Videos|Cuban|Chachacha',
4008            1954 => 'Music Videos|Cuban|Guajira',
4009            1955 => 'Music Videos|Cuban|Son',
4010            1956 => 'Music Videos|Cuban|Bolero',
4011            1957 => 'Music Videos|Cuban|Guaracha',
4012            1958 => 'Music Videos|Cuban|Timba',
4013            1959 => 'Music Videos|Soundtrack|Video Game',
4014            1960 => 'Music Videos|Indian|Regional Indian|Punjabi|Punjabi Pop',
4015            1961 => 'Music Videos|Indian|Regional Indian|Bengali|Rabindra Sangeet',
4016            1962 => 'Music Videos|Indian|Regional Indian|Malayalam',
4017            1963 => 'Music Videos|Indian|Regional Indian|Kannada',
4018            1964 => 'Music Videos|Indian|Regional Indian|Marathi',
4019            1965 => 'Music Videos|Indian|Regional Indian|Gujarati',
4020            1966 => 'Music Videos|Indian|Regional Indian|Assamese',
4021            1967 => 'Music Videos|Indian|Regional Indian|Bhojpuri',
4022            1968 => 'Music Videos|Indian|Regional Indian|Haryanvi',
4023            1969 => 'Music Videos|Indian|Regional Indian|Odia',
4024            1970 => 'Music Videos|Indian|Regional Indian|Rajasthani',
4025            1971 => 'Music Videos|Indian|Regional Indian|Urdu',
4026            1972 => 'Music Videos|Indian|Regional Indian|Punjabi',
4027            1973 => 'Music Videos|Indian|Regional Indian|Bengali',
4028            1974 => 'Music Videos|Indian|Indian Classical|Carnatic Classical',
4029            1975 => 'Music Videos|Indian|Indian Classical|Hindustani Classical',
4030            1976 => 'Music Videos|African|Afro House',
4031            1977 => 'Music Videos|African|Afro Soul',
4032            1978 => 'Music Videos|African|Afrobeats',
4033            1979 => 'Music Videos|African|Benga',
4034            1980 => 'Music Videos|African|Bongo-Flava',
4035            1981 => 'Music Videos|African|Coupe-Decale',
4036            1982 => 'Music Videos|African|Gqom',
4037            1983 => 'Music Videos|African|Highlife',
4038            1984 => 'Music Videos|African|Kuduro',
4039            1985 => 'Music Videos|African|Kizomba',
4040            1986 => 'Music Videos|African|Kwaito',
4041            1987 => 'Music Videos|African|Mbalax',
4042            1988 => 'Music Videos|African|Ndombolo',
4043            1989 => 'Music Videos|African|Shangaan Electro',
4044            1990 => 'Music Videos|African|Soukous',
4045            1991 => 'Music Videos|African|Taarab',
4046            1992 => 'Music Videos|African|Zouglou',
4047            1993 => 'Music Videos|Turkish|Ozgun',
4048            1994 => 'Music Videos|Turkish|Fantezi',
4049            1995 => 'Music Videos|Turkish|Religious',
4050            1996 => 'Music Videos|Pop|Turkish Pop',
4051            1997 => 'Music Videos|Rock|Turkish Rock',
4052            1998 => 'Music Videos|Alternative|Turkish Alternative',
4053            1999 => 'Music Videos|Hip-Hop/Rap|Turkish Hip-Hop/Rap',
4054            2000 => 'Music Videos|African|Maskandi',
4055            2001 => 'Music Videos|Russian|Russian Romance',
4056            2002 => 'Music Videos|Russian|Russian Bard',
4057            2003 => 'Music Videos|Russian|Russian Pop',
4058            2004 => 'Music Videos|Russian|Russian Rock',
4059            2005 => 'Music Videos|Russian|Russian Hip-Hop',
4060            2006 => 'Music Videos|Arabic|Levant',
4061            2007 => 'Music Videos|Arabic|Levant|Dabke',
4062            2008 => 'Music Videos|Arabic|Maghreb Rai',
4063            2009 => 'Music Videos|Arabic|Khaleeji|Khaleeji Jalsat',
4064            2010 => 'Music Videos|Arabic|Khaleeji|Khaleeji Shailat',
4065            2011 => 'Music Videos|Tarab',
4066            2012 => 'Music Videos|Tarab|Iraqi Tarab',
4067            2013 => 'Music Videos|Tarab|Egyptian Tarab',
4068            2014 => 'Music Videos|Tarab|Khaleeji Tarab',
4069            2015 => 'Music Videos|Pop|Levant Pop',
4070            2016 => 'Music Videos|Pop|Iraqi Pop',
4071            2017 => 'Music Videos|Pop|Egyptian Pop',
4072            2018 => 'Music Videos|Pop|Maghreb Pop',
4073            2019 => 'Music Videos|Pop|Khaleeji Pop',
4074            2020 => 'Music Videos|Hip-Hop/Rap|Levant Hip-Hop',
4075            2021 => 'Music Videos|Hip-Hop/Rap|Egyptian Hip-Hop',
4076            2022 => 'Music Videos|Hip-Hop/Rap|Maghreb Hip-Hop',
4077            2023 => 'Music Videos|Hip-Hop/Rap|Khaleeji Hip-Hop',
4078            2024 => 'Music Videos|Alternative|Indie Levant',
4079            2025 => 'Music Videos|Alternative|Indie Egyptian',
4080            2026 => 'Music Videos|Alternative|Indie Maghreb',
4081            2027 => 'Music Videos|Electronic|Levant Electronic',
4082            2028 => "Music Videos|Electronic|Electro-Cha'abi",
4083            2029 => 'Music Videos|Electronic|Maghreb Electronic',
4084            2030 => 'Music Videos|Folk|Iraqi Folk',
4085            2031 => 'Music Videos|Folk|Khaleeji Folk',
4086            2032 => 'Music Videos|Dance|Maghreb Dance',
4087            4000 => 'TV Shows|Comedy',
4088            4001 => 'TV Shows|Drama',
4089            4002 => 'TV Shows|Animation',
4090            4003 => 'TV Shows|Action & Adventure',
4091            4004 => 'TV Shows|Classics',
4092            4005 => 'TV Shows|Kids & Family',
4093            4006 => 'TV Shows|Nonfiction',
4094            4007 => 'TV Shows|Reality TV',
4095            4008 => 'TV Shows|Sci-Fi & Fantasy',
4096            4009 => 'TV Shows|Sports',
4097            4010 => 'TV Shows|Teens',
4098            4011 => 'TV Shows|Latino TV',
4099            4401 => 'Movies|Action & Adventure',
4100            4402 => 'Movies|Anime',
4101            4403 => 'Movies|Classics',
4102            4404 => 'Movies|Comedy',
4103            4405 => 'Movies|Documentary',
4104            4406 => 'Movies|Drama',
4105            4407 => 'Movies|Foreign',
4106            4408 => 'Movies|Horror',
4107            4409 => 'Movies|Independent',
4108            4410 => 'Movies|Kids & Family',
4109            4411 => 'Movies|Musicals',
4110            4412 => 'Movies|Romance',
4111            4413 => 'Movies|Sci-Fi & Fantasy',
4112            4414 => 'Movies|Short Films',
4113            4415 => 'Movies|Special Interest',
4114            4416 => 'Movies|Thriller',
4115            4417 => 'Movies|Sports',
4116            4418 => 'Movies|Western',
4117            4419 => 'Movies|Urban',
4118            4420 => 'Movies|Holiday',
4119            4421 => 'Movies|Made for TV',
4120            4422 => 'Movies|Concert Films',
4121            4423 => 'Movies|Music Documentaries',
4122            4424 => 'Movies|Music Feature Films',
4123            4425 => 'Movies|Japanese Cinema',
4124            4426 => 'Movies|Jidaigeki',
4125            4427 => 'Movies|Tokusatsu',
4126            4428 => 'Movies|Korean Cinema',
4127            4429 => 'Movies|Russian',
4128            4430 => 'Movies|Turkish',
4129            4431 => 'Movies|Bollywood',
4130            4432 => 'Movies|Regional Indian',
4131            4433 => 'Movies|Middle Eastern',
4132            4434 => 'Movies|African',
4133            6000 => 'App Store|Business',
4134            6001 => 'App Store|Weather',
4135            6002 => 'App Store|Utilities',
4136            6003 => 'App Store|Travel',
4137            6004 => 'App Store|Sports',
4138            6005 => 'App Store|Social Networking',
4139            6006 => 'App Store|Reference',
4140            6007 => 'App Store|Productivity',
4141            6008 => 'App Store|Photo & Video',
4142            6009 => 'App Store|News',
4143            6010 => 'App Store|Navigation',
4144            6011 => 'App Store|Music',
4145            6012 => 'App Store|Lifestyle',
4146            6013 => 'App Store|Health & Fitness',
4147            6014 => 'App Store|Games',
4148            6015 => 'App Store|Finance',
4149            6016 => 'App Store|Entertainment',
4150            6017 => 'App Store|Education',
4151            6018 => 'App Store|Books',
4152            6020 => 'App Store|Medical',
4153            6021 => 'App Store|Magazines & Newspapers',
4154            6022 => 'App Store|Catalogs',
4155            6023 => 'App Store|Food & Drink',
4156            6024 => 'App Store|Shopping',
4157            6025 => 'App Store|Stickers',
4158            6026 => 'App Store|Developer Tools',
4159            6027 => 'App Store|Graphics & Design',
4160            7001 => 'App Store|Games|Action',
4161            7002 => 'App Store|Games|Adventure',
4162            7003 => 'App Store|Games|Casual',
4163            7004 => 'App Store|Games|Board',
4164            7005 => 'App Store|Games|Card',
4165            7006 => 'App Store|Games|Casino',
4166            7007 => 'App Store|Games|Dice',
4167            7008 => 'App Store|Games|Educational',
4168            7009 => 'App Store|Games|Family',
4169            7011 => 'App Store|Games|Music',
4170            7012 => 'App Store|Games|Puzzle',
4171            7013 => 'App Store|Games|Racing',
4172            7014 => 'App Store|Games|Role Playing',
4173            7015 => 'App Store|Games|Simulation',
4174            7016 => 'App Store|Games|Sports',
4175            7017 => 'App Store|Games|Strategy',
4176            7018 => 'App Store|Games|Trivia',
4177            7019 => 'App Store|Games|Word',
4178            8001 => 'Tones|Ringtones|Alternative',
4179            8002 => 'Tones|Ringtones|Blues',
4180            8003 => "Tones|Ringtones|Children's Music",
4181            8004 => 'Tones|Ringtones|Classical',
4182            8005 => 'Tones|Ringtones|Comedy',
4183            8006 => 'Tones|Ringtones|Country',
4184            8007 => 'Tones|Ringtones|Dance',
4185            8008 => 'Tones|Ringtones|Electronic',
4186            8009 => 'Tones|Ringtones|Enka',
4187            8010 => 'Tones|Ringtones|French Pop',
4188            8011 => 'Tones|Ringtones|German Folk',
4189            8012 => 'Tones|Ringtones|German Pop',
4190            8013 => 'Tones|Ringtones|Hip-Hop/Rap',
4191            8014 => 'Tones|Ringtones|Holiday',
4192            8015 => 'Tones|Ringtones|Inspirational',
4193            8016 => 'Tones|Ringtones|J-Pop',
4194            8017 => 'Tones|Ringtones|Jazz',
4195            8018 => 'Tones|Ringtones|Kayokyoku',
4196            8019 => 'Tones|Ringtones|Latin',
4197            8020 => 'Tones|Ringtones|New Age',
4198            8021 => 'Tones|Ringtones|Classical|Opera',
4199            8022 => 'Tones|Ringtones|Pop',
4200            8023 => 'Tones|Ringtones|R&B/Soul',
4201            8024 => 'Tones|Ringtones|Reggae',
4202            8025 => 'Tones|Ringtones|Rock',
4203            8026 => 'Tones|Ringtones|Singer/Songwriter',
4204            8027 => 'Tones|Ringtones|Soundtrack',
4205            8028 => 'Tones|Ringtones|Spoken Word',
4206            8029 => 'Tones|Ringtones|Vocal',
4207            8030 => 'Tones|Ringtones|World',
4208            8050 => 'Tones|Alert Tones|Sound Effects',
4209            8051 => 'Tones|Alert Tones|Dialogue',
4210            8052 => 'Tones|Alert Tones|Music',
4211            8053 => 'Tones|Ringtones',
4212            8054 => 'Tones|Alert Tones',
4213            8055 => 'Tones|Ringtones|Alternative|Chinese Alt',
4214            8056 => 'Tones|Ringtones|Alternative|College Rock',
4215            8057 => 'Tones|Ringtones|Alternative|Goth Rock',
4216            8058 => 'Tones|Ringtones|Alternative|Grunge',
4217            8059 => 'Tones|Ringtones|Alternative|Indie Rock',
4218            8060 => 'Tones|Ringtones|Alternative|Korean Indie',
4219            8061 => 'Tones|Ringtones|Alternative|New Wave',
4220            8062 => 'Tones|Ringtones|Alternative|Punk',
4221            8063 => 'Tones|Ringtones|Anime',
4222            8064 => 'Tones|Ringtones|Arabic',
4223            8065 => 'Tones|Ringtones|Arabic|Arabic Pop',
4224            8066 => 'Tones|Ringtones|Arabic|Islamic',
4225            8067 => 'Tones|Ringtones|Arabic|Khaleeji',
4226            8068 => 'Tones|Ringtones|Arabic|North African',
4227            8069 => 'Tones|Ringtones|Blues|Acoustic Blues',
4228            8070 => 'Tones|Ringtones|Blues|Chicago Blues',
4229            8071 => 'Tones|Ringtones|Blues|Classic Blues',
4230            8072 => 'Tones|Ringtones|Blues|Contemporary Blues',
4231            8073 => 'Tones|Ringtones|Blues|Country Blues',
4232            8074 => 'Tones|Ringtones|Blues|Delta Blues',
4233            8075 => 'Tones|Ringtones|Blues|Electric Blues',
4234            8076 => 'Tones|Ringtones|Brazilian',
4235            8077 => 'Tones|Ringtones|Brazilian|Axe', # (Ax&eacute;)
4236            8078 => 'Tones|Ringtones|Brazilian|Baile Funk',
4237            8079 => 'Tones|Ringtones|Brazilian|Bossa Nova',
4238            8080 => 'Tones|Ringtones|Brazilian|Choro',
4239            8081 => 'Tones|Ringtones|Brazilian|Forro', # (Forr&oacute;)
4240            8082 => 'Tones|Ringtones|Brazilian|Frevo',
4241            8083 => 'Tones|Ringtones|Brazilian|MPB',
4242            8084 => 'Tones|Ringtones|Brazilian|Pagode',
4243            8085 => 'Tones|Ringtones|Brazilian|Samba',
4244            8086 => 'Tones|Ringtones|Brazilian|Sertanejo',
4245            8087 => "Tones|Ringtones|Children's Music|Lullabies",
4246            8088 => "Tones|Ringtones|Children's Music|Sing-Along",
4247            8089 => "Tones|Ringtones|Children's Music|Stories",
4248            8090 => 'Tones|Ringtones|Chinese',
4249            8091 => 'Tones|Ringtones|Chinese|Chinese Classical',
4250            8092 => 'Tones|Ringtones|Chinese|Chinese Flute',
4251            8093 => 'Tones|Ringtones|Chinese|Chinese Opera',
4252            8094 => 'Tones|Ringtones|Chinese|Chinese Orchestral',
4253            8095 => 'Tones|Ringtones|Chinese|Chinese Regional Folk',
4254            8096 => 'Tones|Ringtones|Chinese|Chinese Strings',
4255            8097 => 'Tones|Ringtones|Chinese|Taiwanese Folk',
4256            8098 => 'Tones|Ringtones|Chinese|Tibetan Native Music',
4257            8099 => 'Tones|Ringtones|Christian & Gospel',
4258            8100 => 'Tones|Ringtones|Christian & Gospel|CCM',
4259            8101 => 'Tones|Ringtones|Christian & Gospel|Christian Metal',
4260            8102 => 'Tones|Ringtones|Christian & Gospel|Christian Pop',
4261            8103 => 'Tones|Ringtones|Christian & Gospel|Christian Rap',
4262            8104 => 'Tones|Ringtones|Christian & Gospel|Christian Rock',
4263            8105 => 'Tones|Ringtones|Christian & Gospel|Classic Christian',
4264            8106 => 'Tones|Ringtones|Christian & Gospel|Contemporary Gospel',
4265            8107 => 'Tones|Ringtones|Christian & Gospel|Gospel',
4266            8108 => 'Tones|Ringtones|Christian & Gospel|Praise & Worship',
4267            8109 => 'Tones|Ringtones|Christian & Gospel|Southern Gospel',
4268            8110 => 'Tones|Ringtones|Christian & Gospel|Traditional Gospel',
4269            8111 => 'Tones|Ringtones|Classical|Avant-Garde',
4270            8112 => 'Tones|Ringtones|Classical|Baroque Era',
4271            8113 => 'Tones|Ringtones|Classical|Chamber Music',
4272            8114 => 'Tones|Ringtones|Classical|Chant',
4273            8115 => 'Tones|Ringtones|Classical|Choral',
4274            8116 => 'Tones|Ringtones|Classical|Classical Crossover',
4275            8117 => 'Tones|Ringtones|Classical|Early Music',
4276            8118 => 'Tones|Ringtones|Classical|High Classical',
4277            8119 => 'Tones|Ringtones|Classical|Impressionist',
4278            8120 => 'Tones|Ringtones|Classical|Medieval Era',
4279            8121 => 'Tones|Ringtones|Classical|Minimalism',
4280            8122 => 'Tones|Ringtones|Classical|Modern Era',
4281            8123 => 'Tones|Ringtones|Classical|Orchestral',
4282            8124 => 'Tones|Ringtones|Classical|Renaissance',
4283            8125 => 'Tones|Ringtones|Classical|Romantic Era',
4284            8126 => 'Tones|Ringtones|Classical|Wedding Music',
4285            8127 => 'Tones|Ringtones|Comedy|Novelty',
4286            8128 => 'Tones|Ringtones|Comedy|Standup Comedy',
4287            8129 => 'Tones|Ringtones|Country|Alternative Country',
4288            8130 => 'Tones|Ringtones|Country|Americana',
4289            8131 => 'Tones|Ringtones|Country|Bluegrass',
4290            8132 => 'Tones|Ringtones|Country|Contemporary Bluegrass',
4291            8133 => 'Tones|Ringtones|Country|Contemporary Country',
4292            8134 => 'Tones|Ringtones|Country|Country Gospel',
4293            8135 => 'Tones|Ringtones|Country|Honky Tonk',
4294            8136 => 'Tones|Ringtones|Country|Outlaw Country',
4295            8137 => 'Tones|Ringtones|Country|Thai Country',
4296            8138 => 'Tones|Ringtones|Country|Traditional Bluegrass',
4297            8139 => 'Tones|Ringtones|Country|Traditional Country',
4298            8140 => 'Tones|Ringtones|Country|Urban Cowboy',
4299            8141 => 'Tones|Ringtones|Dance|Breakbeat',
4300            8142 => 'Tones|Ringtones|Dance|Exercise',
4301            8143 => 'Tones|Ringtones|Dance|Garage',
4302            8144 => 'Tones|Ringtones|Dance|Hardcore',
4303            8145 => 'Tones|Ringtones|Dance|House',
4304            8146 => "Tones|Ringtones|Dance|Jungle/Drum'n'bass",
4305            8147 => 'Tones|Ringtones|Dance|Techno',
4306            8148 => 'Tones|Ringtones|Dance|Trance',
4307            8149 => 'Tones|Ringtones|Disney',
4308            8150 => 'Tones|Ringtones|Easy Listening',
4309            8151 => 'Tones|Ringtones|Easy Listening|Lounge',
4310            8152 => 'Tones|Ringtones|Easy Listening|Swing',
4311            8153 => 'Tones|Ringtones|Electronic|Ambient',
4312            8154 => 'Tones|Ringtones|Electronic|Downtempo',
4313            8155 => 'Tones|Ringtones|Electronic|Electronica',
4314            8156 => 'Tones|Ringtones|Electronic|IDM/Experimental',
4315            8157 => 'Tones|Ringtones|Electronic|Industrial',
4316            8158 => 'Tones|Ringtones|Fitness & Workout',
4317            8159 => 'Tones|Ringtones|Folk',
4318            8160 => 'Tones|Ringtones|Hip-Hop/Rap|Alternative Rap',
4319            8161 => 'Tones|Ringtones|Hip-Hop/Rap|Chinese Hip-Hop',
4320            8162 => 'Tones|Ringtones|Hip-Hop/Rap|Dirty South',
4321            8163 => 'Tones|Ringtones|Hip-Hop/Rap|East Coast Rap',
4322            8164 => 'Tones|Ringtones|Hip-Hop/Rap|Gangsta Rap',
4323            8165 => 'Tones|Ringtones|Hip-Hop/Rap|Hardcore Rap',
4324            8166 => 'Tones|Ringtones|Hip-Hop/Rap|Hip-Hop',
4325            8167 => 'Tones|Ringtones|Hip-Hop/Rap|Korean Hip-Hop',
4326            8168 => 'Tones|Ringtones|Hip-Hop/Rap|Latin Rap',
4327            8169 => 'Tones|Ringtones|Hip-Hop/Rap|Old School Rap',
4328            8170 => 'Tones|Ringtones|Hip-Hop/Rap|Rap',
4329            8171 => 'Tones|Ringtones|Hip-Hop/Rap|Underground Rap',
4330            8172 => 'Tones|Ringtones|Hip-Hop/Rap|West Coast Rap',
4331            8173 => 'Tones|Ringtones|Holiday|Chanukah',
4332            8174 => 'Tones|Ringtones|Holiday|Christmas',
4333            8175 => "Tones|Ringtones|Holiday|Christmas: Children's",
4334            8176 => 'Tones|Ringtones|Holiday|Christmas: Classic',
4335            8177 => 'Tones|Ringtones|Holiday|Christmas: Classical',
4336            8178 => 'Tones|Ringtones|Holiday|Christmas: Jazz',
4337            8179 => 'Tones|Ringtones|Holiday|Christmas: Modern',
4338            8180 => 'Tones|Ringtones|Holiday|Christmas: Pop',
4339            8181 => 'Tones|Ringtones|Holiday|Christmas: R&B',
4340            8182 => 'Tones|Ringtones|Holiday|Christmas: Religious',
4341            8183 => 'Tones|Ringtones|Holiday|Christmas: Rock',
4342            8184 => 'Tones|Ringtones|Holiday|Easter',
4343            8185 => 'Tones|Ringtones|Holiday|Halloween',
4344            8186 => 'Tones|Ringtones|Holiday|Thanksgiving',
4345            8187 => 'Tones|Ringtones|Indian',
4346            8188 => 'Tones|Ringtones|Indian|Bollywood',
4347            8189 => 'Tones|Ringtones|Indian|Devotional & Spiritual',
4348            8190 => 'Tones|Ringtones|Indian|Ghazals',
4349            8191 => 'Tones|Ringtones|Indian|Indian Classical',
4350            8192 => 'Tones|Ringtones|Indian|Indian Folk',
4351            8193 => 'Tones|Ringtones|Indian|Indian Pop',
4352            8194 => 'Tones|Ringtones|Indian|Regional Indian',
4353            8195 => 'Tones|Ringtones|Indian|Sufi',
4354            8196 => 'Tones|Ringtones|Indian|Regional Indian|Tamil',
4355            8197 => 'Tones|Ringtones|Indian|Regional Indian|Telugu',
4356            8198 => 'Tones|Ringtones|Instrumental',
4357            8199 => 'Tones|Ringtones|Jazz|Avant-Garde Jazz',
4358            8201 => 'Tones|Ringtones|Jazz|Big Band',
4359            8202 => 'Tones|Ringtones|Jazz|Bop',
4360            8203 => 'Tones|Ringtones|Jazz|Contemporary Jazz',
4361            8204 => 'Tones|Ringtones|Jazz|Cool Jazz',
4362            8205 => 'Tones|Ringtones|Jazz|Crossover Jazz',
4363            8206 => 'Tones|Ringtones|Jazz|Dixieland',
4364            8207 => 'Tones|Ringtones|Jazz|Fusion',
4365            8208 => 'Tones|Ringtones|Jazz|Hard Bop',
4366            8209 => 'Tones|Ringtones|Jazz|Latin Jazz',
4367            8210 => 'Tones|Ringtones|Jazz|Mainstream Jazz',
4368            8211 => 'Tones|Ringtones|Jazz|Ragtime',
4369            8212 => 'Tones|Ringtones|Jazz|Smooth Jazz',
4370            8213 => 'Tones|Ringtones|Jazz|Trad Jazz',
4371            8214 => 'Tones|Ringtones|Pop|K-Pop',
4372            8215 => 'Tones|Ringtones|Karaoke',
4373            8216 => 'Tones|Ringtones|Korean',
4374            8217 => 'Tones|Ringtones|Korean|Korean Classical',
4375            8218 => 'Tones|Ringtones|Korean|Korean Trad Instrumental',
4376            8219 => 'Tones|Ringtones|Korean|Korean Trad Song',
4377            8220 => 'Tones|Ringtones|Korean|Korean Trad Theater',
4378            8221 => 'Tones|Ringtones|Latin|Alternative & Rock in Spanish',
4379            8222 => 'Tones|Ringtones|Latin|Baladas y Boleros',
4380            8223 => 'Tones|Ringtones|Latin|Contemporary Latin',
4381            8224 => 'Tones|Ringtones|Latin|Latin Jazz',
4382            8225 => 'Tones|Ringtones|Latin|Latin Urban',
4383            8226 => 'Tones|Ringtones|Latin|Pop in Spanish',
4384            8227 => 'Tones|Ringtones|Latin|Raices',
4385            8228 => 'Tones|Ringtones|Latin|Musica Mexicana', # (M&uacute;sica Mexicana)
4386            8229 => 'Tones|Ringtones|Latin|Salsa y Tropical',
4387            8230 => 'Tones|Ringtones|Marching Bands',
4388            8231 => 'Tones|Ringtones|New Age|Healing',
4389            8232 => 'Tones|Ringtones|New Age|Meditation',
4390            8233 => 'Tones|Ringtones|New Age|Nature',
4391            8234 => 'Tones|Ringtones|New Age|Relaxation',
4392            8235 => 'Tones|Ringtones|New Age|Travel',
4393            8236 => 'Tones|Ringtones|Orchestral',
4394            8237 => 'Tones|Ringtones|Pop|Adult Contemporary',
4395            8238 => 'Tones|Ringtones|Pop|Britpop',
4396            8239 => 'Tones|Ringtones|Pop|C-Pop',
4397            8240 => 'Tones|Ringtones|Pop|Cantopop/HK-Pop',
4398            8241 => 'Tones|Ringtones|Pop|Indo Pop',
4399            8242 => 'Tones|Ringtones|Pop|Korean Folk-Pop',
4400            8243 => 'Tones|Ringtones|Pop|Malaysian Pop',
4401            8244 => 'Tones|Ringtones|Pop|Mandopop',
4402            8245 => 'Tones|Ringtones|Pop|Manilla Sound',
4403            8246 => 'Tones|Ringtones|Pop|Oldies',
4404            8247 => 'Tones|Ringtones|Pop|Original Pilipino Music',
4405            8248 => 'Tones|Ringtones|Pop|Pinoy Pop',
4406            8249 => 'Tones|Ringtones|Pop|Pop/Rock',
4407            8250 => 'Tones|Ringtones|Pop|Soft Rock',
4408            8251 => 'Tones|Ringtones|Pop|Tai-Pop',
4409            8252 => 'Tones|Ringtones|Pop|Teen Pop',
4410            8253 => 'Tones|Ringtones|Pop|Thai Pop',
4411            8254 => 'Tones|Ringtones|R&B/Soul|Contemporary R&B',
4412            8255 => 'Tones|Ringtones|R&B/Soul|Disco',
4413            8256 => 'Tones|Ringtones|R&B/Soul|Doo Wop',
4414            8257 => 'Tones|Ringtones|R&B/Soul|Funk',
4415            8258 => 'Tones|Ringtones|R&B/Soul|Motown',
4416            8259 => 'Tones|Ringtones|R&B/Soul|Neo-Soul',
4417            8260 => 'Tones|Ringtones|R&B/Soul|Soul',
4418            8261 => 'Tones|Ringtones|Reggae|Modern Dancehall',
4419            8262 => 'Tones|Ringtones|Reggae|Dub',
4420            8263 => 'Tones|Ringtones|Reggae|Roots Reggae',
4421            8264 => 'Tones|Ringtones|Reggae|Ska',
4422            8265 => 'Tones|Ringtones|Rock|Adult Alternative',
4423            8266 => 'Tones|Ringtones|Rock|American Trad Rock',
4424            8267 => 'Tones|Ringtones|Rock|Arena Rock',
4425            8268 => 'Tones|Ringtones|Rock|Blues-Rock',
4426            8269 => 'Tones|Ringtones|Rock|British Invasion',
4427            8270 => 'Tones|Ringtones|Rock|Chinese Rock',
4428            8271 => 'Tones|Ringtones|Rock|Death Metal/Black Metal',
4429            8272 => 'Tones|Ringtones|Rock|Glam Rock',
4430            8273 => 'Tones|Ringtones|Rock|Hair Metal',
4431            8274 => 'Tones|Ringtones|Rock|Hard Rock',
4432            8275 => 'Tones|Ringtones|Rock|Metal',
4433            8276 => 'Tones|Ringtones|Rock|Jam Bands',
4434            8277 => 'Tones|Ringtones|Rock|Korean Rock',
4435            8278 => 'Tones|Ringtones|Rock|Prog-Rock/Art Rock',
4436            8279 => 'Tones|Ringtones|Rock|Psychedelic',
4437            8280 => 'Tones|Ringtones|Rock|Rock & Roll',
4438            8281 => 'Tones|Ringtones|Rock|Rockabilly',
4439            8282 => 'Tones|Ringtones|Rock|Roots Rock',
4440            8283 => 'Tones|Ringtones|Rock|Singer/Songwriter',
4441            8284 => 'Tones|Ringtones|Rock|Southern Rock',
4442            8285 => 'Tones|Ringtones|Rock|Surf',
4443            8286 => 'Tones|Ringtones|Rock|Tex-Mex',
4444            8287 => 'Tones|Ringtones|Singer/Songwriter|Alternative Folk',
4445            8288 => 'Tones|Ringtones|Singer/Songwriter|Contemporary Folk',
4446            8289 => 'Tones|Ringtones|Singer/Songwriter|Contemporary Singer/Songwriter',
4447            8290 => 'Tones|Ringtones|Singer/Songwriter|Folk-Rock',
4448            8291 => 'Tones|Ringtones|Singer/Songwriter|New Acoustic',
4449            8292 => 'Tones|Ringtones|Singer/Songwriter|Traditional Folk',
4450            8293 => 'Tones|Ringtones|Soundtrack|Foreign Cinema',
4451            8294 => 'Tones|Ringtones|Soundtrack|Musicals',
4452            8295 => 'Tones|Ringtones|Soundtrack|Original Score',
4453            8296 => 'Tones|Ringtones|Soundtrack|Sound Effects',
4454            8297 => 'Tones|Ringtones|Soundtrack|Soundtrack',
4455            8298 => 'Tones|Ringtones|Soundtrack|TV Soundtrack',
4456            8299 => 'Tones|Ringtones|Vocal|Standards',
4457            8300 => 'Tones|Ringtones|Vocal|Traditional Pop',
4458            8301 => 'Tones|Ringtones|Vocal|Trot',
4459            8302 => 'Tones|Ringtones|Jazz|Vocal Jazz',
4460            8303 => 'Tones|Ringtones|Vocal|Vocal Pop',
4461            8304 => 'Tones|Ringtones|African',
4462            8305 => 'Tones|Ringtones|African|Afrikaans',
4463            8306 => 'Tones|Ringtones|African|Afro-Beat',
4464            8307 => 'Tones|Ringtones|African|Afro-Pop',
4465            8308 => 'Tones|Ringtones|Turkish|Arabesque',
4466            8309 => 'Tones|Ringtones|World|Asia',
4467            8310 => 'Tones|Ringtones|World|Australia',
4468            8311 => 'Tones|Ringtones|World|Cajun',
4469            8312 => 'Tones|Ringtones|World|Calypso',
4470            8313 => 'Tones|Ringtones|World|Caribbean',
4471            8314 => 'Tones|Ringtones|World|Celtic',
4472            8315 => 'Tones|Ringtones|World|Celtic Folk',
4473            8316 => 'Tones|Ringtones|World|Contemporary Celtic',
4474            8317 => 'Tones|Ringtones|World|Dangdut',
4475            8318 => 'Tones|Ringtones|World|Dini',
4476            8319 => 'Tones|Ringtones|World|Europe',
4477            8320 => 'Tones|Ringtones|World|Fado',
4478            8321 => 'Tones|Ringtones|World|Farsi',
4479            8322 => 'Tones|Ringtones|World|Flamenco',
4480            8323 => 'Tones|Ringtones|World|France',
4481            8324 => 'Tones|Ringtones|Turkish|Halk',
4482            8325 => 'Tones|Ringtones|World|Hawaii',
4483            8326 => 'Tones|Ringtones|World|Iberia',
4484            8327 => 'Tones|Ringtones|World|Indonesian Religious',
4485            8328 => 'Tones|Ringtones|World|Israeli',
4486            8329 => 'Tones|Ringtones|World|Japan',
4487            8330 => 'Tones|Ringtones|World|Klezmer',
4488            8331 => 'Tones|Ringtones|World|North America',
4489            8332 => 'Tones|Ringtones|World|Polka',
4490            8333 => 'Tones|Ringtones|Russian',
4491            8334 => 'Tones|Ringtones|Russian|Russian Chanson',
4492            8335 => 'Tones|Ringtones|Turkish|Sanat',
4493            8336 => 'Tones|Ringtones|World|Soca',
4494            8337 => 'Tones|Ringtones|World|South Africa',
4495            8338 => 'Tones|Ringtones|World|South America',
4496            8339 => 'Tones|Ringtones|World|Tango',
4497            8340 => 'Tones|Ringtones|World|Traditional Celtic',
4498            8341 => 'Tones|Ringtones|Turkish',
4499            8342 => 'Tones|Ringtones|World|Worldbeat',
4500            8343 => 'Tones|Ringtones|World|Zydeco',
4501            8345 => 'Tones|Ringtones|Classical|Art Song',
4502            8346 => 'Tones|Ringtones|Classical|Brass & Woodwinds',
4503            8347 => 'Tones|Ringtones|Classical|Solo Instrumental',
4504            8348 => 'Tones|Ringtones|Classical|Contemporary Era',
4505            8349 => 'Tones|Ringtones|Classical|Oratorio',
4506            8350 => 'Tones|Ringtones|Classical|Cantata',
4507            8351 => 'Tones|Ringtones|Classical|Electronic',
4508            8352 => 'Tones|Ringtones|Classical|Sacred',
4509            8353 => 'Tones|Ringtones|Classical|Guitar',
4510            8354 => 'Tones|Ringtones|Classical|Piano',
4511            8355 => 'Tones|Ringtones|Classical|Violin',
4512            8356 => 'Tones|Ringtones|Classical|Cello',
4513            8357 => 'Tones|Ringtones|Classical|Percussion',
4514            8358 => 'Tones|Ringtones|Electronic|Dubstep',
4515            8359 => 'Tones|Ringtones|Electronic|Bass',
4516            8360 => 'Tones|Ringtones|Hip-Hop/Rap|UK Hip Hop',
4517            8361 => 'Tones|Ringtones|Reggae|Lovers Rock',
4518            8362 => 'Tones|Ringtones|Alternative|EMO',
4519            8363 => 'Tones|Ringtones|Alternative|Pop Punk',
4520            8364 => 'Tones|Ringtones|Alternative|Indie Pop',
4521            8365 => 'Tones|Ringtones|New Age|Yoga',
4522            8366 => 'Tones|Ringtones|Pop|Tribute',
4523            8367 => 'Tones|Ringtones|Pop|Shows',
4524            8368 => 'Tones|Ringtones|Cuban',
4525            8369 => 'Tones|Ringtones|Cuban|Mambo',
4526            8370 => 'Tones|Ringtones|Cuban|Chachacha',
4527            8371 => 'Tones|Ringtones|Cuban|Guajira',
4528            8372 => 'Tones|Ringtones|Cuban|Son',
4529            8373 => 'Tones|Ringtones|Cuban|Bolero',
4530            8374 => 'Tones|Ringtones|Cuban|Guaracha',
4531            8375 => 'Tones|Ringtones|Cuban|Timba',
4532            8376 => 'Tones|Ringtones|Soundtrack|Video Game',
4533            8377 => 'Tones|Ringtones|Indian|Regional Indian|Punjabi|Punjabi Pop',
4534            8378 => 'Tones|Ringtones|Indian|Regional Indian|Bengali|Rabindra Sangeet',
4535            8379 => 'Tones|Ringtones|Indian|Regional Indian|Malayalam',
4536            8380 => 'Tones|Ringtones|Indian|Regional Indian|Kannada',
4537            8381 => 'Tones|Ringtones|Indian|Regional Indian|Marathi',
4538            8382 => 'Tones|Ringtones|Indian|Regional Indian|Gujarati',
4539            8383 => 'Tones|Ringtones|Indian|Regional Indian|Assamese',
4540            8384 => 'Tones|Ringtones|Indian|Regional Indian|Bhojpuri',
4541            8385 => 'Tones|Ringtones|Indian|Regional Indian|Haryanvi',
4542            8386 => 'Tones|Ringtones|Indian|Regional Indian|Odia',
4543            8387 => 'Tones|Ringtones|Indian|Regional Indian|Rajasthani',
4544            8388 => 'Tones|Ringtones|Indian|Regional Indian|Urdu',
4545            8389 => 'Tones|Ringtones|Indian|Regional Indian|Punjabi',
4546            8390 => 'Tones|Ringtones|Indian|Regional Indian|Bengali',
4547            8391 => 'Tones|Ringtones|Indian|Indian Classical|Carnatic Classical',
4548            8392 => 'Tones|Ringtones|Indian|Indian Classical|Hindustani Classical',
4549            8393 => 'Tones|Ringtones|African|Afro House',
4550            8394 => 'Tones|Ringtones|African|Afro Soul',
4551            8395 => 'Tones|Ringtones|African|Afrobeats',
4552            8396 => 'Tones|Ringtones|African|Benga',
4553            8397 => 'Tones|Ringtones|African|Bongo-Flava',
4554            8398 => 'Tones|Ringtones|African|Coupe-Decale',
4555            8399 => 'Tones|Ringtones|African|Gqom',
4556            8400 => 'Tones|Ringtones|African|Highlife',
4557            8401 => 'Tones|Ringtones|African|Kuduro',
4558            8402 => 'Tones|Ringtones|African|Kizomba',
4559            8403 => 'Tones|Ringtones|African|Kwaito',
4560            8404 => 'Tones|Ringtones|African|Mbalax',
4561            8405 => 'Tones|Ringtones|African|Ndombolo',
4562            8406 => 'Tones|Ringtones|African|Shangaan Electro',
4563            8407 => 'Tones|Ringtones|African|Soukous',
4564            8408 => 'Tones|Ringtones|African|Taarab',
4565            8409 => 'Tones|Ringtones|African|Zouglou',
4566            8410 => 'Tones|Ringtones|Turkish|Ozgun',
4567            8411 => 'Tones|Ringtones|Turkish|Fantezi',
4568            8412 => 'Tones|Ringtones|Turkish|Religious',
4569            8413 => 'Tones|Ringtones|Pop|Turkish Pop',
4570            8414 => 'Tones|Ringtones|Rock|Turkish Rock',
4571            8415 => 'Tones|Ringtones|Alternative|Turkish Alternative',
4572            8416 => 'Tones|Ringtones|Hip-Hop/Rap|Turkish Hip-Hop/Rap',
4573            8417 => 'Tones|Ringtones|African|Maskandi',
4574            8418 => 'Tones|Ringtones|Russian|Russian Romance',
4575            8419 => 'Tones|Ringtones|Russian|Russian Bard',
4576            8420 => 'Tones|Ringtones|Russian|Russian Pop',
4577            8421 => 'Tones|Ringtones|Russian|Russian Rock',
4578            8422 => 'Tones|Ringtones|Russian|Russian Hip-Hop',
4579            8423 => 'Tones|Ringtones|Arabic|Levant',
4580            8424 => 'Tones|Ringtones|Arabic|Levant|Dabke',
4581            8425 => 'Tones|Ringtones|Arabic|Maghreb Rai',
4582            8426 => 'Tones|Ringtones|Arabic|Khaleeji|Khaleeji Jalsat',
4583            8427 => 'Tones|Ringtones|Arabic|Khaleeji|Khaleeji Shailat',
4584            8428 => 'Tones|Ringtones|Tarab',
4585            8429 => 'Tones|Ringtones|Tarab|Iraqi Tarab',
4586            8430 => 'Tones|Ringtones|Tarab|Egyptian Tarab',
4587            8431 => 'Tones|Ringtones|Tarab|Khaleeji Tarab',
4588            8432 => 'Tones|Ringtones|Pop|Levant Pop',
4589            8433 => 'Tones|Ringtones|Pop|Iraqi Pop',
4590            8434 => 'Tones|Ringtones|Pop|Egyptian Pop',
4591            8435 => 'Tones|Ringtones|Pop|Maghreb Pop',
4592            8436 => 'Tones|Ringtones|Pop|Khaleeji Pop',
4593            8437 => 'Tones|Ringtones|Hip-Hop/Rap|Levant Hip-Hop',
4594            8438 => 'Tones|Ringtones|Hip-Hop/Rap|Egyptian Hip-Hop',
4595            8439 => 'Tones|Ringtones|Hip-Hop/Rap|Maghreb Hip-Hop',
4596            8440 => 'Tones|Ringtones|Hip-Hop/Rap|Khaleeji Hip-Hop',
4597            8441 => 'Tones|Ringtones|Alternative|Indie Levant',
4598            8442 => 'Tones|Ringtones|Alternative|Indie Egyptian',
4599            8443 => 'Tones|Ringtones|Alternative|Indie Maghreb',
4600            8444 => 'Tones|Ringtones|Electronic|Levant Electronic',
4601            8445 => "Tones|Ringtones|Electronic|Electro-Cha'abi",
4602            8446 => 'Tones|Ringtones|Electronic|Maghreb Electronic',
4603            8447 => 'Tones|Ringtones|Folk|Iraqi Folk',
4604            8448 => 'Tones|Ringtones|Folk|Khaleeji Folk',
4605            8449 => 'Tones|Ringtones|Dance|Maghreb Dance',
4606            9002 => 'Books|Nonfiction',
4607            9003 => 'Books|Romance',
4608            9004 => 'Books|Travel & Adventure',
4609            9007 => 'Books|Arts & Entertainment',
4610            9008 => 'Books|Biographies & Memoirs',
4611            9009 => 'Books|Business & Personal Finance',
4612            9010 => 'Books|Children & Teens',
4613            9012 => 'Books|Humor',
4614            9015 => 'Books|History',
4615            9018 => 'Books|Religion & Spirituality',
4616            9019 => 'Books|Science & Nature',
4617            9020 => 'Books|Sci-Fi & Fantasy',
4618            9024 => 'Books|Lifestyle & Home',
4619            9025 => 'Books|Self-Development',
4620            9026 => 'Books|Comics & Graphic Novels',
4621            9027 => 'Books|Computers & Internet',
4622            9028 => 'Books|Cookbooks, Food & Wine',
4623            9029 => 'Books|Professional & Technical',
4624            9030 => 'Books|Parenting',
4625            9031 => 'Books|Fiction & Literature',
4626            9032 => 'Books|Mysteries & Thrillers',
4627            9033 => 'Books|Reference',
4628            9034 => 'Books|Politics & Current Events',
4629            9035 => 'Books|Sports & Outdoors',
4630            10001 => 'Books|Lifestyle & Home|Antiques & Collectibles',
4631            10002 => 'Books|Arts & Entertainment|Art & Architecture',
4632            10003 => 'Books|Religion & Spirituality|Bibles',
4633            10004 => 'Books|Self-Development|Spirituality',
4634            10005 => 'Books|Business & Personal Finance|Industries & Professions',
4635            10006 => 'Books|Business & Personal Finance|Marketing & Sales',
4636            10007 => 'Books|Business & Personal Finance|Small Business & Entrepreneurship',
4637            10008 => 'Books|Business & Personal Finance|Personal Finance',
4638            10009 => 'Books|Business & Personal Finance|Reference',
4639            10010 => 'Books|Business & Personal Finance|Careers',
4640            10011 => 'Books|Business & Personal Finance|Economics',
4641            10012 => 'Books|Business & Personal Finance|Investing',
4642            10013 => 'Books|Business & Personal Finance|Finance',
4643            10014 => 'Books|Business & Personal Finance|Management & Leadership',
4644            10015 => 'Books|Comics & Graphic Novels|Graphic Novels',
4645            10016 => 'Books|Comics & Graphic Novels|Manga',
4646            10017 => 'Books|Computers & Internet|Computers',
4647            10018 => 'Books|Computers & Internet|Databases',
4648            10019 => 'Books|Computers & Internet|Digital Media',
4649            10020 => 'Books|Computers & Internet|Internet',
4650            10021 => 'Books|Computers & Internet|Network',
4651            10022 => 'Books|Computers & Internet|Operating Systems',
4652            10023 => 'Books|Computers & Internet|Programming',
4653            10024 => 'Books|Computers & Internet|Software',
4654            10025 => 'Books|Computers & Internet|System Administration',
4655            10026 => 'Books|Cookbooks, Food & Wine|Beverages',
4656            10027 => 'Books|Cookbooks, Food & Wine|Courses & Dishes',
4657            10028 => 'Books|Cookbooks, Food & Wine|Special Diet',
4658            10029 => 'Books|Cookbooks, Food & Wine|Special Occasions',
4659            10030 => 'Books|Cookbooks, Food & Wine|Methods',
4660            10031 => 'Books|Cookbooks, Food & Wine|Reference',
4661            10032 => 'Books|Cookbooks, Food & Wine|Regional & Ethnic',
4662            10033 => 'Books|Cookbooks, Food & Wine|Specific Ingredients',
4663            10034 => 'Books|Lifestyle & Home|Crafts & Hobbies',
4664            10035 => 'Books|Professional & Technical|Design',
4665            10036 => 'Books|Arts & Entertainment|Theater',
4666            10037 => 'Books|Professional & Technical|Education',
4667            10038 => 'Books|Nonfiction|Family & Relationships',
4668            10039 => 'Books|Fiction & Literature|Action & Adventure',
4669            10040 => 'Books|Fiction & Literature|African American',
4670            10041 => 'Books|Fiction & Literature|Religious',
4671            10042 => 'Books|Fiction & Literature|Classics',
4672            10043 => 'Books|Fiction & Literature|Erotica',
4673            10044 => 'Books|Sci-Fi & Fantasy|Fantasy',
4674            10045 => 'Books|Fiction & Literature|Gay',
4675            10046 => 'Books|Fiction & Literature|Ghost',
4676            10047 => 'Books|Fiction & Literature|Historical',
4677            10048 => 'Books|Fiction & Literature|Horror',
4678            10049 => 'Books|Fiction & Literature|Literary',
4679            10050 => 'Books|Mysteries & Thrillers|Hard-Boiled',
4680            10051 => 'Books|Mysteries & Thrillers|Historical',
4681            10052 => 'Books|Mysteries & Thrillers|Police Procedural',
4682            10053 => 'Books|Mysteries & Thrillers|Short Stories',
4683            10054 => 'Books|Mysteries & Thrillers|British Detectives',
4684            10055 => 'Books|Mysteries & Thrillers|Women Sleuths',
4685            10056 => 'Books|Romance|Erotic Romance',
4686            10057 => 'Books|Romance|Contemporary',
4687            10058 => 'Books|Romance|Paranormal',
4688            10059 => 'Books|Romance|Historical',
4689            10060 => 'Books|Romance|Short Stories',
4690            10061 => 'Books|Romance|Suspense',
4691            10062 => 'Books|Romance|Western',
4692            10063 => 'Books|Sci-Fi & Fantasy|Science Fiction',
4693            10064 => 'Books|Sci-Fi & Fantasy|Science Fiction & Literature',
4694            10065 => 'Books|Fiction & Literature|Short Stories',
4695            10066 => 'Books|Reference|Foreign Languages',
4696            10067 => 'Books|Arts & Entertainment|Games',
4697            10068 => 'Books|Lifestyle & Home|Gardening',
4698            10069 => 'Books|Self-Development|Health & Fitness',
4699            10070 => 'Books|History|Africa',
4700            10071 => 'Books|History|Americas',
4701            10072 => 'Books|History|Ancient',
4702            10073 => 'Books|History|Asia',
4703            10074 => 'Books|History|Australia & Oceania',
4704            10075 => 'Books|History|Europe',
4705            10076 => 'Books|History|Latin America',
4706            10077 => 'Books|History|Middle East',
4707            10078 => 'Books|History|Military',
4708            10079 => 'Books|History|United States',
4709            10080 => 'Books|History|World',
4710            10081 => "Books|Children & Teens|Children's Fiction",
4711            10082 => "Books|Children & Teens|Children's Nonfiction",
4712            10083 => 'Books|Professional & Technical|Law',
4713            10084 => 'Books|Fiction & Literature|Literary Criticism',
4714            10085 => 'Books|Science & Nature|Mathematics',
4715            10086 => 'Books|Professional & Technical|Medical',
4716            10087 => 'Books|Arts & Entertainment|Music',
4717            10088 => 'Books|Science & Nature|Nature',
4718            10089 => 'Books|Arts & Entertainment|Performing Arts',
4719            10090 => 'Books|Lifestyle & Home|Pets',
4720            10091 => 'Books|Nonfiction|Philosophy',
4721            10092 => 'Books|Arts & Entertainment|Photography',
4722            10093 => 'Books|Fiction & Literature|Poetry',
4723            10094 => 'Books|Self-Development|Psychology',
4724            10095 => 'Books|Reference|Almanacs & Yearbooks',
4725            10096 => 'Books|Reference|Atlases & Maps',
4726            10097 => 'Books|Reference|Catalogs & Directories',
4727            10098 => 'Books|Reference|Consumer Guides',
4728            10099 => 'Books|Reference|Dictionaries & Thesauruses',
4729            10100 => 'Books|Reference|Encyclopedias',
4730            10101 => 'Books|Reference|Etiquette',
4731            10102 => 'Books|Reference|Quotations',
4732            10103 => 'Books|Reference|Words & Language',
4733            10104 => 'Books|Reference|Writing',
4734            10105 => 'Books|Religion & Spirituality|Bible Studies',
4735            10106 => 'Books|Religion & Spirituality|Buddhism',
4736            10107 => 'Books|Religion & Spirituality|Christianity',
4737            10108 => 'Books|Religion & Spirituality|Hinduism',
4738            10109 => 'Books|Religion & Spirituality|Islam',
4739            10110 => 'Books|Religion & Spirituality|Judaism',
4740            10111 => 'Books|Science & Nature|Astronomy',
4741            10112 => 'Books|Science & Nature|Chemistry',
4742            10113 => 'Books|Science & Nature|Earth Sciences',
4743            10114 => 'Books|Science & Nature|Essays',
4744            10115 => 'Books|Science & Nature|History',
4745            10116 => 'Books|Science & Nature|Life Sciences',
4746            10117 => 'Books|Science & Nature|Physics',
4747            10118 => 'Books|Science & Nature|Reference',
4748            10119 => 'Books|Self-Development|Self-Improvement',
4749            10120 => 'Books|Nonfiction|Social Science',
4750            10121 => 'Books|Sports & Outdoors|Baseball',
4751            10122 => 'Books|Sports & Outdoors|Basketball',
4752            10123 => 'Books|Sports & Outdoors|Coaching',
4753            10124 => 'Books|Sports & Outdoors|Extreme Sports',
4754            10125 => 'Books|Sports & Outdoors|Football',
4755            10126 => 'Books|Sports & Outdoors|Golf',
4756            10127 => 'Books|Sports & Outdoors|Hockey',
4757            10128 => 'Books|Sports & Outdoors|Mountaineering',
4758            10129 => 'Books|Sports & Outdoors|Outdoors',
4759            10130 => 'Books|Sports & Outdoors|Racket Sports',
4760            10131 => 'Books|Sports & Outdoors|Reference',
4761            10132 => 'Books|Sports & Outdoors|Soccer',
4762            10133 => 'Books|Sports & Outdoors|Training',
4763            10134 => 'Books|Sports & Outdoors|Water Sports',
4764            10135 => 'Books|Sports & Outdoors|Winter Sports',
4765            10136 => 'Books|Reference|Study Aids',
4766            10137 => 'Books|Professional & Technical|Engineering',
4767            10138 => 'Books|Nonfiction|Transportation',
4768            10139 => 'Books|Travel & Adventure|Africa',
4769            10140 => 'Books|Travel & Adventure|Asia',
4770            10141 => 'Books|Travel & Adventure|Specialty Travel',
4771            10142 => 'Books|Travel & Adventure|Canada',
4772            10143 => 'Books|Travel & Adventure|Caribbean',
4773            10144 => 'Books|Travel & Adventure|Latin America',
4774            10145 => 'Books|Travel & Adventure|Essays & Memoirs',
4775            10146 => 'Books|Travel & Adventure|Europe',
4776            10147 => 'Books|Travel & Adventure|Middle East',
4777            10148 => 'Books|Travel & Adventure|United States',
4778            10149 => 'Books|Nonfiction|True Crime',
4779            11001 => 'Books|Sci-Fi & Fantasy|Fantasy|Contemporary',
4780            11002 => 'Books|Sci-Fi & Fantasy|Fantasy|Epic',
4781            11003 => 'Books|Sci-Fi & Fantasy|Fantasy|Historical',
4782            11004 => 'Books|Sci-Fi & Fantasy|Fantasy|Paranormal',
4783            11005 => 'Books|Sci-Fi & Fantasy|Fantasy|Short Stories',
4784            11006 => 'Books|Sci-Fi & Fantasy|Science Fiction & Literature|Adventure',
4785            11007 => 'Books|Sci-Fi & Fantasy|Science Fiction & Literature|High Tech',
4786            11008 => 'Books|Sci-Fi & Fantasy|Science Fiction & Literature|Short Stories',
4787            11009 => 'Books|Professional & Technical|Education|Language Arts & Disciplines',
4788            11010 => 'Books|Communications & Media',
4789            11011 => 'Books|Communications & Media|Broadcasting',
4790            11012 => 'Books|Communications & Media|Digital Media',
4791            11013 => 'Books|Communications & Media|Journalism',
4792            11014 => 'Books|Communications & Media|Photojournalism',
4793            11015 => 'Books|Communications & Media|Print',
4794            11016 => 'Books|Communications & Media|Speech',
4795            11017 => 'Books|Communications & Media|Writing',
4796            11018 => 'Books|Arts & Entertainment|Art & Architecture|Urban Planning',
4797            11019 => 'Books|Arts & Entertainment|Dance',
4798            11020 => 'Books|Arts & Entertainment|Fashion',
4799            11021 => 'Books|Arts & Entertainment|Film',
4800            11022 => 'Books|Arts & Entertainment|Interior Design',
4801            11023 => 'Books|Arts & Entertainment|Media Arts',
4802            11024 => 'Books|Arts & Entertainment|Radio',
4803            11025 => 'Books|Arts & Entertainment|TV',
4804            11026 => 'Books|Arts & Entertainment|Visual Arts',
4805            11027 => 'Books|Biographies & Memoirs|Arts & Entertainment',
4806            11028 => 'Books|Biographies & Memoirs|Business',
4807            11029 => 'Books|Biographies & Memoirs|Culinary',
4808            11030 => 'Books|Biographies & Memoirs|Gay & Lesbian',
4809            11031 => 'Books|Biographies & Memoirs|Historical',
4810            11032 => 'Books|Biographies & Memoirs|Literary',
4811            11033 => 'Books|Biographies & Memoirs|Media & Journalism',
4812            11034 => 'Books|Biographies & Memoirs|Military',
4813            11035 => 'Books|Biographies & Memoirs|Politics',
4814            11036 => 'Books|Biographies & Memoirs|Religious',
4815            11037 => 'Books|Biographies & Memoirs|Science & Technology',
4816            11038 => 'Books|Biographies & Memoirs|Sports',
4817            11039 => 'Books|Biographies & Memoirs|Women',
4818            11040 => 'Books|Romance|New Adult',
4819            11042 => 'Books|Romance|Romantic Comedy',
4820            11043 => 'Books|Romance|Gay & Lesbian',
4821            11044 => 'Books|Fiction & Literature|Essays',
4822            11045 => 'Books|Fiction & Literature|Anthologies',
4823            11046 => 'Books|Fiction & Literature|Comparative Literature',
4824            11047 => 'Books|Fiction & Literature|Drama',
4825            11049 => 'Books|Fiction & Literature|Fairy Tales, Myths & Fables',
4826            11050 => 'Books|Fiction & Literature|Family',
4827            11051 => 'Books|Comics & Graphic Novels|Manga|School Drama',
4828            11052 => 'Books|Comics & Graphic Novels|Manga|Human Drama',
4829            11053 => 'Books|Comics & Graphic Novels|Manga|Family Drama',
4830            11054 => 'Books|Sports & Outdoors|Boxing',
4831            11055 => 'Books|Sports & Outdoors|Cricket',
4832            11056 => 'Books|Sports & Outdoors|Cycling',
4833            11057 => 'Books|Sports & Outdoors|Equestrian',
4834            11058 => 'Books|Sports & Outdoors|Martial Arts & Self Defense',
4835            11059 => 'Books|Sports & Outdoors|Motor Sports',
4836            11060 => 'Books|Sports & Outdoors|Rugby',
4837            11061 => 'Books|Sports & Outdoors|Running',
4838            11062 => 'Books|Self-Development|Diet & Nutrition',
4839            11063 => 'Books|Science & Nature|Agriculture',
4840            11064 => 'Books|Science & Nature|Atmosphere',
4841            11065 => 'Books|Science & Nature|Biology',
4842            11066 => 'Books|Science & Nature|Ecology',
4843            11067 => 'Books|Science & Nature|Environment',
4844            11068 => 'Books|Science & Nature|Geography',
4845            11069 => 'Books|Science & Nature|Geology',
4846            11070 => 'Books|Nonfiction|Social Science|Anthropology',
4847            11071 => 'Books|Nonfiction|Social Science|Archaeology',
4848            11072 => 'Books|Nonfiction|Social Science|Civics',
4849            11073 => 'Books|Nonfiction|Social Science|Government',
4850            11074 => 'Books|Nonfiction|Social Science|Social Studies',
4851            11075 => 'Books|Nonfiction|Social Science|Social Welfare',
4852            11076 => 'Books|Nonfiction|Social Science|Society',
4853            11077 => 'Books|Nonfiction|Philosophy|Aesthetics',
4854            11078 => 'Books|Nonfiction|Philosophy|Epistemology',
4855            11079 => 'Books|Nonfiction|Philosophy|Ethics',
4856            11080 => 'Books|Nonfiction|Philosophy|Language',
4857            11081 => 'Books|Nonfiction|Philosophy|Logic',
4858            11082 => 'Books|Nonfiction|Philosophy|Metaphysics',
4859            11083 => 'Books|Nonfiction|Philosophy|Political',
4860            11084 => 'Books|Nonfiction|Philosophy|Religion',
4861            11085 => 'Books|Reference|Manuals',
4862            11086 => 'Books|Kids',
4863            11087 => 'Books|Kids|Animals',
4864            11088 => 'Books|Kids|Basic Concepts',
4865            11089 => 'Books|Kids|Basic Concepts|Alphabet',
4866            11090 => 'Books|Kids|Basic Concepts|Body',
4867            11091 => 'Books|Kids|Basic Concepts|Colors',
4868            11092 => 'Books|Kids|Basic Concepts|Counting & Numbers',
4869            11093 => 'Books|Kids|Basic Concepts|Date & Time',
4870            11094 => 'Books|Kids|Basic Concepts|General',
4871            11095 => 'Books|Kids|Basic Concepts|Money',
4872            11096 => 'Books|Kids|Basic Concepts|Opposites',
4873            11097 => 'Books|Kids|Basic Concepts|Seasons',
4874            11098 => 'Books|Kids|Basic Concepts|Senses & Sensation',
4875            11099 => 'Books|Kids|Basic Concepts|Size & Shape',
4876            11100 => 'Books|Kids|Basic Concepts|Sounds',
4877            11101 => 'Books|Kids|Basic Concepts|Words',
4878            11102 => 'Books|Kids|Biography',
4879            11103 => 'Books|Kids|Careers & Occupations',
4880            11104 => 'Books|Kids|Computers & Technology',
4881            11105 => 'Books|Kids|Cooking & Food',
4882            11106 => 'Books|Kids|Arts & Entertainment',
4883            11107 => 'Books|Kids|Arts & Entertainment|Art',
4884            11108 => 'Books|Kids|Arts & Entertainment|Crafts',
4885            11109 => 'Books|Kids|Arts & Entertainment|Music',
4886            11110 => 'Books|Kids|Arts & Entertainment|Performing Arts',
4887            11111 => 'Books|Kids|Family',
4888            11112 => 'Books|Kids|Fiction',
4889            11113 => 'Books|Kids|Fiction|Action & Adventure',
4890            11114 => 'Books|Kids|Fiction|Animals',
4891            11115 => 'Books|Kids|Fiction|Classics',
4892            11116 => 'Books|Kids|Fiction|Comics & Graphic Novels',
4893            11117 => 'Books|Kids|Fiction|Culture, Places & People',
4894            11118 => 'Books|Kids|Fiction|Family & Relationships',
4895            11119 => 'Books|Kids|Fiction|Fantasy',
4896            11120 => 'Books|Kids|Fiction|Fairy Tales, Myths & Fables',
4897            11121 => 'Books|Kids|Fiction|Favorite Characters',
4898            11122 => 'Books|Kids|Fiction|Historical',
4899            11123 => 'Books|Kids|Fiction|Holidays & Celebrations',
4900            11124 => 'Books|Kids|Fiction|Monsters & Ghosts',
4901            11125 => 'Books|Kids|Fiction|Mysteries',
4902            11126 => 'Books|Kids|Fiction|Nature',
4903            11127 => 'Books|Kids|Fiction|Religion',
4904            11128 => 'Books|Kids|Fiction|Sci-Fi',
4905            11129 => 'Books|Kids|Fiction|Social Issues',
4906            11130 => 'Books|Kids|Fiction|Sports & Recreation',
4907            11131 => 'Books|Kids|Fiction|Transportation',
4908            11132 => 'Books|Kids|Games & Activities',
4909            11133 => 'Books|Kids|General Nonfiction',
4910            11134 => 'Books|Kids|Health',
4911            11135 => 'Books|Kids|History',
4912            11136 => 'Books|Kids|Holidays & Celebrations',
4913            11137 => 'Books|Kids|Holidays & Celebrations|Birthdays',
4914            11138 => 'Books|Kids|Holidays & Celebrations|Christmas & Advent',
4915            11139 => 'Books|Kids|Holidays & Celebrations|Easter & Lent',
4916            11140 => 'Books|Kids|Holidays & Celebrations|General',
4917            11141 => 'Books|Kids|Holidays & Celebrations|Halloween',
4918            11142 => 'Books|Kids|Holidays & Celebrations|Hanukkah',
4919            11143 => 'Books|Kids|Holidays & Celebrations|Other',
4920            11144 => 'Books|Kids|Holidays & Celebrations|Passover',
4921            11145 => 'Books|Kids|Holidays & Celebrations|Patriotic Holidays',
4922            11146 => 'Books|Kids|Holidays & Celebrations|Ramadan',
4923            11147 => 'Books|Kids|Holidays & Celebrations|Thanksgiving',
4924            11148 => "Books|Kids|Holidays & Celebrations|Valentine's Day",
4925            11149 => 'Books|Kids|Humor',
4926            11150 => 'Books|Kids|Humor|Jokes & Riddles',
4927            11151 => 'Books|Kids|Poetry',
4928            11152 => 'Books|Kids|Learning to Read',
4929            11153 => 'Books|Kids|Learning to Read|Chapter Books',
4930            11154 => 'Books|Kids|Learning to Read|Early Readers',
4931            11155 => 'Books|Kids|Learning to Read|Intermediate Readers',
4932            11156 => 'Books|Kids|Nursery Rhymes',
4933            11157 => 'Books|Kids|Government',
4934            11158 => 'Books|Kids|Reference',
4935            11159 => 'Books|Kids|Religion',
4936            11160 => 'Books|Kids|Science & Nature',
4937            11161 => 'Books|Kids|Social Issues',
4938            11162 => 'Books|Kids|Social Studies',
4939            11163 => 'Books|Kids|Sports & Recreation',
4940            11164 => 'Books|Kids|Transportation',
4941            11165 => 'Books|Young Adult',
4942            11166 => 'Books|Young Adult|Animals',
4943            11167 => 'Books|Young Adult|Biography',
4944            11168 => 'Books|Young Adult|Careers & Occupations',
4945            11169 => 'Books|Young Adult|Computers & Technology',
4946            11170 => 'Books|Young Adult|Cooking & Food',
4947            11171 => 'Books|Young Adult|Arts & Entertainment',
4948            11172 => 'Books|Young Adult|Arts & Entertainment|Art',
4949            11173 => 'Books|Young Adult|Arts & Entertainment|Crafts',
4950            11174 => 'Books|Young Adult|Arts & Entertainment|Music',
4951            11175 => 'Books|Young Adult|Arts & Entertainment|Performing Arts',
4952            11176 => 'Books|Young Adult|Family',
4953            11177 => 'Books|Young Adult|Fiction',
4954            11178 => 'Books|Young Adult|Fiction|Action & Adventure',
4955            11179 => 'Books|Young Adult|Fiction|Animals',
4956            11180 => 'Books|Young Adult|Fiction|Classics',
4957            11181 => 'Books|Young Adult|Fiction|Comics & Graphic Novels',
4958            11182 => 'Books|Young Adult|Fiction|Culture, Places & People',
4959            11183 => 'Books|Young Adult|Fiction|Dystopian',
4960            11184 => 'Books|Young Adult|Fiction|Family & Relationships',
4961            11185 => 'Books|Young Adult|Fiction|Fantasy',
4962            11186 => 'Books|Young Adult|Fiction|Fairy Tales, Myths & Fables',
4963            11187 => 'Books|Young Adult|Fiction|Favorite Characters',
4964            11188 => 'Books|Young Adult|Fiction|Historical',
4965            11189 => 'Books|Young Adult|Fiction|Holidays & Celebrations',
4966            11190 => 'Books|Young Adult|Fiction|Horror, Monsters & Ghosts',
4967            11191 => 'Books|Young Adult|Fiction|Crime & Mystery',
4968            11192 => 'Books|Young Adult|Fiction|Nature',
4969            11193 => 'Books|Young Adult|Fiction|Religion',
4970            11194 => 'Books|Young Adult|Fiction|Romance',
4971            11195 => 'Books|Young Adult|Fiction|Sci-Fi',
4972            11196 => 'Books|Young Adult|Fiction|Coming of Age',
4973            11197 => 'Books|Young Adult|Fiction|Sports & Recreation',
4974            11198 => 'Books|Young Adult|Fiction|Transportation',
4975            11199 => 'Books|Young Adult|Games & Activities',
4976            11200 => 'Books|Young Adult|General Nonfiction',
4977            11201 => 'Books|Young Adult|Health',
4978            11202 => 'Books|Young Adult|History',
4979            11203 => 'Books|Young Adult|Holidays & Celebrations',
4980            11204 => 'Books|Young Adult|Holidays & Celebrations|Birthdays',
4981            11205 => 'Books|Young Adult|Holidays & Celebrations|Christmas & Advent',
4982            11206 => 'Books|Young Adult|Holidays & Celebrations|Easter & Lent',
4983            11207 => 'Books|Young Adult|Holidays & Celebrations|General',
4984            11208 => 'Books|Young Adult|Holidays & Celebrations|Halloween',
4985            11209 => 'Books|Young Adult|Holidays & Celebrations|Hanukkah',
4986            11210 => 'Books|Young Adult|Holidays & Celebrations|Other',
4987            11211 => 'Books|Young Adult|Holidays & Celebrations|Passover',
4988            11212 => 'Books|Young Adult|Holidays & Celebrations|Patriotic Holidays',
4989            11213 => 'Books|Young Adult|Holidays & Celebrations|Ramadan',
4990            11214 => 'Books|Young Adult|Holidays & Celebrations|Thanksgiving',
4991            11215 => "Books|Young Adult|Holidays & Celebrations|Valentine's Day",
4992            11216 => 'Books|Young Adult|Humor',
4993            11217 => 'Books|Young Adult|Humor|Jokes & Riddles',
4994            11218 => 'Books|Young Adult|Poetry',
4995            11219 => 'Books|Young Adult|Politics & Government',
4996            11220 => 'Books|Young Adult|Reference',
4997            11221 => 'Books|Young Adult|Religion',
4998            11222 => 'Books|Young Adult|Science & Nature',
4999            11223 => 'Books|Young Adult|Coming of Age',
5000            11224 => 'Books|Young Adult|Social Studies',
5001            11225 => 'Books|Young Adult|Sports & Recreation',
5002            11226 => 'Books|Young Adult|Transportation',
5003            11227 => 'Books|Communications & Media',
5004            11228 => 'Books|Military & Warfare',
5005            11229 => 'Books|Romance|Inspirational',
5006            11231 => 'Books|Romance|Holiday',
5007            11232 => 'Books|Romance|Wholesome',
5008            11233 => 'Books|Romance|Military',
5009            11234 => 'Books|Arts & Entertainment|Art History',
5010            11236 => 'Books|Arts & Entertainment|Design',
5011            11243 => 'Books|Business & Personal Finance|Accounting',
5012            11244 => 'Books|Business & Personal Finance|Hospitality',
5013            11245 => 'Books|Business & Personal Finance|Real Estate',
5014            11246 => 'Books|Humor|Jokes & Riddles',
5015            11247 => 'Books|Religion & Spirituality|Comparative Religion',
5016            11255 => 'Books|Cookbooks, Food & Wine|Culinary Arts',
5017            11259 => 'Books|Mysteries & Thrillers|Cozy',
5018            11260 => 'Books|Politics & Current Events|Current Events',
5019            11261 => 'Books|Politics & Current Events|Foreign Policy & International Relations',
5020            11262 => 'Books|Politics & Current Events|Local Government',
5021            11263 => 'Books|Politics & Current Events|National Government',
5022            11264 => 'Books|Politics & Current Events|Political Science',
5023            11265 => 'Books|Politics & Current Events|Public Administration',
5024            11266 => 'Books|Politics & Current Events|World Affairs',
5025            11273 => 'Books|Nonfiction|Family & Relationships|Family & Childcare',
5026            11274 => 'Books|Nonfiction|Family & Relationships|Love & Romance',
5027            11275 => 'Books|Sci-Fi & Fantasy|Fantasy|Urban',
5028            11276 => 'Books|Reference|Foreign Languages|Arabic',
5029            11277 => 'Books|Reference|Foreign Languages|Bilingual Editions',
5030            11278 => 'Books|Reference|Foreign Languages|African Languages',
5031            11279 => 'Books|Reference|Foreign Languages|Ancient Languages',
5032            11280 => 'Books|Reference|Foreign Languages|Chinese',
5033            11281 => 'Books|Reference|Foreign Languages|English',
5034            11282 => 'Books|Reference|Foreign Languages|French',
5035            11283 => 'Books|Reference|Foreign Languages|German',
5036            11284 => 'Books|Reference|Foreign Languages|Hebrew',
5037            11285 => 'Books|Reference|Foreign Languages|Hindi',
5038            11286 => 'Books|Reference|Foreign Languages|Italian',
5039            11287 => 'Books|Reference|Foreign Languages|Japanese',
5040            11288 => 'Books|Reference|Foreign Languages|Korean',
5041            11289 => 'Books|Reference|Foreign Languages|Linguistics',
5042            11290 => 'Books|Reference|Foreign Languages|Other Languages',
5043            11291 => 'Books|Reference|Foreign Languages|Portuguese',
5044            11292 => 'Books|Reference|Foreign Languages|Russian',
5045            11293 => 'Books|Reference|Foreign Languages|Spanish',
5046            11294 => 'Books|Reference|Foreign Languages|Speech Pathology',
5047            11295 => 'Books|Science & Nature|Mathematics|Advanced Mathematics',
5048            11296 => 'Books|Science & Nature|Mathematics|Algebra',
5049            11297 => 'Books|Science & Nature|Mathematics|Arithmetic',
5050            11298 => 'Books|Science & Nature|Mathematics|Calculus',
5051            11299 => 'Books|Science & Nature|Mathematics|Geometry',
5052            11300 => 'Books|Science & Nature|Mathematics|Statistics',
5053            11301 => 'Books|Professional & Technical|Medical|Veterinary',
5054            11302 => 'Books|Professional & Technical|Medical|Neuroscience',
5055            11303 => 'Books|Professional & Technical|Medical|Immunology',
5056            11304 => 'Books|Professional & Technical|Medical|Nursing',
5057            11305 => 'Books|Professional & Technical|Medical|Pharmacology & Toxicology',
5058            11306 => 'Books|Professional & Technical|Medical|Anatomy & Physiology',
5059            11307 => 'Books|Professional & Technical|Medical|Dentistry',
5060            11308 => 'Books|Professional & Technical|Medical|Emergency Medicine',
5061            11309 => 'Books|Professional & Technical|Medical|Genetics',
5062            11310 => 'Books|Professional & Technical|Medical|Psychiatry',
5063            11311 => 'Books|Professional & Technical|Medical|Radiology',
5064            11312 => 'Books|Professional & Technical|Medical|Alternative Medicine',
5065            11317 => 'Books|Nonfiction|Philosophy|Political Philosophy',
5066            11319 => 'Books|Nonfiction|Philosophy|Philosophy of Language',
5067            11320 => 'Books|Nonfiction|Philosophy|Philosophy of Religion',
5068            11327 => 'Books|Nonfiction|Social Science|Sociology',
5069            11329 => 'Books|Professional & Technical|Engineering|Aeronautics',
5070            11330 => 'Books|Professional & Technical|Engineering|Chemical & Petroleum Engineering',
5071            11331 => 'Books|Professional & Technical|Engineering|Civil Engineering',
5072            11332 => 'Books|Professional & Technical|Engineering|Computer Science',
5073            11333 => 'Books|Professional & Technical|Engineering|Electrical Engineering',
5074            11334 => 'Books|Professional & Technical|Engineering|Environmental Engineering',
5075            11335 => 'Books|Professional & Technical|Engineering|Mechanical Engineering',
5076            11336 => 'Books|Professional & Technical|Engineering|Power Resources',
5077            11337 => 'Books|Comics & Graphic Novels|Manga|Boys',
5078            11338 => 'Books|Comics & Graphic Novels|Manga|Men',
5079            11339 => 'Books|Comics & Graphic Novels|Manga|Girls',
5080            11340 => 'Books|Comics & Graphic Novels|Manga|Women',
5081            11341 => 'Books|Comics & Graphic Novels|Manga|Other',
5082            11342 => 'Books|Comics & Graphic Novels|Manga|Yaoi',
5083            11343 => 'Books|Comics & Graphic Novels|Manga|Comic Essays',
5084            12001 => 'Mac App Store|Business',
5085            12002 => 'Mac App Store|Developer Tools',
5086            12003 => 'Mac App Store|Education',
5087            12004 => 'Mac App Store|Entertainment',
5088            12005 => 'Mac App Store|Finance',
5089            12006 => 'Mac App Store|Games',
5090            12007 => 'Mac App Store|Health & Fitness',
5091            12008 => 'Mac App Store|Lifestyle',
5092            12010 => 'Mac App Store|Medical',
5093            12011 => 'Mac App Store|Music',
5094            12012 => 'Mac App Store|News',
5095            12013 => 'Mac App Store|Photography',
5096            12014 => 'Mac App Store|Productivity',
5097            12015 => 'Mac App Store|Reference',
5098            12016 => 'Mac App Store|Social Networking',
5099            12017 => 'Mac App Store|Sports',
5100            12018 => 'Mac App Store|Travel',
5101            12019 => 'Mac App Store|Utilities',
5102            12020 => 'Mac App Store|Video',
5103            12021 => 'Mac App Store|Weather',
5104            12022 => 'Mac App Store|Graphics & Design',
5105            12201 => 'Mac App Store|Games|Action',
5106            12202 => 'Mac App Store|Games|Adventure',
5107            12203 => 'Mac App Store|Games|Casual',
5108            12204 => 'Mac App Store|Games|Board',
5109            12205 => 'Mac App Store|Games|Card',
5110            12206 => 'Mac App Store|Games|Casino',
5111            12207 => 'Mac App Store|Games|Dice',
5112            12208 => 'Mac App Store|Games|Educational',
5113            12209 => 'Mac App Store|Games|Family',
5114            12210 => 'Mac App Store|Games|Kids',
5115            12211 => 'Mac App Store|Games|Music',
5116            12212 => 'Mac App Store|Games|Puzzle',
5117            12213 => 'Mac App Store|Games|Racing',
5118            12214 => 'Mac App Store|Games|Role Playing',
5119            12215 => 'Mac App Store|Games|Simulation',
5120            12216 => 'Mac App Store|Games|Sports',
5121            12217 => 'Mac App Store|Games|Strategy',
5122            12218 => 'Mac App Store|Games|Trivia',
5123            12219 => 'Mac App Store|Games|Word',
5124            13001 => 'App Store|Magazines & Newspapers|News & Politics',
5125            13002 => 'App Store|Magazines & Newspapers|Fashion & Style',
5126            13003 => 'App Store|Magazines & Newspapers|Home & Garden',
5127            13004 => 'App Store|Magazines & Newspapers|Outdoors & Nature',
5128            13005 => 'App Store|Magazines & Newspapers|Sports & Leisure',
5129            13006 => 'App Store|Magazines & Newspapers|Automotive',
5130            13007 => 'App Store|Magazines & Newspapers|Arts & Photography',
5131            13008 => 'App Store|Magazines & Newspapers|Brides & Weddings',
5132            13009 => 'App Store|Magazines & Newspapers|Business & Investing',
5133            13010 => "App Store|Magazines & Newspapers|Children's Magazines",
5134            13011 => 'App Store|Magazines & Newspapers|Computers & Internet',
5135            13012 => 'App Store|Magazines & Newspapers|Cooking, Food & Drink',
5136            13013 => 'App Store|Magazines & Newspapers|Crafts & Hobbies',
5137            13014 => 'App Store|Magazines & Newspapers|Electronics & Audio',
5138            13015 => 'App Store|Magazines & Newspapers|Entertainment',
5139            13017 => 'App Store|Magazines & Newspapers|Health, Mind & Body',
5140            13018 => 'App Store|Magazines & Newspapers|History',
5141            13019 => 'App Store|Magazines & Newspapers|Literary Magazines & Journals',
5142            13020 => "App Store|Magazines & Newspapers|Men's Interest",
5143            13021 => 'App Store|Magazines & Newspapers|Movies & Music',
5144            13023 => 'App Store|Magazines & Newspapers|Parenting & Family',
5145            13024 => 'App Store|Magazines & Newspapers|Pets',
5146            13025 => 'App Store|Magazines & Newspapers|Professional & Trade',
5147            13026 => 'App Store|Magazines & Newspapers|Regional News',
5148            13027 => 'App Store|Magazines & Newspapers|Science',
5149            13028 => 'App Store|Magazines & Newspapers|Teens',
5150            13029 => 'App Store|Magazines & Newspapers|Travel & Regional',
5151            13030 => "App Store|Magazines & Newspapers|Women's Interest",
5152            15000 => 'Textbooks|Arts & Entertainment',
5153            15001 => 'Textbooks|Arts & Entertainment|Art & Architecture',
5154            15002 => 'Textbooks|Arts & Entertainment|Art & Architecture|Urban Planning',
5155            15003 => 'Textbooks|Arts & Entertainment|Art History',
5156            15004 => 'Textbooks|Arts & Entertainment|Dance',
5157            15005 => 'Textbooks|Arts & Entertainment|Design',
5158            15006 => 'Textbooks|Arts & Entertainment|Fashion',
5159            15007 => 'Textbooks|Arts & Entertainment|Film',
5160            15008 => 'Textbooks|Arts & Entertainment|Games',
5161            15009 => 'Textbooks|Arts & Entertainment|Interior Design',
5162            15010 => 'Textbooks|Arts & Entertainment|Media Arts',
5163            15011 => 'Textbooks|Arts & Entertainment|Music',
5164            15012 => 'Textbooks|Arts & Entertainment|Performing Arts',
5165            15013 => 'Textbooks|Arts & Entertainment|Photography',
5166            15014 => 'Textbooks|Arts & Entertainment|Theater',
5167            15015 => 'Textbooks|Arts & Entertainment|TV',
5168            15016 => 'Textbooks|Arts & Entertainment|Visual Arts',
5169            15017 => 'Textbooks|Biographies & Memoirs',
5170            15018 => 'Textbooks|Business & Personal Finance',
5171            15019 => 'Textbooks|Business & Personal Finance|Accounting',
5172            15020 => 'Textbooks|Business & Personal Finance|Careers',
5173            15021 => 'Textbooks|Business & Personal Finance|Economics',
5174            15022 => 'Textbooks|Business & Personal Finance|Finance',
5175            15023 => 'Textbooks|Business & Personal Finance|Hospitality',
5176            15024 => 'Textbooks|Business & Personal Finance|Industries & Professions',
5177            15025 => 'Textbooks|Business & Personal Finance|Investing',
5178            15026 => 'Textbooks|Business & Personal Finance|Management & Leadership',
5179            15027 => 'Textbooks|Business & Personal Finance|Marketing & Sales',
5180            15028 => 'Textbooks|Business & Personal Finance|Personal Finance',
5181            15029 => 'Textbooks|Business & Personal Finance|Real Estate',
5182            15030 => 'Textbooks|Business & Personal Finance|Reference',
5183            15031 => 'Textbooks|Business & Personal Finance|Small Business & Entrepreneurship',
5184            15032 => 'Textbooks|Children & Teens',
5185            15033 => 'Textbooks|Children & Teens|Fiction',
5186            15034 => 'Textbooks|Children & Teens|Nonfiction',
5187            15035 => 'Textbooks|Comics & Graphic Novels',
5188            15036 => 'Textbooks|Comics & Graphic Novels|Graphic Novels',
5189            15037 => 'Textbooks|Comics & Graphic Novels|Manga',
5190            15038 => 'Textbooks|Communications & Media',
5191            15039 => 'Textbooks|Communications & Media|Broadcasting',
5192            15040 => 'Textbooks|Communications & Media|Digital Media',
5193            15041 => 'Textbooks|Communications & Media|Journalism',
5194            15042 => 'Textbooks|Communications & Media|Photojournalism',
5195            15043 => 'Textbooks|Communications & Media|Print',
5196            15044 => 'Textbooks|Communications & Media|Speech',
5197            15045 => 'Textbooks|Communications & Media|Writing',
5198            15046 => 'Textbooks|Computers & Internet',
5199            15047 => 'Textbooks|Computers & Internet|Computers',
5200            15048 => 'Textbooks|Computers & Internet|Databases',
5201            15049 => 'Textbooks|Computers & Internet|Digital Media',
5202            15050 => 'Textbooks|Computers & Internet|Internet',
5203            15051 => 'Textbooks|Computers & Internet|Network',
5204            15052 => 'Textbooks|Computers & Internet|Operating Systems',
5205            15053 => 'Textbooks|Computers & Internet|Programming',
5206            15054 => 'Textbooks|Computers & Internet|Software',
5207            15055 => 'Textbooks|Computers & Internet|System Administration',
5208            15056 => 'Textbooks|Cookbooks, Food & Wine',
5209            15057 => 'Textbooks|Cookbooks, Food & Wine|Beverages',
5210            15058 => 'Textbooks|Cookbooks, Food & Wine|Courses & Dishes',
5211            15059 => 'Textbooks|Cookbooks, Food & Wine|Culinary Arts',
5212            15060 => 'Textbooks|Cookbooks, Food & Wine|Methods',
5213            15061 => 'Textbooks|Cookbooks, Food & Wine|Reference',
5214            15062 => 'Textbooks|Cookbooks, Food & Wine|Regional & Ethnic',
5215            15063 => 'Textbooks|Cookbooks, Food & Wine|Special Diet',
5216            15064 => 'Textbooks|Cookbooks, Food & Wine|Special Occasions',
5217            15065 => 'Textbooks|Cookbooks, Food & Wine|Specific Ingredients',
5218            15066 => 'Textbooks|Engineering',
5219            15067 => 'Textbooks|Engineering|Aeronautics',
5220            15068 => 'Textbooks|Engineering|Chemical & Petroleum Engineering',
5221            15069 => 'Textbooks|Engineering|Civil Engineering',
5222            15070 => 'Textbooks|Engineering|Computer Science',
5223            15071 => 'Textbooks|Engineering|Electrical Engineering',
5224            15072 => 'Textbooks|Engineering|Environmental Engineering',
5225            15073 => 'Textbooks|Engineering|Mechanical Engineering',
5226            15074 => 'Textbooks|Engineering|Power Resources',
5227            15075 => 'Textbooks|Fiction & Literature',
5228            15076 => 'Textbooks|Fiction & Literature|Latino',
5229            15077 => 'Textbooks|Fiction & Literature|Action & Adventure',
5230            15078 => 'Textbooks|Fiction & Literature|African American',
5231            15079 => 'Textbooks|Fiction & Literature|Anthologies',
5232            15080 => 'Textbooks|Fiction & Literature|Classics',
5233            15081 => 'Textbooks|Fiction & Literature|Comparative Literature',
5234            15082 => 'Textbooks|Fiction & Literature|Erotica',
5235            15083 => 'Textbooks|Fiction & Literature|Gay',
5236            15084 => 'Textbooks|Fiction & Literature|Ghost',
5237            15085 => 'Textbooks|Fiction & Literature|Historical',
5238            15086 => 'Textbooks|Fiction & Literature|Horror',
5239            15087 => 'Textbooks|Fiction & Literature|Literary',
5240            15088 => 'Textbooks|Fiction & Literature|Literary Criticism',
5241            15089 => 'Textbooks|Fiction & Literature|Poetry',
5242            15090 => 'Textbooks|Fiction & Literature|Religious',
5243            15091 => 'Textbooks|Fiction & Literature|Short Stories',
5244            15092 => 'Textbooks|Health, Mind & Body',
5245            15093 => 'Textbooks|Health, Mind & Body|Fitness',
5246            15094 => 'Textbooks|Health, Mind & Body|Self-Improvement',
5247            15095 => 'Textbooks|History',
5248            15096 => 'Textbooks|History|Africa',
5249            15097 => 'Textbooks|History|Americas',
5250            15098 => 'Textbooks|History|Americas|Canada',
5251            15099 => 'Textbooks|History|Americas|Latin America',
5252            15100 => 'Textbooks|History|Americas|United States',
5253            15101 => 'Textbooks|History|Ancient',
5254            15102 => 'Textbooks|History|Asia',
5255            15103 => 'Textbooks|History|Australia & Oceania',
5256            15104 => 'Textbooks|History|Europe',
5257            15105 => 'Textbooks|History|Middle East',
5258            15106 => 'Textbooks|History|Military',
5259            15107 => 'Textbooks|History|World',
5260            15108 => 'Textbooks|Humor',
5261            15109 => 'Textbooks|Language Studies',
5262            15110 => 'Textbooks|Language Studies|African Languages',
5263            15111 => 'Textbooks|Language Studies|Ancient Languages',
5264            15112 => 'Textbooks|Language Studies|Arabic',
5265            15113 => 'Textbooks|Language Studies|Bilingual Editions',
5266            15114 => 'Textbooks|Language Studies|Chinese',
5267            15115 => 'Textbooks|Language Studies|English',
5268            15116 => 'Textbooks|Language Studies|French',
5269            15117 => 'Textbooks|Language Studies|German',
5270            15118 => 'Textbooks|Language Studies|Hebrew',
5271            15119 => 'Textbooks|Language Studies|Hindi',
5272            15120 => 'Textbooks|Language Studies|Indigenous Languages',
5273            15121 => 'Textbooks|Language Studies|Italian',
5274            15122 => 'Textbooks|Language Studies|Japanese',
5275            15123 => 'Textbooks|Language Studies|Korean',
5276            15124 => 'Textbooks|Language Studies|Linguistics',
5277            15125 => 'Textbooks|Language Studies|Other Language',
5278            15126 => 'Textbooks|Language Studies|Portuguese',
5279            15127 => 'Textbooks|Language Studies|Russian',
5280            15128 => 'Textbooks|Language Studies|Spanish',
5281            15129 => 'Textbooks|Language Studies|Speech Pathology',
5282            15130 => 'Textbooks|Lifestyle & Home',
5283            15131 => 'Textbooks|Lifestyle & Home|Antiques & Collectibles',
5284            15132 => 'Textbooks|Lifestyle & Home|Crafts & Hobbies',
5285            15133 => 'Textbooks|Lifestyle & Home|Gardening',
5286            15134 => 'Textbooks|Lifestyle & Home|Pets',
5287            15135 => 'Textbooks|Mathematics',
5288            15136 => 'Textbooks|Mathematics|Advanced Mathematics',
5289            15137 => 'Textbooks|Mathematics|Algebra',
5290            15138 => 'Textbooks|Mathematics|Arithmetic',
5291            15139 => 'Textbooks|Mathematics|Calculus',
5292            15140 => 'Textbooks|Mathematics|Geometry',
5293            15141 => 'Textbooks|Mathematics|Statistics',
5294            15142 => 'Textbooks|Medicine',
5295            15143 => 'Textbooks|Medicine|Anatomy & Physiology',
5296            15144 => 'Textbooks|Medicine|Dentistry',
5297            15145 => 'Textbooks|Medicine|Emergency Medicine',
5298            15146 => 'Textbooks|Medicine|Genetics',
5299            15147 => 'Textbooks|Medicine|Immunology',
5300            15148 => 'Textbooks|Medicine|Neuroscience',
5301            15149 => 'Textbooks|Medicine|Nursing',
5302            15150 => 'Textbooks|Medicine|Pharmacology & Toxicology',
5303            15151 => 'Textbooks|Medicine|Psychiatry',
5304            15152 => 'Textbooks|Medicine|Psychology',
5305            15153 => 'Textbooks|Medicine|Radiology',
5306            15154 => 'Textbooks|Medicine|Veterinary',
5307            15155 => 'Textbooks|Mysteries & Thrillers',
5308            15156 => 'Textbooks|Mysteries & Thrillers|British Detectives',
5309            15157 => 'Textbooks|Mysteries & Thrillers|Hard-Boiled',
5310            15158 => 'Textbooks|Mysteries & Thrillers|Historical',
5311            15159 => 'Textbooks|Mysteries & Thrillers|Police Procedural',
5312            15160 => 'Textbooks|Mysteries & Thrillers|Short Stories',
5313            15161 => 'Textbooks|Mysteries & Thrillers|Women Sleuths',
5314            15162 => 'Textbooks|Nonfiction',
5315            15163 => 'Textbooks|Nonfiction|Family & Relationships',
5316            15164 => 'Textbooks|Nonfiction|Transportation',
5317            15165 => 'Textbooks|Nonfiction|True Crime',
5318            15166 => 'Textbooks|Parenting',
5319            15167 => 'Textbooks|Philosophy',
5320            15168 => 'Textbooks|Philosophy|Aesthetics',
5321            15169 => 'Textbooks|Philosophy|Epistemology',
5322            15170 => 'Textbooks|Philosophy|Ethics',
5323            15171 => 'Textbooks|Philosophy|Philosophy of Language',
5324            15172 => 'Textbooks|Philosophy|Logic',
5325            15173 => 'Textbooks|Philosophy|Metaphysics',
5326            15174 => 'Textbooks|Philosophy|Political Philosophy',
5327            15175 => 'Textbooks|Philosophy|Philosophy of Religion',
5328            15176 => 'Textbooks|Politics & Current Events',
5329            15177 => 'Textbooks|Politics & Current Events|Current Events',
5330            15178 => 'Textbooks|Politics & Current Events|Foreign Policy & International Relations',
5331            15179 => 'Textbooks|Politics & Current Events|Local Governments',
5332            15180 => 'Textbooks|Politics & Current Events|National Governments',
5333            15181 => 'Textbooks|Politics & Current Events|Political Science',
5334            15182 => 'Textbooks|Politics & Current Events|Public Administration',
5335            15183 => 'Textbooks|Politics & Current Events|World Affairs',
5336            15184 => 'Textbooks|Professional & Technical',
5337            15185 => 'Textbooks|Professional & Technical|Design',
5338            15186 => 'Textbooks|Professional & Technical|Language Arts & Disciplines',
5339            15187 => 'Textbooks|Professional & Technical|Engineering',
5340            15188 => 'Textbooks|Professional & Technical|Law',
5341            15189 => 'Textbooks|Professional & Technical|Medical',
5342            15190 => 'Textbooks|Reference',
5343            15191 => 'Textbooks|Reference|Almanacs & Yearbooks',
5344            15192 => 'Textbooks|Reference|Atlases & Maps',
5345            15193 => 'Textbooks|Reference|Catalogs & Directories',
5346            15194 => 'Textbooks|Reference|Consumer Guides',
5347            15195 => 'Textbooks|Reference|Dictionaries & Thesauruses',
5348            15196 => 'Textbooks|Reference|Encyclopedias',
5349            15197 => 'Textbooks|Reference|Etiquette',
5350            15198 => 'Textbooks|Reference|Quotations',
5351            15199 => 'Textbooks|Reference|Study Aids',
5352            15200 => 'Textbooks|Reference|Words & Language',
5353            15201 => 'Textbooks|Reference|Writing',
5354            15202 => 'Textbooks|Religion & Spirituality',
5355            15203 => 'Textbooks|Religion & Spirituality|Bible Studies',
5356            15204 => 'Textbooks|Religion & Spirituality|Bibles',
5357            15205 => 'Textbooks|Religion & Spirituality|Buddhism',
5358            15206 => 'Textbooks|Religion & Spirituality|Christianity',
5359            15207 => 'Textbooks|Religion & Spirituality|Comparative Religion',
5360            15208 => 'Textbooks|Religion & Spirituality|Hinduism',
5361            15209 => 'Textbooks|Religion & Spirituality|Islam',
5362            15210 => 'Textbooks|Religion & Spirituality|Judaism',
5363            15211 => 'Textbooks|Religion & Spirituality|Spirituality',
5364            15212 => 'Textbooks|Romance',
5365            15213 => 'Textbooks|Romance|Contemporary',
5366            15214 => 'Textbooks|Romance|Erotic Romance',
5367            15215 => 'Textbooks|Romance|Paranormal',
5368            15216 => 'Textbooks|Romance|Historical',
5369            15217 => 'Textbooks|Romance|Short Stories',
5370            15218 => 'Textbooks|Romance|Suspense',
5371            15219 => 'Textbooks|Romance|Western',
5372            15220 => 'Textbooks|Sci-Fi & Fantasy',
5373            15221 => 'Textbooks|Sci-Fi & Fantasy|Fantasy',
5374            15222 => 'Textbooks|Sci-Fi & Fantasy|Fantasy|Contemporary',
5375            15223 => 'Textbooks|Sci-Fi & Fantasy|Fantasy|Epic',
5376            15224 => 'Textbooks|Sci-Fi & Fantasy|Fantasy|Historical',
5377            15225 => 'Textbooks|Sci-Fi & Fantasy|Fantasy|Paranormal',
5378            15226 => 'Textbooks|Sci-Fi & Fantasy|Fantasy|Short Stories',
5379            15227 => 'Textbooks|Sci-Fi & Fantasy|Science Fiction',
5380            15228 => 'Textbooks|Sci-Fi & Fantasy|Science Fiction & Literature',
5381            15229 => 'Textbooks|Sci-Fi & Fantasy|Science Fiction & Literature|Adventure',
5382            15230 => 'Textbooks|Sci-Fi & Fantasy|Science Fiction & Literature|High Tech',
5383            15231 => 'Textbooks|Sci-Fi & Fantasy|Science Fiction & Literature|Short Stories',
5384            15232 => 'Textbooks|Science & Nature',
5385            15233 => 'Textbooks|Science & Nature|Agriculture',
5386            15234 => 'Textbooks|Science & Nature|Astronomy',
5387            15235 => 'Textbooks|Science & Nature|Atmosphere',
5388            15236 => 'Textbooks|Science & Nature|Biology',
5389            15237 => 'Textbooks|Science & Nature|Chemistry',
5390            15238 => 'Textbooks|Science & Nature|Earth Sciences',
5391            15239 => 'Textbooks|Science & Nature|Ecology',
5392            15240 => 'Textbooks|Science & Nature|Environment',
5393            15241 => 'Textbooks|Science & Nature|Essays',
5394            15242 => 'Textbooks|Science & Nature|Geography',
5395            15243 => 'Textbooks|Science & Nature|Geology',
5396            15244 => 'Textbooks|Science & Nature|History',
5397            15245 => 'Textbooks|Science & Nature|Life Sciences',
5398            15246 => 'Textbooks|Science & Nature|Nature',
5399            15247 => 'Textbooks|Science & Nature|Physics',
5400            15248 => 'Textbooks|Science & Nature|Reference',
5401            15249 => 'Textbooks|Social Science',
5402            15250 => 'Textbooks|Social Science|Anthropology',
5403            15251 => 'Textbooks|Social Science|Archaeology',
5404            15252 => 'Textbooks|Social Science|Civics',
5405            15253 => 'Textbooks|Social Science|Government',
5406            15254 => 'Textbooks|Social Science|Social Studies',
5407            15255 => 'Textbooks|Social Science|Social Welfare',
5408            15256 => 'Textbooks|Social Science|Society',
5409            15257 => 'Textbooks|Social Science|Society|African Studies',
5410            15258 => 'Textbooks|Social Science|Society|American Studies',
5411            15259 => 'Textbooks|Social Science|Society|Asia Pacific Studies',
5412            15260 => 'Textbooks|Social Science|Society|Cross-Cultural Studies',
5413            15261 => 'Textbooks|Social Science|Society|European Studies',
5414            15262 => 'Textbooks|Social Science|Society|Immigration & Emigration',
5415            15263 => 'Textbooks|Social Science|Society|Indigenous Studies',
5416            15264 => 'Textbooks|Social Science|Society|Latin & Caribbean Studies',
5417            15265 => 'Textbooks|Social Science|Society|Middle Eastern Studies',
5418            15266 => 'Textbooks|Social Science|Society|Race & Ethnicity Studies',
5419            15267 => 'Textbooks|Social Science|Society|Sexuality Studies',
5420            15268 => "Textbooks|Social Science|Society|Women's Studies",
5421            15269 => 'Textbooks|Social Science|Sociology',
5422            15270 => 'Textbooks|Sports & Outdoors',
5423            15271 => 'Textbooks|Sports & Outdoors|Baseball',
5424            15272 => 'Textbooks|Sports & Outdoors|Basketball',
5425            15273 => 'Textbooks|Sports & Outdoors|Coaching',
5426            15274 => 'Textbooks|Sports & Outdoors|Equestrian',
5427            15275 => 'Textbooks|Sports & Outdoors|Extreme Sports',
5428            15276 => 'Textbooks|Sports & Outdoors|Football',
5429            15277 => 'Textbooks|Sports & Outdoors|Golf',
5430            15278 => 'Textbooks|Sports & Outdoors|Hockey',
5431            15279 => 'Textbooks|Sports & Outdoors|Motor Sports',
5432            15280 => 'Textbooks|Sports & Outdoors|Mountaineering',
5433            15281 => 'Textbooks|Sports & Outdoors|Outdoors',
5434            15282 => 'Textbooks|Sports & Outdoors|Racket Sports',
5435            15283 => 'Textbooks|Sports & Outdoors|Reference',
5436            15284 => 'Textbooks|Sports & Outdoors|Soccer',
5437            15285 => 'Textbooks|Sports & Outdoors|Training',
5438            15286 => 'Textbooks|Sports & Outdoors|Water Sports',
5439            15287 => 'Textbooks|Sports & Outdoors|Winter Sports',
5440            15288 => 'Textbooks|Teaching & Learning',
5441            15289 => 'Textbooks|Teaching & Learning|Adult Education',
5442            15290 => 'Textbooks|Teaching & Learning|Curriculum & Teaching',
5443            15291 => 'Textbooks|Teaching & Learning|Educational Leadership',
5444            15292 => 'Textbooks|Teaching & Learning|Educational Technology',
5445            15293 => 'Textbooks|Teaching & Learning|Family & Childcare',
5446            15294 => 'Textbooks|Teaching & Learning|Information & Library Science',
5447            15295 => 'Textbooks|Teaching & Learning|Learning Resources',
5448            15296 => 'Textbooks|Teaching & Learning|Psychology & Research',
5449            15297 => 'Textbooks|Teaching & Learning|Special Education',
5450            15298 => 'Textbooks|Travel & Adventure',
5451            15299 => 'Textbooks|Travel & Adventure|Africa',
5452            15300 => 'Textbooks|Travel & Adventure|Americas',
5453            15301 => 'Textbooks|Travel & Adventure|Americas|Canada',
5454            15302 => 'Textbooks|Travel & Adventure|Americas|Latin America',
5455            15303 => 'Textbooks|Travel & Adventure|Americas|United States',
5456            15304 => 'Textbooks|Travel & Adventure|Asia',
5457            15305 => 'Textbooks|Travel & Adventure|Caribbean',
5458            15306 => 'Textbooks|Travel & Adventure|Essays & Memoirs',
5459            15307 => 'Textbooks|Travel & Adventure|Europe',
5460            15308 => 'Textbooks|Travel & Adventure|Middle East',
5461            15309 => 'Textbooks|Travel & Adventure|Oceania',
5462            15310 => 'Textbooks|Travel & Adventure|Specialty Travel',
5463            15311 => 'Textbooks|Comics & Graphic Novels|Comics',
5464            15312 => 'Textbooks|Reference|Manuals',
5465            16001 => 'App Store|Stickers|Emoji & Expressions',
5466            16003 => 'App Store|Stickers|Animals & Nature',
5467            16005 => 'App Store|Stickers|Art',
5468            16006 => 'App Store|Stickers|Celebrations',
5469            16007 => 'App Store|Stickers|Celebrities',
5470            16008 => 'App Store|Stickers|Comics & Cartoons',
5471            16009 => 'App Store|Stickers|Eating & Drinking',
5472            16010 => 'App Store|Stickers|Gaming',
5473            16014 => 'App Store|Stickers|Movies & TV',
5474            16015 => 'App Store|Stickers|Music',
5475            16017 => 'App Store|Stickers|People',
5476            16019 => 'App Store|Stickers|Places & Objects',
5477            16021 => 'App Store|Stickers|Sports & Activities',
5478            16025 => 'App Store|Stickers|Kids & Family',
5479            16026 => 'App Store|Stickers|Fashion',
5480            100000 => 'Music|Christian & Gospel',
5481            100001 => 'Music|Classical|Art Song',
5482            100002 => 'Music|Classical|Brass & Woodwinds',
5483            100003 => 'Music|Classical|Solo Instrumental',
5484            100004 => 'Music|Classical|Contemporary Era',
5485            100005 => 'Music|Classical|Oratorio',
5486            100006 => 'Music|Classical|Cantata',
5487            100007 => 'Music|Classical|Electronic',
5488            100008 => 'Music|Classical|Sacred',
5489            100009 => 'Music|Classical|Guitar',
5490            100010 => 'Music|Classical|Piano',
5491            100011 => 'Music|Classical|Violin',
5492            100012 => 'Music|Classical|Cello',
5493            100013 => 'Music|Classical|Percussion',
5494            100014 => 'Music|Electronic|Dubstep',
5495            100015 => 'Music|Electronic|Bass',
5496            100016 => 'Music|Hip-Hop/Rap|UK Hip-Hop',
5497            100017 => 'Music|Reggae|Lovers Rock',
5498            100018 => 'Music|Alternative|EMO',
5499            100019 => 'Music|Alternative|Pop Punk',
5500            100020 => 'Music|Alternative|Indie Pop',
5501            100021 => 'Music|New Age|Yoga',
5502            100022 => 'Music|Pop|Tribute',
5503            100023 => 'Music|Pop|Shows',
5504            100024 => 'Music|Cuban',
5505            100025 => 'Music|Cuban|Mambo',
5506            100026 => 'Music|Cuban|Chachacha',
5507            100027 => 'Music|Cuban|Guajira',
5508            100028 => 'Music|Cuban|Son',
5509            100029 => 'Music|Cuban|Bolero',
5510            100030 => 'Music|Cuban|Guaracha',
5511            100031 => 'Music|Cuban|Timba',
5512            100032 => 'Music|Soundtrack|Video Game',
5513            100033 => 'Music|Indian|Regional Indian|Punjabi|Punjabi Pop',
5514            100034 => 'Music|Indian|Regional Indian|Bengali|Rabindra Sangeet',
5515            100035 => 'Music|Indian|Regional Indian|Malayalam',
5516            100036 => 'Music|Indian|Regional Indian|Kannada',
5517            100037 => 'Music|Indian|Regional Indian|Marathi',
5518            100038 => 'Music|Indian|Regional Indian|Gujarati',
5519            100039 => 'Music|Indian|Regional Indian|Assamese',
5520            100040 => 'Music|Indian|Regional Indian|Bhojpuri',
5521            100041 => 'Music|Indian|Regional Indian|Haryanvi',
5522            100042 => 'Music|Indian|Regional Indian|Odia',
5523            100043 => 'Music|Indian|Regional Indian|Rajasthani',
5524            100044 => 'Music|Indian|Regional Indian|Urdu',
5525            100045 => 'Music|Indian|Regional Indian|Punjabi',
5526            100046 => 'Music|Indian|Regional Indian|Bengali',
5527            100047 => 'Music|Indian|Indian Classical|Carnatic Classical',
5528            100048 => 'Music|Indian|Indian Classical|Hindustani Classical',
5529            100049 => 'Music|African|Afro House',
5530            100050 => 'Music|African|Afro Soul',
5531            100051 => 'Music|African|Afrobeats',
5532            100052 => 'Music|African|Benga',
5533            100053 => 'Music|African|Bongo-Flava',
5534            100054 => 'Music|African|Coupe-Decale',
5535            100055 => 'Music|African|Gqom',
5536            100056 => 'Music|African|Highlife',
5537            100057 => 'Music|African|Kuduro',
5538            100058 => 'Music|African|Kizomba',
5539            100059 => 'Music|African|Kwaito',
5540            100060 => 'Music|African|Mbalax',
5541            100061 => 'Music|African|Ndombolo',
5542            100062 => 'Music|African|Shangaan Electro',
5543            100063 => 'Music|African|Soukous',
5544            100064 => 'Music|African|Taarab',
5545            100065 => 'Music|African|Zouglou',
5546            100066 => 'Music|Turkish|Ozgun',
5547            100067 => 'Music|Turkish|Fantezi',
5548            100068 => 'Music|Turkish|Religious',
5549            100069 => 'Music|Pop|Turkish Pop',
5550            100070 => 'Music|Rock|Turkish Rock',
5551            100071 => 'Music|Alternative|Turkish Alternative',
5552            100072 => 'Music|Hip-Hop/Rap|Turkish Hip-Hop/Rap',
5553            100073 => 'Music|African|Maskandi',
5554            100074 => 'Music|Russian|Russian Romance',
5555            100075 => 'Music|Russian|Russian Bard',
5556            100076 => 'Music|Russian|Russian Pop',
5557            100077 => 'Music|Russian|Russian Rock',
5558            100078 => 'Music|Russian|Russian Hip-Hop',
5559            100079 => 'Music|Arabic|Levant',
5560            100080 => 'Music|Arabic|Levant|Dabke',
5561            100081 => 'Music|Arabic|Maghreb Rai',
5562            100082 => 'Music|Arabic|Khaleeji|Khaleeji Jalsat',
5563            100083 => 'Music|Arabic|Khaleeji|Khaleeji Shailat',
5564            100084 => 'Music|Tarab',
5565            100085 => 'Music|Tarab|Iraqi Tarab',
5566            100086 => 'Music|Tarab|Egyptian Tarab',
5567            100087 => 'Music|Tarab|Khaleeji Tarab',
5568            100088 => 'Music|Pop|Levant Pop',
5569            100089 => 'Music|Pop|Iraqi Pop',
5570            100090 => 'Music|Pop|Egyptian Pop',
5571            100091 => 'Music|Pop|Maghreb Pop',
5572            100092 => 'Music|Pop|Khaleeji Pop',
5573            100093 => 'Music|Hip-Hop/Rap|Levant Hip-Hop',
5574            100094 => 'Music|Hip-Hop/Rap|Egyptian Hip-Hop',
5575            100095 => 'Music|Hip-Hop/Rap|Maghreb Hip-Hop',
5576            100096 => 'Music|Hip-Hop/Rap|Khaleeji Hip-Hop',
5577            100097 => 'Music|Alternative|Indie Levant',
5578            100098 => 'Music|Alternative|Indie Egyptian',
5579            100099 => 'Music|Alternative|Indie Maghreb',
5580            100100 => 'Music|Electronic|Levant Electronic',
5581            100101 => "Music|Electronic|Electro-Cha'abi",
5582            100102 => 'Music|Electronic|Maghreb Electronic',
5583            100103 => 'Music|Folk|Iraqi Folk',
5584            100104 => 'Music|Folk|Khaleeji Folk',
5585            100105 => 'Music|Dance|Maghreb Dance',
5586            40000000 => 'iTunes U',
5587            40000001 => 'iTunes U|Business & Economics',
5588            40000002 => 'iTunes U|Business & Economics|Economics',
5589            40000003 => 'iTunes U|Business & Economics|Finance',
5590            40000004 => 'iTunes U|Business & Economics|Hospitality',
5591            40000005 => 'iTunes U|Business & Economics|Management',
5592            40000006 => 'iTunes U|Business & Economics|Marketing',
5593            40000007 => 'iTunes U|Business & Economics|Personal Finance',
5594            40000008 => 'iTunes U|Business & Economics|Real Estate',
5595            40000009 => 'iTunes U|Engineering',
5596            40000010 => 'iTunes U|Engineering|Chemical & Petroleum Engineering',
5597            40000011 => 'iTunes U|Engineering|Civil Engineering',
5598            40000012 => 'iTunes U|Engineering|Computer Science',
5599            40000013 => 'iTunes U|Engineering|Electrical Engineering',
5600            40000014 => 'iTunes U|Engineering|Environmental Engineering',
5601            40000015 => 'iTunes U|Engineering|Mechanical Engineering',
5602            40000016 => 'iTunes U|Music, Art, & Design',
5603            40000017 => 'iTunes U|Music, Art, & Design|Architecture',
5604            40000019 => 'iTunes U|Music, Art, & Design|Art History',
5605            40000020 => 'iTunes U|Music, Art, & Design|Dance',
5606            40000021 => 'iTunes U|Music, Art, & Design|Film',
5607            40000022 => 'iTunes U|Music, Art, & Design|Design',
5608            40000023 => 'iTunes U|Music, Art, & Design|Interior Design',
5609            40000024 => 'iTunes U|Music, Art, & Design|Music',
5610            40000025 => 'iTunes U|Music, Art, & Design|Theater',
5611            40000026 => 'iTunes U|Health & Medicine',
5612            40000027 => 'iTunes U|Health & Medicine|Anatomy & Physiology',
5613            40000028 => 'iTunes U|Health & Medicine|Behavioral Science',
5614            40000029 => 'iTunes U|Health & Medicine|Dentistry',
5615            40000030 => 'iTunes U|Health & Medicine|Diet & Nutrition',
5616            40000031 => 'iTunes U|Health & Medicine|Emergency Medicine',
5617            40000032 => 'iTunes U|Health & Medicine|Genetics',
5618            40000033 => 'iTunes U|Health & Medicine|Gerontology',
5619            40000034 => 'iTunes U|Health & Medicine|Health & Exercise Science',
5620            40000035 => 'iTunes U|Health & Medicine|Immunology',
5621            40000036 => 'iTunes U|Health & Medicine|Neuroscience',
5622            40000037 => 'iTunes U|Health & Medicine|Pharmacology & Toxicology',
5623            40000038 => 'iTunes U|Health & Medicine|Psychiatry',
5624            40000039 => 'iTunes U|Health & Medicine|Global Health',
5625            40000040 => 'iTunes U|Health & Medicine|Radiology',
5626            40000041 => 'iTunes U|History',
5627            40000042 => 'iTunes U|History|Ancient History',
5628            40000043 => 'iTunes U|History|Medieval History',
5629            40000044 => 'iTunes U|History|Military History',
5630            40000045 => 'iTunes U|History|Modern History',
5631            40000046 => 'iTunes U|History|African History',
5632            40000047 => 'iTunes U|History|Asia-Pacific History',
5633            40000048 => 'iTunes U|History|European History',
5634            40000049 => 'iTunes U|History|Middle Eastern History',
5635            40000050 => 'iTunes U|History|North American History',
5636            40000051 => 'iTunes U|History|South American History',
5637            40000053 => 'iTunes U|Communications & Journalism',
5638            40000054 => 'iTunes U|Philosophy',
5639            40000055 => 'iTunes U|Religion & Spirituality',
5640            40000056 => 'iTunes U|Languages',
5641            40000057 => 'iTunes U|Languages|African Languages',
5642            40000058 => 'iTunes U|Languages|Ancient Languages',
5643            40000061 => 'iTunes U|Languages|English',
5644            40000063 => 'iTunes U|Languages|French',
5645            40000064 => 'iTunes U|Languages|German',
5646            40000065 => 'iTunes U|Languages|Italian',
5647            40000066 => 'iTunes U|Languages|Linguistics',
5648            40000068 => 'iTunes U|Languages|Spanish',
5649            40000069 => 'iTunes U|Languages|Speech Pathology',
5650            40000070 => 'iTunes U|Writing & Literature',
5651            40000071 => 'iTunes U|Writing & Literature|Anthologies',
5652            40000072 => 'iTunes U|Writing & Literature|Biography',
5653            40000073 => 'iTunes U|Writing & Literature|Classics',
5654            40000074 => 'iTunes U|Writing & Literature|Literary Criticism',
5655            40000075 => 'iTunes U|Writing & Literature|Fiction',
5656            40000076 => 'iTunes U|Writing & Literature|Poetry',
5657            40000077 => 'iTunes U|Mathematics',
5658            40000078 => 'iTunes U|Mathematics|Advanced Mathematics',
5659            40000079 => 'iTunes U|Mathematics|Algebra',
5660            40000080 => 'iTunes U|Mathematics|Arithmetic',
5661            40000081 => 'iTunes U|Mathematics|Calculus',
5662            40000082 => 'iTunes U|Mathematics|Geometry',
5663            40000083 => 'iTunes U|Mathematics|Statistics',
5664            40000084 => 'iTunes U|Science',
5665            40000085 => 'iTunes U|Science|Agricultural',
5666            40000086 => 'iTunes U|Science|Astronomy',
5667            40000087 => 'iTunes U|Science|Atmosphere',
5668            40000088 => 'iTunes U|Science|Biology',
5669            40000089 => 'iTunes U|Science|Chemistry',
5670            40000090 => 'iTunes U|Science|Ecology',
5671            40000091 => 'iTunes U|Science|Geography',
5672            40000092 => 'iTunes U|Science|Geology',
5673            40000093 => 'iTunes U|Science|Physics',
5674            40000094 => 'iTunes U|Social Science',
5675            40000095 => 'iTunes U|Law & Politics|Law',
5676            40000096 => 'iTunes U|Law & Politics|Political Science',
5677            40000097 => 'iTunes U|Law & Politics|Public Administration',
5678            40000098 => 'iTunes U|Social Science|Psychology',
5679            40000099 => 'iTunes U|Social Science|Social Welfare',
5680            40000100 => 'iTunes U|Social Science|Sociology',
5681            40000101 => 'iTunes U|Society',
5682            40000103 => 'iTunes U|Society|Asia Pacific Studies',
5683            40000104 => 'iTunes U|Society|European Studies',
5684            40000105 => 'iTunes U|Society|Indigenous Studies',
5685            40000106 => 'iTunes U|Society|Latin & Caribbean Studies',
5686            40000107 => 'iTunes U|Society|Middle Eastern Studies',
5687            40000108 => "iTunes U|Society|Women's Studies",
5688            40000109 => 'iTunes U|Teaching & Learning',
5689            40000110 => 'iTunes U|Teaching & Learning|Curriculum & Teaching',
5690            40000111 => 'iTunes U|Teaching & Learning|Educational Leadership',
5691            40000112 => 'iTunes U|Teaching & Learning|Family & Childcare',
5692            40000113 => 'iTunes U|Teaching & Learning|Learning Resources',
5693            40000114 => 'iTunes U|Teaching & Learning|Psychology & Research',
5694            40000115 => 'iTunes U|Teaching & Learning|Special Education',
5695            40000116 => 'iTunes U|Music, Art, & Design|Culinary Arts',
5696            40000117 => 'iTunes U|Music, Art, & Design|Fashion',
5697            40000118 => 'iTunes U|Music, Art, & Design|Media Arts',
5698            40000119 => 'iTunes U|Music, Art, & Design|Photography',
5699            40000120 => 'iTunes U|Music, Art, & Design|Visual Art',
5700            40000121 => 'iTunes U|Business & Economics|Entrepreneurship',
5701            40000122 => 'iTunes U|Communications & Journalism|Broadcasting',
5702            40000123 => 'iTunes U|Communications & Journalism|Digital Media',
5703            40000124 => 'iTunes U|Communications & Journalism|Journalism',
5704            40000125 => 'iTunes U|Communications & Journalism|Photojournalism',
5705            40000126 => 'iTunes U|Communications & Journalism|Print',
5706            40000127 => 'iTunes U|Communications & Journalism|Speech',
5707            40000128 => 'iTunes U|Communications & Journalism|Writing',
5708            40000129 => 'iTunes U|Health & Medicine|Nursing',
5709            40000130 => 'iTunes U|Languages|Arabic',
5710            40000131 => 'iTunes U|Languages|Chinese',
5711            40000132 => 'iTunes U|Languages|Hebrew',
5712            40000133 => 'iTunes U|Languages|Hindi',
5713            40000134 => 'iTunes U|Languages|Indigenous Languages',
5714            40000135 => 'iTunes U|Languages|Japanese',
5715            40000136 => 'iTunes U|Languages|Korean',
5716            40000137 => 'iTunes U|Languages|Other Languages',
5717            40000138 => 'iTunes U|Languages|Portuguese',
5718            40000139 => 'iTunes U|Languages|Russian',
5719            40000140 => 'iTunes U|Law & Politics',
5720            40000141 => 'iTunes U|Law & Politics|Foreign Policy & International Relations',
5721            40000142 => 'iTunes U|Law & Politics|Local Governments',
5722            40000143 => 'iTunes U|Law & Politics|National Governments',
5723            40000144 => 'iTunes U|Law & Politics|World Affairs',
5724            40000145 => 'iTunes U|Writing & Literature|Comparative Literature',
5725            40000146 => 'iTunes U|Philosophy|Aesthetics',
5726            40000147 => 'iTunes U|Philosophy|Epistemology',
5727            40000148 => 'iTunes U|Philosophy|Ethics',
5728            40000149 => 'iTunes U|Philosophy|Metaphysics',
5729            40000150 => 'iTunes U|Philosophy|Political Philosophy',
5730            40000151 => 'iTunes U|Philosophy|Logic',
5731            40000152 => 'iTunes U|Philosophy|Philosophy of Language',
5732            40000153 => 'iTunes U|Philosophy|Philosophy of Religion',
5733            40000154 => 'iTunes U|Social Science|Archaeology',
5734            40000155 => 'iTunes U|Social Science|Anthropology',
5735            40000156 => 'iTunes U|Religion & Spirituality|Buddhism',
5736            40000157 => 'iTunes U|Religion & Spirituality|Christianity',
5737            40000158 => 'iTunes U|Religion & Spirituality|Comparative Religion',
5738            40000159 => 'iTunes U|Religion & Spirituality|Hinduism',
5739            40000160 => 'iTunes U|Religion & Spirituality|Islam',
5740            40000161 => 'iTunes U|Religion & Spirituality|Judaism',
5741            40000162 => 'iTunes U|Religion & Spirituality|Other Religions',
5742            40000163 => 'iTunes U|Religion & Spirituality|Spirituality',
5743            40000164 => 'iTunes U|Science|Environment',
5744            40000165 => 'iTunes U|Society|African Studies',
5745            40000166 => 'iTunes U|Society|American Studies',
5746            40000167 => 'iTunes U|Society|Cross-cultural Studies',
5747            40000168 => 'iTunes U|Society|Immigration & Emigration',
5748            40000169 => 'iTunes U|Society|Race & Ethnicity Studies',
5749            40000170 => 'iTunes U|Society|Sexuality Studies',
5750            40000171 => 'iTunes U|Teaching & Learning|Educational Technology',
5751            40000172 => 'iTunes U|Teaching & Learning|Information/Library Science',
5752            40000173 => 'iTunes U|Languages|Dutch',
5753            40000174 => 'iTunes U|Languages|Luxembourgish',
5754            40000175 => 'iTunes U|Languages|Swedish',
5755            40000176 => 'iTunes U|Languages|Norwegian',
5756            40000177 => 'iTunes U|Languages|Finnish',
5757            40000178 => 'iTunes U|Languages|Danish',
5758            40000179 => 'iTunes U|Languages|Polish',
5759            40000180 => 'iTunes U|Languages|Turkish',
5760            40000181 => 'iTunes U|Languages|Flemish',
5761            50000024 => 'Audiobooks',
5762            50000040 => 'Audiobooks|Fiction',
5763            50000041 => 'Audiobooks|Arts & Entertainment',
5764            50000042 => 'Audiobooks|Biographies & Memoirs',
5765            50000043 => 'Audiobooks|Business & Personal Finance',
5766            50000044 => 'Audiobooks|Kids & Young Adults',
5767            50000045 => 'Audiobooks|Classics',
5768            50000046 => 'Audiobooks|Comedy',
5769            50000047 => 'Audiobooks|Drama & Poetry',
5770            50000048 => 'Audiobooks|Speakers & Storytellers',
5771            50000049 => 'Audiobooks|History',
5772            50000050 => 'Audiobooks|Languages',
5773            50000051 => 'Audiobooks|Mysteries & Thrillers',
5774            50000052 => 'Audiobooks|Nonfiction',
5775            50000053 => 'Audiobooks|Religion & Spirituality',
5776            50000054 => 'Audiobooks|Science & Nature',
5777            50000055 => 'Audiobooks|Sci Fi & Fantasy',
5778            50000056 => 'Audiobooks|Self-Development',
5779            50000057 => 'Audiobooks|Sports & Outdoors',
5780            50000058 => 'Audiobooks|Technology',
5781            50000059 => 'Audiobooks|Travel & Adventure',
5782            50000061 => 'Music|Spoken Word',
5783            50000063 => 'Music|Disney',
5784            50000064 => 'Music|French Pop',
5785            50000066 => 'Music|German Pop',
5786            50000068 => 'Music|German Folk',
5787            50000069 => 'Audiobooks|Romance',
5788            50000070 => 'Audiobooks|Audiobooks Latino',
5789            50000071 => 'Books|Comics & Graphic Novels|Manga|Action',
5790            50000072 => 'Books|Comics & Graphic Novels|Manga|Comedy',
5791            50000073 => 'Books|Comics & Graphic Novels|Manga|Erotica',
5792            50000074 => 'Books|Comics & Graphic Novels|Manga|Fantasy',
5793            50000075 => 'Books|Comics & Graphic Novels|Manga|Four Cell Manga',
5794            50000076 => 'Books|Comics & Graphic Novels|Manga|Gay & Lesbian',
5795            50000077 => 'Books|Comics & Graphic Novels|Manga|Hard-Boiled',
5796            50000078 => 'Books|Comics & Graphic Novels|Manga|Heroes',
5797            50000079 => 'Books|Comics & Graphic Novels|Manga|Historical Fiction',
5798            50000080 => 'Books|Comics & Graphic Novels|Manga|Mecha',
5799            50000081 => 'Books|Comics & Graphic Novels|Manga|Mystery',
5800            50000082 => 'Books|Comics & Graphic Novels|Manga|Nonfiction',
5801            50000083 => 'Books|Comics & Graphic Novels|Manga|Religious',
5802            50000084 => 'Books|Comics & Graphic Novels|Manga|Romance',
5803            50000085 => 'Books|Comics & Graphic Novels|Manga|Romantic Comedy',
5804            50000086 => 'Books|Comics & Graphic Novels|Manga|Science Fiction',
5805            50000087 => 'Books|Comics & Graphic Novels|Manga|Sports',
5806            50000088 => 'Books|Fiction & Literature|Light Novels',
5807            50000089 => 'Books|Comics & Graphic Novels|Manga|Horror',
5808            50000090 => 'Books|Comics & Graphic Novels|Comics',
5809            50000091 => 'Books|Romance|Multicultural',
5810            50000092 => 'Audiobooks|Erotica',
5811            50000093 => 'Audiobooks|Light Novels',
5812        },
5813    },
5814    grup => { Name => 'Grouping', Avoid => 1 }, #10
5815    hdvd => { #10
5816        Name => 'HDVideo',
5817        Format => 'int8u', #24
5818        Writable => 'int8s', #27
5819        PrintConv => { 0 => 'No', 1 => 'Yes' },
5820    },
5821    keyw => 'Keyword', #7
5822    ldes => 'LongDescription', #10
5823    pcst => { #7
5824        Name => 'Podcast',
5825        Format => 'int8u', #23
5826        Writable => 'int8s', #27
5827        PrintConv => { 0 => 'No', 1 => 'Yes' },
5828    },
5829    perf => 'Performer',
5830    plID => { #10 (or TV season)
5831        Name => 'PlayListID',
5832        Format => 'int8u',  # actually int64u, but split it up
5833        Writable => 'int32s', #27
5834    },
5835    purd => 'PurchaseDate', #7
5836    purl => 'PodcastURL', #7
5837    rtng => { #10
5838        Name => 'Rating',
5839        Format => 'int8u', #23
5840        Writable => 'int8s', #27
5841        PrintConv => {
5842            0 => 'none',
5843            1 => 'Explicit',
5844            2 => 'Clean',
5845            4 => 'Explicit (old)',
5846        },
5847    },
5848    sfID => { #10
5849        Name => 'AppleStoreCountry',
5850        Format => 'int32u',
5851        Writable => 'int32s', #27
5852        SeparateTable => 1,
5853        PrintConv => { #21
5854            143441 => 'United States', # US
5855            143442 => 'France', # FR
5856            143443 => 'Germany', # DE
5857            143444 => 'United Kingdom', # GB
5858            143445 => 'Austria', # AT
5859            143446 => 'Belgium', # BE
5860            143447 => 'Finland', # FI
5861            143448 => 'Greece', # GR
5862            143449 => 'Ireland', # IE
5863            143450 => 'Italy', # IT
5864            143451 => 'Luxembourg', # LU
5865            143452 => 'Netherlands', # NL
5866            143453 => 'Portugal', # PT
5867            143454 => 'Spain', # ES
5868            143455 => 'Canada', # CA
5869            143456 => 'Sweden', # SE
5870            143457 => 'Norway', # NO
5871            143458 => 'Denmark', # DK
5872            143459 => 'Switzerland', # CH
5873            143460 => 'Australia', # AU
5874            143461 => 'New Zealand', # NZ
5875            143462 => 'Japan', # JP
5876            143463 => 'Hong Kong', # HK
5877            143464 => 'Singapore', # SG
5878            143465 => 'China', # CN
5879            143466 => 'Republic of Korea', # KR
5880            143467 => 'India', # IN
5881            143468 => 'Mexico', # MX
5882            143469 => 'Russia', # RU
5883            143470 => 'Taiwan', # TW
5884            143471 => 'Vietnam', # VN
5885            143472 => 'South Africa', # ZA
5886            143473 => 'Malaysia', # MY
5887            143474 => 'Philippines', # PH
5888            143475 => 'Thailand', # TH
5889            143476 => 'Indonesia', # ID
5890            143477 => 'Pakistan', # PK
5891            143478 => 'Poland', # PL
5892            143479 => 'Saudi Arabia', # SA
5893            143480 => 'Turkey', # TR
5894            143481 => 'United Arab Emirates', # AE
5895            143482 => 'Hungary', # HU
5896            143483 => 'Chile', # CL
5897            143484 => 'Nepal', # NP
5898            143485 => 'Panama', # PA
5899            143486 => 'Sri Lanka', # LK
5900            143487 => 'Romania', # RO
5901            143489 => 'Czech Republic', # CZ
5902            143491 => 'Israel', # IL
5903            143492 => 'Ukraine', # UA
5904            143493 => 'Kuwait', # KW
5905            143494 => 'Croatia', # HR
5906            143495 => 'Costa Rica', # CR
5907            143496 => 'Slovakia', # SK
5908            143497 => 'Lebanon', # LB
5909            143498 => 'Qatar', # QA
5910            143499 => 'Slovenia', # SI
5911            143501 => 'Colombia', # CO
5912            143502 => 'Venezuela', # VE
5913            143503 => 'Brazil', # BR
5914            143504 => 'Guatemala', # GT
5915            143505 => 'Argentina', # AR
5916            143506 => 'El Salvador', # SV
5917            143507 => 'Peru', # PE
5918            143508 => 'Dominican Republic', # DO
5919            143509 => 'Ecuador', # EC
5920            143510 => 'Honduras', # HN
5921            143511 => 'Jamaica', # JM
5922            143512 => 'Nicaragua', # NI
5923            143513 => 'Paraguay', # PY
5924            143514 => 'Uruguay', # UY
5925            143515 => 'Macau', # MO
5926            143516 => 'Egypt', # EG
5927            143517 => 'Kazakhstan', # KZ
5928            143518 => 'Estonia', # EE
5929            143519 => 'Latvia', # LV
5930            143520 => 'Lithuania', # LT
5931            143521 => 'Malta', # MT
5932            143523 => 'Moldova', # MD
5933            143524 => 'Armenia', # AM
5934            143525 => 'Botswana', # BW
5935            143526 => 'Bulgaria', # BG
5936            143528 => 'Jordan', # JO
5937            143529 => 'Kenya', # KE
5938            143530 => 'Macedonia', # MK
5939            143531 => 'Madagascar', # MG
5940            143532 => 'Mali', # ML
5941            143533 => 'Mauritius', # MU
5942            143534 => 'Niger', # NE
5943            143535 => 'Senegal', # SN
5944            143536 => 'Tunisia', # TN
5945            143537 => 'Uganda', # UG
5946            143538 => 'Anguilla', # AI
5947            143539 => 'Bahamas', # BS
5948            143540 => 'Antigua and Barbuda', # AG
5949            143541 => 'Barbados', # BB
5950            143542 => 'Bermuda', # BM
5951            143543 => 'British Virgin Islands', # VG
5952            143544 => 'Cayman Islands', # KY
5953            143545 => 'Dominica', # DM
5954            143546 => 'Grenada', # GD
5955            143547 => 'Montserrat', # MS
5956            143548 => 'St. Kitts and Nevis', # KN
5957            143549 => 'St. Lucia', # LC
5958            143550 => 'St. Vincent and The Grenadines', # VC
5959            143551 => 'Trinidad and Tobago', # TT
5960            143552 => 'Turks and Caicos', # TC
5961            143553 => 'Guyana', # GY
5962            143554 => 'Suriname', # SR
5963            143555 => 'Belize', # BZ
5964            143556 => 'Bolivia', # BO
5965            143557 => 'Cyprus', # CY
5966            143558 => 'Iceland', # IS
5967            143559 => 'Bahrain', # BH
5968            143560 => 'Brunei Darussalam', # BN
5969            143561 => 'Nigeria', # NG
5970            143562 => 'Oman', # OM
5971            143563 => 'Algeria', # DZ
5972            143564 => 'Angola', # AO
5973            143565 => 'Belarus', # BY
5974            143566 => 'Uzbekistan', # UZ
5975            143568 => 'Azerbaijan', # AZ
5976            143571 => 'Yemen', # YE
5977            143572 => 'Tanzania', # TZ
5978            143573 => 'Ghana', # GH
5979            143575 => 'Albania', # AL
5980            143576 => 'Benin', # BJ
5981            143577 => 'Bhutan', # BT
5982            143578 => 'Burkina Faso', # BF
5983            143579 => 'Cambodia', # KH
5984            143580 => 'Cape Verde', # CV
5985            143581 => 'Chad', # TD
5986            143582 => 'Republic of the Congo', # CG
5987            143583 => 'Fiji', # FJ
5988            143584 => 'Gambia', # GM
5989            143585 => 'Guinea-Bissau', # GW
5990            143586 => 'Kyrgyzstan', # KG
5991            143587 => "Lao People's Democratic Republic", # LA
5992            143588 => 'Liberia', # LR
5993            143589 => 'Malawi', # MW
5994            143590 => 'Mauritania', # MR
5995            143591 => 'Federated States of Micronesia', # FM
5996            143592 => 'Mongolia', # MN
5997            143593 => 'Mozambique', # MZ
5998            143594 => 'Namibia', # NA
5999            143595 => 'Palau', # PW
6000            143597 => 'Papua New Guinea', # PG
6001            143598 => 'Sao Tome and Principe', # ST (S&atilde;o Tom&eacute; and Pr&iacute;ncipe)
6002            143599 => 'Seychelles', # SC
6003            143600 => 'Sierra Leone', # SL
6004            143601 => 'Solomon Islands', # SB
6005            143602 => 'Swaziland', # SZ
6006            143603 => 'Tajikistan', # TJ
6007            143604 => 'Turkmenistan', # TM
6008            143605 => 'Zimbabwe', # ZW
6009        },
6010    },
6011    soaa => 'SortAlbumArtist', #10
6012    soal => 'SortAlbum', #10
6013    soar => 'SortArtist', #10
6014    soco => 'SortComposer', #10
6015    sonm => 'SortName', #10
6016    sosn => 'SortShow', #10
6017    stik => { #10
6018        Name => 'MediaType',
6019        Format => 'int8u', #23
6020        Writable => 'int8s', #27
6021        PrintConvColumns => 2,
6022        PrintConv => { #(http://weblog.xanga.com/gryphondwb/615474010/iphone-ringtones---what-did-itunes-741-really-do.html)
6023            0 => 'Movie (old)', #forum9059 (was Movie)
6024            1 => 'Normal (Music)',
6025            2 => 'Audiobook',
6026            5 => 'Whacked Bookmark',
6027            6 => 'Music Video',
6028            9 => 'Movie', #forum9059 (was Short Film)
6029            10 => 'TV Show',
6030            11 => 'Booklet',
6031            14 => 'Ringtone',
6032            21 => 'Podcast', #15
6033            23 => 'iTunes U', #forum9059
6034        },
6035    },
6036    rate => 'RatingPercent', #PH
6037    titl => { Name => 'Title', Avoid => 1 },
6038    tven => 'TVEpisodeID', #7
6039    tves => { #7/10
6040        Name => 'TVEpisode',
6041        Format => 'int32u',
6042        Writable => 'int32s', #27
6043    },
6044    tvnn => 'TVNetworkName', #7
6045    tvsh => 'TVShow', #10
6046    tvsn => { #7/10
6047        Name => 'TVSeason',
6048        Format => 'int32u',
6049    },
6050    yrrc => 'Year', #(ffmpeg source)
6051    itnu => { #PH (iTunes 10.5)
6052        Name => 'iTunesU',
6053        Format => 'int8u', #27
6054        Writable => 'int8s', #27
6055        Description => 'iTunes U',
6056        PrintConv => { 0 => 'No', 1 => 'Yes' },
6057    },
6058    #https://github.com/communitymedia/mediautilities/blob/master/src/net/sourceforge/jaad/mp4/boxes/BoxTypes.java
6059    gshh => { Name => 'GoogleHostHeader',   Format => 'string' },
6060    gspm => { Name => 'GooglePingMessage',  Format => 'string' },
6061    gspu => { Name => 'GooglePingURL',      Format => 'string' },
6062    gssd => { Name => 'GoogleSourceData',   Format => 'string' },
6063    gsst => { Name => 'GoogleStartTime',    Format => 'string' },
6064    gstd => {
6065        Name => 'GoogleTrackDuration',
6066        Format => 'string',
6067        ValueConv => '$val / 1000',
6068        ValueConvInv => '$val * 1000',
6069        PrintConv => 'ConvertDuration($val)',
6070        PrintConvInv => q{
6071           $val =~ s/ s$//;
6072           my @a = split /(:| days )/, $val;
6073           my $sign = ($val =~ s/^-//) ? -1 : 1;
6074           $a[0] += shift(@a) * 24 if @a == 4;
6075           $a[0] += shift(@a) * 60 while @a > 1;
6076           return $a[0] * $sign;
6077        },
6078    },
6079
6080    # atoms observed in AAX audiobooks (ref PH)
6081    "\xa9cpy" => { Name => 'Copyright', Avoid => 1, Groups => { 2 => 'Author' } },
6082    "\xa9pub" => 'Publisher',
6083    "\xa9nrt" => 'Narrator',
6084    '@pti' => 'ParentTitle', # (guess -- same as "\xa9nam")
6085    '@PST' => 'ParentShortTitle', # (guess -- same as "\xa9nam")
6086    '@ppi' => 'ParentProductID', # (guess -- same as 'prID')
6087    '@sti' => 'ShortTitle', # (guess -- same as "\xa9nam")
6088    prID => 'ProductID',
6089    rldt => { Name => 'ReleaseDate', Groups => { 2 => 'Time' }},
6090    CDEK => { Name => 'Unknown_CDEK', Unknown => 1 }, # eg: "B004ZMTFEG" - used in URL's ("asin=")
6091    CDET => { Name => 'Unknown_CDET', Unknown => 1 }, # eg: "ADBL"
6092    VERS => 'ProductVersion',
6093    GUID => 'GUID',
6094    AACR => { Name => 'Unknown_AACR', Unknown => 1 }, # eg: "CR!1T1H1QH6WX7T714G2BMFX3E9MC4S"
6095    # ausr - 30 bytes (User Alias?)
6096    "\xa9xyz" => { #PH (written by Google Photos)
6097        Name => 'GPSCoordinates',
6098        Groups => { 2 => 'Location' },
6099        ValueConv => \&ConvertISO6709,
6100        ValueConvInv => \&ConvInvISO6709,
6101        PrintConv => \&PrintGPSCoordinates,
6102        PrintConvInv => \&PrintInvGPSCoordinates,
6103    },
6104    # the following tags written by iTunes 12.5.1.21
6105    # (ref https://www.ventismedia.com/mantis/view.php?id=14963
6106    #  https://community.mp3tag.de/t/x-mp4-new-tag-problems/19488)
6107    "\xa9wrk" => 'Work', #PH
6108    "\xa9mvn" => 'MovementName', #PH
6109    "\xa9mvi" => { #PH
6110        Name => 'MovementNumber',
6111        Format => 'int16u', #27
6112        Writable => 'int16s', #27
6113    },
6114    "\xa9mvc" => { #PH
6115        Name => 'MovementCount',
6116        Format => 'int16u', #27
6117        Writable => 'int16s', #27
6118    },
6119    shwm => { #PH
6120        Name => 'ShowMovement',
6121        Format => 'int8u', #27
6122        Writable => 'int8s', #27
6123        PrintConv => { 0 => 'No', 1 => 'Yes' },
6124    },
6125);
6126
6127# tag decoded from timed face records
6128%Image::ExifTool::QuickTime::FaceInfo = (
6129    PROCESS_PROC => \&ProcessMOV,
6130    GROUPS => { 2 => 'Video' },
6131    crec => {
6132        Name => 'FaceRec',
6133        SubDirectory => {
6134            TagTable => 'Image::ExifTool::QuickTime::FaceRec',
6135        },
6136    },
6137);
6138
6139# tag decoded from timed face records
6140%Image::ExifTool::QuickTime::FaceRec = (
6141    PROCESS_PROC => \&ProcessMOV,
6142    GROUPS => { 2 => 'Video' },
6143    cits => {
6144        Name => 'FaceItem',
6145        SubDirectory => {
6146            TagTable => 'Image::ExifTool::QuickTime::Keys',
6147            ProcessProc => \&Process_mebx,
6148        },
6149    },
6150);
6151
6152# item list keys (ref PH)
6153%Image::ExifTool::QuickTime::Keys = (
6154    PROCESS_PROC => \&ProcessKeys,
6155    WRITE_PROC => \&WriteKeys,
6156    CHECK_PROC => \&CheckQTValue,
6157    VARS => { LONG_TAGS => 3 },
6158    WRITABLE => 1,
6159    # (not PREFERRED when writing)
6160    GROUPS => { 1 => 'Keys' },
6161    WRITE_GROUP => 'Keys',
6162    LANG_INFO => \&GetLangInfo,
6163    FORMAT => 'string',
6164    NOTES => q{
6165        This directory contains a list of key names which are used to decode tags
6166        written by the "mdta" handler.  Also in this table are a few tags found in
6167        timed metadata that are not yet writable by ExifTool.  The prefix of
6168        "com.apple.quicktime." has been removed from the TagID's below.  These tags
6169        support alternate languages in the same way as the
6170        L<ItemList|Image::ExifTool::TagNames/QuickTime ItemList Tags> tags.  Note
6171        that by default,
6172        L<ItemList|Image::ExifTool::TagNames/QuickTime ItemList Tags> and
6173        L<UserData|Image::ExifTool::TagNames/QuickTime UserData Tags> tags are
6174        preferred when writing, so to create a tag when a same-named tag exists in
6175        either of these tables, either the "Keys" location must be specified (eg.
6176        C<-Keys:Author=Phil> on the command line), or the PREFERRED level must be
6177        changed via L<the config file|../config.html#PREF>.
6178    },
6179    version     => 'Version',
6180    album       => 'Album',
6181    artist      => { },
6182    artwork     => { },
6183    author      => { Name => 'Author',      Groups => { 2 => 'Author' } },
6184    comment     => { },
6185    copyright   => { Name => 'Copyright',   Groups => { 2 => 'Author' } },
6186    creationdate=> {
6187        Name => 'CreationDate',
6188        Groups => { 2 => 'Time' },
6189        Shift => 'Time',
6190        ValueConv => q{
6191            require Image::ExifTool::XMP;
6192            $val =  Image::ExifTool::XMP::ConvertXMPDate($val,1);
6193            $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary
6194            return $val;
6195        },
6196        ValueConvInv => q{
6197            require Image::ExifTool::XMP;
6198            $val =  Image::ExifTool::XMP::FormatXMPDate($val);
6199            $val =~ s/([-+]\d{2}):(\d{2})$/$1$2/; # remove time zone colon
6200            return $val;
6201        },
6202        PrintConv => '$self->ConvertDateTime($val)',
6203        PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist)
6204    },
6205    description => { },
6206    director    => { },
6207    displayname => { Name => 'DisplayName' },
6208    title       => { }, #22
6209    genre       => { },
6210    information => { },
6211    keywords    => { },
6212    producer    => { }, #22
6213    make        => { Name => 'Make',        Groups => { 2 => 'Camera' } },
6214    model       => { Name => 'Model',       Groups => { 2 => 'Camera' } },
6215    publisher   => { },
6216    software    => { },
6217    year        => { Groups => { 2 => 'Time' } },
6218    'camera.identifier' => 'CameraIdentifier', # (iPhone 4)
6219    'camera.framereadouttimeinmicroseconds' => { # (iPhone 4)
6220        Name => 'FrameReadoutTime',
6221        ValueConv => '$val * 1e-6',
6222        ValueConvInv => 'int($val * 1e6 + 0.5)',
6223        PrintConv => '$val * 1e6 . " microseconds"',
6224        PrintConvInv => '$val =~ s/ .*//; $val * 1e-6',
6225    },
6226    'location.ISO6709' => {
6227        Name => 'GPSCoordinates',
6228        Groups => { 2 => 'Location' },
6229        ValueConv => \&ConvertISO6709,
6230        ValueConvInv => \&ConvInvISO6709,
6231        PrintConv => \&PrintGPSCoordinates,
6232        PrintConvInv => \&PrintInvGPSCoordinates,
6233    },
6234    'location.name' => { Name => 'LocationName', Groups => { 2 => 'Location' } },
6235    'location.body' => { Name => 'LocationBody', Groups => { 2 => 'Location' } },
6236    'location.note' => { Name => 'LocationNote', Groups => { 2 => 'Location' } },
6237    'location.role' => {
6238        Name => 'LocationRole',
6239        Groups => { 2 => 'Location' },
6240        PrintConv => {
6241            0 => 'Shooting Location',
6242            1 => 'Real Location',
6243            2 => 'Fictional Location',
6244        },
6245    },
6246    'location.date' => {
6247        Name => 'LocationDate',
6248        Groups => { 2 => 'Time' },
6249        Shift => 'Time',
6250        ValueConv => q{
6251            require Image::ExifTool::XMP;
6252            $val =  Image::ExifTool::XMP::ConvertXMPDate($val);
6253            $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary
6254            return $val;
6255        },
6256        ValueConvInv => q{
6257            require Image::ExifTool::XMP;
6258            $val =  Image::ExifTool::XMP::FormatXMPDate($val);
6259            $val =~ s/([-+]\d{2}):(\d{2})$/$1$2/; # remove time zone colon
6260            return $val;
6261        },
6262        PrintConv => '$self->ConvertDateTime($val)',
6263        PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist)
6264    },
6265    'direction.facing' => { Name => 'CameraDirection', Groups => { 2 => 'Location' } },
6266    'direction.motion' => { Name => 'CameraMotion',    Groups => { 2 => 'Location' } },
6267    'location.body'    => { Name => 'LocationBody',    Groups => { 2 => 'Location' } },
6268    'player.version'                => 'PlayerVersion',
6269    'player.movie.visual.brightness'=> 'Brightness',
6270    'player.movie.visual.color'     => 'Color',
6271    'player.movie.visual.tint'      => 'Tint',
6272    'player.movie.visual.contrast'  => 'Contrast',
6273    'player.movie.audio.gain'       => 'AudioGain',
6274    'player.movie.audio.treble'     => 'Trebel',
6275    'player.movie.audio.bass'       => 'Bass',
6276    'player.movie.audio.balance'    => 'Balance',
6277    'player.movie.audio.pitchshift' => 'PitchShift',
6278    'player.movie.audio.mute' => {
6279        Name => 'Mute',
6280        Format => 'int8u',
6281        PrintConv => { 0 => 'Off', 1 => 'On' },
6282    },
6283    'rating.user'  => 'UserRating', # (Canon ELPH 510 HS)
6284    'collection.user' => 'UserCollection', #22
6285    'Encoded_With' => 'EncodedWith',
6286#
6287# the following tags aren't in the com.apple.quicktime namespace:
6288#
6289    'com.apple.photos.captureMode' => 'CaptureMode',
6290    'com.android.version' => 'AndroidVersion',
6291#
6292# also seen
6293#
6294    # com.divergentmedia.clipwrap.model            ('NEX-FS700EK')
6295    # com.divergentmedia.clipwrap.model1           ('49')
6296    # com.divergentmedia.clipwrap.model2           ('0')
6297    # com.divergentmedia.clipwrap.manufacturer     ('Sony')
6298    # com.divergentmedia.clipwrap.originalDateTime ('2013/2/6 10:30:40+0200')
6299#
6300# seen in timed metadata (mebx), and added dynamically to the table
6301# via SaveMetaKeys().  NOTE: these tags are not writable!
6302#
6303    # (mdta)com.apple.quicktime.video-orientation (dtyp=66, int16s)
6304    'video-orientation' => { Name => 'VideoOrientation', Writable => 0 },
6305    # (mdta)com.apple.quicktime.live-photo-info (dtyp=com.apple.quicktime.com.apple.quicktime.live-photo-info)
6306    'live-photo-info' => {
6307        Name => 'LivePhotoInfo',
6308        Writable => 0,
6309        # not sure what these values mean, but unpack them anyway - PH
6310        # (ignore the fact that the "f" and "l" unpacks won't work on a big-endian machine)
6311        ValueConv => 'join " ",unpack "VfVVf6c4lCCcclf4Vvv", $val',
6312    },
6313    # (mdta)com.apple.quicktime.still-image-time (dtyp=65, int8s)
6314    'still-image-time' => { # (found in live photo)
6315        Name => 'StillImageTime',
6316        Writable => 0,
6317        Notes => q{
6318            this tag always has a value of -1; the time of the still image is obtained
6319            from the associated SampleTime
6320        },
6321    },
6322    # (mdta)com.apple.quicktime.detected-face (dtyp='com.apple.quicktime.detected-face')
6323    'detected-face' => {
6324        Name => 'FaceInfo',
6325        Writable => 0,
6326        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::FaceInfo' },
6327    },
6328    # ---- detected-face fields ( ----
6329    # --> back here after a round trip through FaceInfo -> FaceRec -> FaceItem
6330    # (fiel)com.apple.quicktime.detected-face.bounds (dtyp=80, float[8])
6331    'detected-face.bounds' => {
6332        Name => 'DetectedFaceBounds',
6333        Writable => 0,
6334        # round to a reasonable number of decimal places
6335        PrintConv => 'my @a=split " ",$val;$_=int($_*1e6+.5)/1e6 foreach @a;join " ",@a',
6336        PrintConvInv => '$val',
6337    },
6338    # (fiel)com.apple.quicktime.detected-face.face-id (dtyp=77, int32u)
6339    'detected-face.face-id'    => { Name => 'DetectedFaceID',        Writable => 0 },
6340    # (fiel)com.apple.quicktime.detected-face.roll-angle (dtyp=23, float)
6341    'detected-face.roll-angle' => { Name => 'DetectedFaceRollAngle', Writable => 0 },
6342    # (fiel)com.apple.quicktime.detected-face.yaw-angle (dtyp=23, float)
6343    'detected-face.yaw-angle'  => { Name => 'DetectedFaceYawAngle',  Writable => 0 },
6344#
6345# seen in Apple ProRes RAW file
6346#
6347    # (mdta)com.apple.proapps.manufacturer (eg. "Sony")
6348    # (mdta)com.apple.proapps.exif.{Exif}.FNumber (float, eg. 1.0)
6349    # (mdta)org.smpte.rdd18.lens.irisfnumber (eg. "F1.0")
6350    # (mdta)com.apple.proapps.exif.{Exif}.ShutterSpeedValue (float, eg. 1.006)
6351    # (mdta)org.smpte.rdd18.camera.shutterspeed_angle (eg. "179.2deg")
6352    # (mdta)org.smpte.rdd18.camera.neutraldensityfilterwheelsetting (eg. "ND1")
6353    # (mdta)org.smpte.rdd18.camera.whitebalance (eg. "4300K")
6354    # (mdta)com.apple.proapps.exif.{Exif}.ExposureIndex (float, eg. 4000)
6355    # (mdta)org.smpte.rdd18.camera.isosensitivity (eg. "4000")
6356    # (mdta)com.apple.proapps.image.{TIFF}.Make (eg. "Atmos")
6357    # (mdta)com.apple.proapps.image.{TIFF}.Model (eg. "ShogunInferno")
6358    # (mdta)com.apple.proapps.image.{TIFF}.Software (eg. "9.0")
6359);
6360
6361# iTunes info ('----') atoms
6362%Image::ExifTool::QuickTime::iTunesInfo = (
6363    PROCESS_PROC => \&ProcessMOV,
6364    GROUPS => { 2 => 'Audio' },
6365    NOTES => q{
6366        ExifTool will extract any iTunesInfo tags that exist, even if they are not
6367        defined in this table.
6368    },
6369    # 'mean'/'name'/'data' atoms form a triplet, but unfortunately
6370    # I haven't been able to find any documentation on this.
6371    # 'mean' is normally 'com.apple.iTunes'
6372    mean => {
6373        Name => 'Mean',
6374        # the 'Triplet' flag tells ProcessMOV() to generate
6375        # a single tag from the mean/name/data triplet
6376        Triplet => 1,
6377        Hidden => 1,
6378    },
6379    name => {
6380        Name => 'Name',
6381        Triplet => 1,
6382        Hidden => 1,
6383    },
6384    data => {
6385        Name => 'Data',
6386        Triplet => 1,
6387        Hidden => 1,
6388    },
6389    # the tag ID's below are composed from "mean/name",
6390    # but "mean/" is omitted if it is "com.apple.iTunes/":
6391    'iTunMOVI' => {
6392        Name => 'iTunMOVI',
6393        SubDirectory => { TagTable => 'Image::ExifTool::PLIST::Main' },
6394    },
6395    'tool' => {
6396        Name => 'iTunTool',
6397        Description => 'iTunTool',
6398        Format => 'int32u',
6399        PrintConv => 'sprintf("0x%.8x",$val)',
6400    },
6401    'iTunEXTC' => {
6402        Name => 'ContentRating',
6403        Notes => 'standard | rating | score | reasons',
6404        # eg. 'us-tv|TV-14|500|V', 'mpaa|PG-13|300|For violence and sexuality'
6405        # (see http://shadowofged.blogspot.ca/2008/06/itunes-content-ratings.html)
6406    },
6407    'iTunNORM' => {
6408        Name => 'VolumeNormalization',
6409        PrintConv => '$val=~s/ 0+(\w)/ $1/g; $val=~s/^\s+//; $val',
6410    },
6411    'iTunSMPB' => {
6412        Name => 'iTunSMPB',
6413        Description => 'iTunSMPB',
6414        # hex format, similar to iTunNORM, but 12 words instead of 10,
6415        # and 4th word is 16 hex digits (all others are 8)
6416        # (gives AAC encoder delay, ref http://code.google.com/p/l-smash/issues/detail?id=1)
6417        PrintConv => '$val=~s/ 0+(\w)/ $1/g; $val=~s/^\s+//; $val',
6418    },
6419    # (CDDB = Compact Disc DataBase)
6420    # iTunes_CDDB_1 = <CDDB1 disk ID>+<# tracks>+<logical block address for each track>...
6421    'iTunes_CDDB_1' => 'CDDB1Info',
6422    'iTunes_CDDB_TrackNumber' => 'CDDBTrackNumber',
6423    'Encoding Params' => {
6424        Name => 'EncodingParams',
6425        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::EncodingParams' },
6426    },
6427    # also heard about 'iTunPGAP', but I haven't seen a sample
6428    DISCNUMBER => 'DiscNumber', #PH
6429    TRACKNUMBER => 'TrackNumber', #PH
6430    popularimeter => 'Popularimeter', #PH
6431);
6432
6433# iTunes audio encoding parameters
6434# ref https://developer.apple.com/library/mac/#documentation/MusicAudio/Reference/AudioCodecServicesRef/Reference/reference.html
6435%Image::ExifTool::QuickTime::EncodingParams = (
6436    PROCESS_PROC => \&ProcessEncodingParams,
6437    GROUPS => { 2 => 'Audio' },
6438    # (I have commented out the ones that don't have integer values because they
6439    #  probably don't appear, and definitely wouldn't work with current decoding - PH)
6440
6441    # global codec properties
6442    #'lnam' => 'AudioCodecName',
6443    #'lmak' => 'AudioCodecManufacturer',
6444    #'lfor' => 'AudioCodecFormat',
6445    'vpk?' => 'AudioHasVariablePacketByteSizes',
6446    #'ifm#' => 'AudioSupportedInputFormats',
6447    #'ofm#' => 'AudioSupportedOutputFormats',
6448    #'aisr' => 'AudioAvailableInputSampleRates',
6449    #'aosr' => 'AudioAvailableOutputSampleRates',
6450    'abrt' => 'AudioAvailableBitRateRange',
6451    'mnip' => 'AudioMinimumNumberInputPackets',
6452    'mnop' => 'AudioMinimumNumberOutputPackets',
6453    'cmnc' => 'AudioAvailableNumberChannels',
6454    'lmrc' => 'AudioDoesSampleRateConversion',
6455    #'aicl' => 'AudioAvailableInputChannelLayoutTags',
6456    #'aocl' => 'AudioAvailableOutputChannelLayoutTags',
6457    #'if4o' => 'AudioInputFormatsForOutputFormat',
6458    #'of4i' => 'AudioOutputFormatsForInputFormat',
6459    #'acfi' => 'AudioFormatInfo',
6460
6461    # instance codec properties
6462    'tbuf' => 'AudioInputBufferSize',
6463    'pakf' => 'AudioPacketFrameSize',
6464    'pakb' => 'AudioMaximumPacketByteSize',
6465    #'ifmt' => 'AudioCurrentInputFormat',
6466    #'ofmt' => 'AudioCurrentOutputFormat',
6467    #'kuki' => 'AudioMagicCookie',
6468    'ubuf' => 'AudioUsedInputBufferSize',
6469    'init' => 'AudioIsInitialized',
6470    'brat' => 'AudioCurrentTargetBitRate',
6471    #'cisr' => 'AudioCurrentInputSampleRate',
6472    #'cosr' => 'AudioCurrentOutputSampleRate',
6473    'srcq' => 'AudioQualitySetting',
6474    #'brta' => 'AudioApplicableBitRateRange',
6475    #'isra' => 'AudioApplicableInputSampleRates',
6476    #'osra' => 'AudioApplicableOutputSampleRates',
6477    'pad0' => 'AudioZeroFramesPadded',
6478    'prmm' => 'AudioCodecPrimeMethod',
6479    #'prim' => 'AudioCodecPrimeInfo',
6480    #'icl ' => 'AudioInputChannelLayout',
6481    #'ocl ' => 'AudioOutputChannelLayout',
6482    #'acs ' => 'AudioCodecSettings',
6483    #'acfl' => 'AudioCodecFormatList',
6484    'acbf' => 'AudioBitRateControlMode',
6485    'vbrq' => 'AudioVBRQuality',
6486    'mdel' => 'AudioMinimumDelayMode',
6487
6488    # deprecated
6489    'pakd' => 'AudioRequiresPacketDescription',
6490    #'brt#' => 'AudioAvailableBitRates',
6491    'acef' => 'AudioExtendFrequencies',
6492    'ursr' => 'AudioUseRecommendedSampleRate',
6493    'oppr' => 'AudioOutputPrecedence',
6494    #'loud' => 'AudioCurrentLoudnessStatistics',
6495
6496    # others
6497    'vers' => 'AudioEncodingParamsVersion', #PH
6498    'cdcv' => { #PH
6499        Name => 'AudioComponentVersion',
6500        ValueConv => 'join ".", unpack("ncc", pack("N",$val))',
6501    },
6502);
6503
6504# print to video data block
6505%Image::ExifTool::QuickTime::Video = (
6506    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
6507    GROUPS => { 2 => 'Video' },
6508    0 => {
6509        Name => 'DisplaySize',
6510        PrintConv => {
6511            0 => 'Normal',
6512            1 => 'Double Size',
6513            2 => 'Half Size',
6514            3 => 'Full Screen',
6515            4 => 'Current Size',
6516        },
6517    },
6518    6 => {
6519        Name => 'SlideShow',
6520        PrintConv => {
6521            0 => 'No',
6522            1 => 'Yes',
6523        },
6524    },
6525);
6526
6527# 'hnti' atoms
6528%Image::ExifTool::QuickTime::HintInfo = (
6529    PROCESS_PROC => \&ProcessMOV,
6530    GROUPS => { 2 => 'Video' },
6531    'rtp ' => {
6532        Name => 'RealtimeStreamingProtocol',
6533        PrintConv => '$val=~s/^sdp /(SDP) /; $val',
6534    },
6535    'sdp ' => 'StreamingDataProtocol',
6536);
6537
6538# 'hinf' atoms
6539%Image::ExifTool::QuickTime::HintTrackInfo = (
6540    PROCESS_PROC => \&ProcessMOV,
6541    GROUPS => { 2 => 'Video' },
6542    trpY => { Name => 'TotalBytes', Format => 'int64u' }, #(documented)
6543    trpy => { Name => 'TotalBytes', Format => 'int64u' }, #(observed)
6544    totl => { Name => 'TotalBytes', Format => 'int32u' },
6545    nump => { Name => 'NumPackets', Format => 'int64u' },
6546    npck => { Name => 'NumPackets', Format => 'int32u' },
6547    tpyl => { Name => 'TotalBytesNoRTPHeaders', Format => 'int64u' },
6548    tpaY => { Name => 'TotalBytesNoRTPHeaders', Format => 'int32u' }, #(documented)
6549    tpay => { Name => 'TotalBytesNoRTPHeaders', Format => 'int32u' }, #(observed)
6550    maxr => {
6551        Name => 'MaxDataRate',
6552        Format => 'int32u',
6553        Count => 2,
6554        PrintConv => 'my @a=split(" ",$val);sprintf("%d bytes in %.3f s",$a[1],$a[0]/1000)',
6555    },
6556    dmed => { Name => 'MediaTrackBytes',    Format => 'int64u' },
6557    dimm => { Name => 'ImmediateDataBytes', Format => 'int64u' },
6558    drep => { Name => 'RepeatedDataBytes',  Format => 'int64u' },
6559    tmin => {
6560        Name => 'MinTransmissionTime',
6561        Format => 'int32u',
6562        PrintConv => 'sprintf("%.3f s",$val/1000)',
6563    },
6564    tmax => {
6565        Name => 'MaxTransmissionTime',
6566        Format => 'int32u',
6567        PrintConv => 'sprintf("%.3f s",$val/1000)',
6568    },
6569    pmax => { Name => 'LargestPacketSize',  Format => 'int32u' },
6570    dmax => {
6571        Name => 'LargestPacketDuration',
6572        Format => 'int32u',
6573        PrintConv => 'sprintf("%.3f s",$val/1000)',
6574    },
6575    payt => {
6576        Name => 'PayloadType',
6577        Format => 'undef',  # (necessary to prevent decoding as string!)
6578        ValueConv => 'unpack("N",$val) . " " . substr($val, 5)',
6579        PrintConv => '$val=~s/ /, /;$val',
6580    },
6581);
6582
6583# MP4 media box (ref 5)
6584%Image::ExifTool::QuickTime::Media = (
6585    PROCESS_PROC => \&ProcessMOV,
6586    WRITE_PROC => \&WriteQuickTime,
6587    GROUPS => { 1 => 'Track#', 2 => 'Video' },
6588    NOTES => 'MP4 media box.',
6589    mdhd => {
6590        Name => 'MediaHeader',
6591        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MediaHeader' },
6592    },
6593    hdlr => {
6594        Name => 'Handler',
6595        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Handler' },
6596    },
6597    minf => {
6598        Name => 'MediaInfo',
6599        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MediaInfo' },
6600    },
6601);
6602
6603# MP4 media header box (ref 5)
6604%Image::ExifTool::QuickTime::MediaHeader = (
6605    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
6606    WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
6607    CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
6608    GROUPS => { 1 => 'Track#', 2 => 'Video' },
6609    FORMAT => 'int32u',
6610    DATAMEMBER => [ 0, 1, 2, 3, 4 ],
6611    0 => {
6612        Name => 'MediaHeaderVersion',
6613        RawConv => '$$self{MediaHeaderVersion} = $val',
6614    },
6615    1 => {
6616        Name => 'MediaCreateDate',
6617        Groups => { 2 => 'Time' },
6618        %timeInfo,
6619        # this is int64u if MediaHeaderVersion == 1 (ref 5/13)
6620        Hook => '$$self{MediaHeaderVersion} and $format = "int64u", $varSize += 4',
6621    },
6622    2 => {
6623        Name => 'MediaModifyDate',
6624        Groups => { 2 => 'Time' },
6625        %timeInfo,
6626        # this is int64u if MediaHeaderVersion == 1 (ref 5/13)
6627        Hook => '$$self{MediaHeaderVersion} and $format = "int64u", $varSize += 4',
6628    },
6629    3 => {
6630        Name => 'MediaTimeScale',
6631        RawConv => '$$self{MediaTS} = $val',
6632    },
6633    4 => {
6634        Name => 'MediaDuration',
6635        RawConv => '$$self{MediaTS} ? $val / $$self{MediaTS} : $val',
6636        PrintConv => '$$self{MediaTS} ? ConvertDuration($val) : $val',
6637        # this is int64u if MediaHeaderVersion == 1 (ref 5/13)
6638        Hook => '$$self{MediaHeaderVersion} and $format = "int64u", $varSize += 4',
6639    },
6640    5 => {
6641        Name => 'MediaLanguageCode',
6642        Format => 'int16u',
6643        RawConv => '$val ? $val : undef',
6644        # allow both Macintosh (for MOV files) and ISO (for MP4 files) language codes
6645        ValueConv => '($val < 0x400 or $val == 0x7fff) ? $val : pack "C*", map { (($val>>$_)&0x1f)+0x60 } 10, 5, 0',
6646        PrintConv => q{
6647            return $val unless $val =~ /^\d+$/;
6648            require Image::ExifTool::Font;
6649            return $Image::ExifTool::Font::ttLang{Macintosh}{$val} || "Unknown ($val)";
6650        },
6651    },
6652);
6653
6654# MP4 media information box (ref 5)
6655%Image::ExifTool::QuickTime::MediaInfo = (
6656    PROCESS_PROC => \&ProcessMOV,
6657    WRITE_PROC => \&WriteQuickTime,
6658    GROUPS => { 1 => 'Track#', 2 => 'Video' },
6659    NOTES => 'MP4 media info box.',
6660    vmhd => {
6661        Name => 'VideoHeader',
6662        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::VideoHeader' },
6663    },
6664    smhd => {
6665        Name => 'AudioHeader',
6666        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::AudioHeader' },
6667    },
6668    hmhd => {
6669        Name => 'HintHeader',
6670        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HintHeader' },
6671    },
6672    nmhd => {
6673        Name => 'NullMediaHeader',
6674        Flags => ['Binary','Unknown'],
6675    },
6676    dinf => {
6677        Name => 'DataInfo', # (don't change this name -- used to recognize directory when writing)
6678        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::DataInfo' },
6679    },
6680    gmhd => {
6681        Name => 'GenMediaHeader',
6682        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::GenMediaHeader' },
6683    },
6684    hdlr => { #PH
6685        Name => 'Handler',
6686        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Handler' },
6687    },
6688    stbl => {
6689        Name => 'SampleTable',
6690        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::SampleTable' },
6691    },
6692);
6693
6694# MP4 video media header (ref 5)
6695%Image::ExifTool::QuickTime::VideoHeader = (
6696    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
6697    GROUPS => { 2 => 'Video' },
6698    NOTES => 'MP4 video media header.',
6699    FORMAT => 'int16u',
6700    2 => {
6701        Name => 'GraphicsMode',
6702        PrintHex => 1,
6703        SeparateTable => 'GraphicsMode',
6704        PrintConv => \%graphicsMode,
6705    },
6706    3 => { Name => 'OpColor', Format => 'int16u[3]' },
6707);
6708
6709# MP4 audio media header (ref 5)
6710%Image::ExifTool::QuickTime::AudioHeader = (
6711    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
6712    GROUPS => { 2 => 'Audio' },
6713    NOTES => 'MP4 audio media header.',
6714    FORMAT => 'int16u',
6715    2 => { Name => 'Balance', Format => 'fixed16s' },
6716);
6717
6718# MP4 hint media header (ref 5)
6719%Image::ExifTool::QuickTime::HintHeader = (
6720    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
6721    NOTES => 'MP4 hint media header.',
6722    FORMAT => 'int16u',
6723    2 => 'MaxPDUSize',
6724    3 => 'AvgPDUSize',
6725    4 => { Name => 'MaxBitrate', Format => 'int32u', PrintConv => 'ConvertBitrate($val)' },
6726    6 => { Name => 'AvgBitrate', Format => 'int32u', PrintConv => 'ConvertBitrate($val)' },
6727);
6728
6729# MP4 sample table box (ref 5)
6730%Image::ExifTool::QuickTime::SampleTable = (
6731    PROCESS_PROC => \&ProcessMOV,
6732    WRITE_PROC => \&WriteQuickTime,
6733    GROUPS => { 2 => 'Video' },
6734    NOTES => 'MP4 sample table box.',
6735    stsd => [
6736        {
6737            Name => 'AudioSampleDesc',
6738            Condition => '$$self{HandlerType} and $$self{HandlerType} eq "soun"',
6739            SubDirectory => {
6740                TagTable => 'Image::ExifTool::QuickTime::AudioSampleDesc',
6741                ProcessProc => \&ProcessSampleDesc,
6742            },
6743        },{
6744            Name => 'VideoSampleDesc',
6745            Condition => '$$self{HandlerType} and $$self{HandlerType} eq "vide"',
6746            SubDirectory => {
6747                TagTable => 'Image::ExifTool::QuickTime::ImageDesc',
6748                ProcessProc => \&ProcessSampleDesc,
6749            },
6750        },{
6751            Name => 'HintSampleDesc',
6752            Condition => '$$self{HandlerType} and $$self{HandlerType} eq "hint"',
6753            SubDirectory => {
6754                TagTable => 'Image::ExifTool::QuickTime::HintSampleDesc',
6755                ProcessProc => \&ProcessSampleDesc,
6756            },
6757        },{
6758            Name => 'MetaSampleDesc',
6759            Condition => '$$self{HandlerType} and $$self{HandlerType} eq "meta"',
6760            SubDirectory => {
6761                TagTable => 'Image::ExifTool::QuickTime::MetaSampleDesc',
6762                ProcessProc => \&ProcessSampleDesc,
6763            },
6764        },{
6765            Name => 'OtherSampleDesc',
6766            SubDirectory => {
6767                TagTable => 'Image::ExifTool::QuickTime::OtherSampleDesc',
6768                ProcessProc => \&ProcessSampleDesc,
6769            },
6770        },
6771        # (Note: "alis" HandlerType handled by the parent audio or video handler)
6772    ],
6773    stts => [ # decoding time-to-sample table
6774        {
6775            Name => 'VideoFrameRate',
6776            Notes => 'average rate calculated from time-to-sample table for video media',
6777            Condition => '$$self{HandlerType} and $$self{HandlerType} eq "vide"',
6778            Format => 'undef',  # (necessary to prevent decoding as string!)
6779            # (must be RawConv so appropriate MediaTS is used in calculation)
6780            RawConv => 'Image::ExifTool::QuickTime::CalcSampleRate($self, \$val)',
6781            PrintConv => 'int($val * 1000 + 0.5) / 1000',
6782        },
6783        {
6784            Name => 'TimeToSampleTable',
6785            Flags => ['Binary','Unknown'],
6786        },
6787    ],
6788    ctts => {
6789        Name => 'CompositionTimeToSample',
6790        Flags => ['Binary','Unknown'],
6791    },
6792    stsc => {
6793        Name => 'SampleToChunk',
6794        Flags => ['Binary','Unknown'],
6795    },
6796    stsz => {
6797        Name => 'SampleSizes',
6798        Flags => ['Binary','Unknown'],
6799    },
6800    stz2 => {
6801        Name => 'CompactSampleSizes',
6802        Flags => ['Binary','Unknown'],
6803    },
6804    stco => {
6805        Name => 'ChunkOffset',
6806        Flags => ['Binary','Unknown'],
6807    },
6808    co64 => {
6809        Name => 'ChunkOffset64',
6810        Flags => ['Binary','Unknown'],
6811    },
6812    stss => {
6813        Name => 'SyncSampleTable',
6814        Flags => ['Binary','Unknown'],
6815    },
6816    stsh => {
6817        Name => 'ShadowSyncSampleTable',
6818        Flags => ['Binary','Unknown'],
6819    },
6820    padb => {
6821        Name => 'SamplePaddingBits',
6822        Flags => ['Binary','Unknown'],
6823    },
6824    stdp => {
6825        Name => 'SampleDegradationPriority',
6826        Flags => ['Binary','Unknown'],
6827    },
6828    sdtp => {
6829        Name => 'IdependentAndDisposableSamples',
6830        Flags => ['Binary','Unknown'],
6831    },
6832    sbgp => {
6833        Name => 'SampleToGroup',
6834        Flags => ['Binary','Unknown'],
6835    },
6836    sgpd => {
6837        Name => 'SampleGroupDescription',
6838        Flags => ['Binary','Unknown'],
6839        # bytes 4-7 give grouping type (ref ISO/IEC 14496-15:2014)
6840        #   tsas - temporal sublayer sample
6841        #   stsa - step-wise temporal layer access
6842        #   avss - AVC sample
6843        #   tscl - temporal layer scalability
6844        #   sync - sync sample
6845    },
6846    subs => {
6847        Name => 'Sub-sampleInformation',
6848        Flags => ['Binary','Unknown'],
6849    },
6850    cslg => {
6851        Name => 'CompositionToDecodeTimelineMapping',
6852        Flags => ['Binary','Unknown'],
6853    },
6854    stps => {
6855        Name => 'PartialSyncSamples',
6856        ValueConv => 'join " ",unpack("x8N*",$val)',
6857    },
6858    # mark - 8 bytes all zero (GoPro)
6859);
6860
6861# MP4 audio sample description box (ref 5/AtomicParsley 0.9.4 parsley.cpp)
6862%Image::ExifTool::QuickTime::AudioSampleDesc = (
6863    PROCESS_PROC => \&ProcessHybrid,
6864    VARS => { ID_LABEL => 'ID/Index' },
6865    GROUPS => { 2 => 'Audio' },
6866    NOTES => q{
6867        MP4 audio sample description.  This hybrid atom contains both data and child
6868        atoms.
6869    },
6870    4  => {
6871        Name => 'AudioFormat',
6872        Format => 'undef[4]',
6873        RawConv => q{
6874            $$self{AudioFormat} = $val;
6875            return undef unless $val =~ /^[\w ]{4}$/i;
6876            # check for protected audio format
6877            $self->OverrideFileType('M4P') if $val eq 'drms' and $$self{VALUE}{FileType} eq 'M4A';
6878            return $val;
6879        },
6880        # see this link for print conversions (not complete):
6881        # https://github.com/yannickcr/brooser/blob/master/php/librairies/getid3/module.audio-video.quicktime.php
6882    },
6883    20 => { #PH
6884        Name => 'AudioVendorID',
6885        Condition => '$$self{AudioFormat} ne "mp4s"',
6886        Format => 'undef[4]',
6887        RawConv => '$val eq "\0\0\0\0" ? undef : $val',
6888        PrintConv => \%vendorID,
6889        SeparateTable => 'VendorID',
6890    },
6891    24 => { Name => 'AudioChannels',        Format => 'int16u' },
6892    26 => { Name => 'AudioBitsPerSample',   Format => 'int16u' },
6893    32 => { Name => 'AudioSampleRate',      Format => 'fixed32u' },
6894#
6895# Observed offsets for child atoms of various AudioFormat types:
6896#
6897#   AudioFormat  Offset  Child atoms
6898#   -----------  ------  ----------------
6899#   mp4a         52 *    wave, chan, esds, SA3D(Insta360 spherical video params?,also GoPro Max)
6900#   in24         52      wave, chan
6901#   "ms\0\x11"   52      wave
6902#   sowt         52      chan
6903#   mp4a         36 *    esds, pinf
6904#   drms         36      esds, sinf
6905#   samr         36      damr
6906#   alac         36      alac
6907#   ac-3         36      dac3
6908#
6909# (* child atoms found at different offsets in mp4a)
6910#
6911    pinf => {
6912        Name => 'PurchaseInfo',
6913        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ProtectionInfo' },
6914    },
6915    sinf => { # "protection scheme information"
6916        Name => 'ProtectionInfo', #3
6917        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ProtectionInfo' },
6918    },
6919    # f - 16/36 bytes
6920    # esds - 31/40/42/43 bytes - ES descriptor (ref 3)
6921    damr => { #3
6922        Name => 'DecodeConfig',
6923        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::DecodeConfig' },
6924    },
6925    wave => {
6926        Name => 'Wave',
6927        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Wave' },
6928    },
6929    chan => {
6930        Name => 'AudioChannelLayout',
6931        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ChannelLayout' },
6932    }
6933    # alac - 28 bytes
6934    # adrm - AAX DRM atom? 148 bytes
6935    # aabd - AAX unknown 17kB (contains 'aavd' strings)
6936    # SA3D - written by Garmin VIRB360
6937);
6938
6939# AMR decode config box (ref 3)
6940%Image::ExifTool::QuickTime::DecodeConfig = (
6941    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
6942    GROUPS => { 2 => 'Audio' },
6943    0 => {
6944        Name => 'EncoderVendor',
6945        Format => 'undef[4]',
6946    },
6947    4 => 'EncoderVersion',
6948    # 5 - int16u - packet modes
6949    # 7 - int8u - number of packet mode changes
6950    # 8 - int8u - bytes per packet
6951);
6952
6953%Image::ExifTool::QuickTime::ProtectionInfo = (
6954    PROCESS_PROC => \&ProcessMOV,
6955    GROUPS => { 2 => 'Audio' },
6956    NOTES => 'Child atoms found in "sinf" and/or "pinf" atoms.',
6957    frma => 'OriginalFormat',
6958    # imif - IPMP information
6959    schm => {
6960        Name => 'SchemeType',
6961        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::SchemeType' },
6962    },
6963    schi => {
6964        Name => 'SchemeInfo',
6965        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::SchemeInfo' },
6966    },
6967    enda => {
6968        Name => 'Endianness',
6969        Format => 'int16u',
6970        PrintConv => {
6971            0 => 'Big-endian (Motorola, MM)',
6972            1 => 'Little-endian (Intel, II)',
6973        },
6974    },
6975    # skcr
6976);
6977
6978%Image::ExifTool::QuickTime::Wave = (
6979    PROCESS_PROC => \&ProcessMOV,
6980    frma => 'PurchaseFileFormat',
6981    enda => {
6982        Name => 'Endianness',
6983        Format => 'int16u',
6984        PrintConv => {
6985            0 => 'Big-endian (Motorola, MM)',
6986            1 => 'Little-endian (Intel, II)',
6987        },
6988    },
6989    # "ms\0\x11" - 20 bytes
6990);
6991
6992# audio channel layout (ref CoreAudioTypes.h)
6993%Image::ExifTool::QuickTime::ChannelLayout = (
6994    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
6995    GROUPS => { 2 => 'Audio' },
6996    DATAMEMBER => [ 0, 8 ],
6997    NOTES => 'Audio channel layout.',
6998    # 0 - version and flags
6999    4 => {
7000        Name => 'LayoutFlags',
7001        Format => 'int16u',
7002        RawConv => '$$self{LayoutFlags} = $val',
7003        PrintConvColumns => 2,
7004        PrintConv => {
7005            0 => 'UseDescriptions',
7006            1 => 'UseBitmap',
7007            100 => 'Mono',
7008            101 => 'Stereo',
7009            102 => 'StereoHeadphones',
7010            100 => 'Mono',
7011            101 => 'Stereo',
7012            102 => 'StereoHeadphones',
7013            103 => 'MatrixStereo',
7014            104 => 'MidSide',
7015            105 => 'XY',
7016            106 => 'Binaural',
7017            107 => 'Ambisonic_B_Format',
7018            108 => 'Quadraphonic',
7019            109 => 'Pentagonal',
7020            110 => 'Hexagonal',
7021            111 => 'Octagonal',
7022            112 => 'Cube',
7023            113 => 'MPEG_3_0_A',
7024            114 => 'MPEG_3_0_B',
7025            115 => 'MPEG_4_0_A',
7026            116 => 'MPEG_4_0_B',
7027            117 => 'MPEG_5_0_A',
7028            118 => 'MPEG_5_0_B',
7029            119 => 'MPEG_5_0_C',
7030            120 => 'MPEG_5_0_D',
7031            121 => 'MPEG_5_1_A',
7032            122 => 'MPEG_5_1_B',
7033            123 => 'MPEG_5_1_C',
7034            124 => 'MPEG_5_1_D',
7035            125 => 'MPEG_6_1_A',
7036            126 => 'MPEG_7_1_A',
7037            127 => 'MPEG_7_1_B',
7038            128 => 'MPEG_7_1_C',
7039            129 => 'Emagic_Default_7_1',
7040            130 => 'SMPTE_DTV',
7041            131 => 'ITU_2_1',
7042            132 => 'ITU_2_2',
7043            133 => 'DVD_4',
7044            134 => 'DVD_5',
7045            135 => 'DVD_6',
7046            136 => 'DVD_10',
7047            137 => 'DVD_11',
7048            138 => 'DVD_18',
7049            139 => 'AudioUnit_6_0',
7050            140 => 'AudioUnit_7_0',
7051            141 => 'AAC_6_0',
7052            142 => 'AAC_6_1',
7053            143 => 'AAC_7_0',
7054            144 => 'AAC_Octagonal',
7055            145 => 'TMH_10_2_std',
7056            146 => 'TMH_10_2_full',
7057            147 => 'DiscreteInOrder',
7058            148 => 'AudioUnit_7_0_Front',
7059            149 => 'AC3_1_0_1',
7060            150 => 'AC3_3_0',
7061            151 => 'AC3_3_1',
7062            152 => 'AC3_3_0_1',
7063            153 => 'AC3_2_1_1',
7064            154 => 'AC3_3_1_1',
7065            155 => 'EAC_6_0_A',
7066            156 => 'EAC_7_0_A',
7067            157 => 'EAC3_6_1_A',
7068            158 => 'EAC3_6_1_B',
7069            159 => 'EAC3_6_1_C',
7070            160 => 'EAC3_7_1_A',
7071            161 => 'EAC3_7_1_B',
7072            162 => 'EAC3_7_1_C',
7073            163 => 'EAC3_7_1_D',
7074            164 => 'EAC3_7_1_E',
7075            165 => 'EAC3_7_1_F',
7076            166 => 'EAC3_7_1_G',
7077            167 => 'EAC3_7_1_H',
7078            168 => 'DTS_3_1',
7079            169 => 'DTS_4_1',
7080            170 => 'DTS_6_0_A',
7081            171 => 'DTS_6_0_B',
7082            172 => 'DTS_6_0_C',
7083            173 => 'DTS_6_1_A',
7084            174 => 'DTS_6_1_B',
7085            175 => 'DTS_6_1_C',
7086            176 => 'DTS_7_0',
7087            177 => 'DTS_7_1',
7088            178 => 'DTS_8_0_A',
7089            179 => 'DTS_8_0_B',
7090            180 => 'DTS_8_1_A',
7091            181 => 'DTS_8_1_B',
7092            182 => 'DTS_6_1_D',
7093            183 => 'AAC_7_1_B',
7094            0xffff => 'Unknown',
7095        },
7096    },
7097    6  => {
7098        Name => 'AudioChannels',
7099        Condition => '$$self{LayoutFlags} != 0 and $$self{LayoutFlags} != 1',
7100        Format => 'int16u',
7101    },
7102    8 => {
7103        Name => 'AudioChannelTypes',
7104        Condition => '$$self{LayoutFlags} == 1',
7105        Format => 'int32u',
7106        PrintConv => { BITMASK => {
7107            0 => 'Left',
7108            1 => 'Right',
7109            2 => 'Center',
7110            3 => 'LFEScreen',
7111            4 => 'LeftSurround',
7112            5 => 'RightSurround',
7113            6 => 'LeftCenter',
7114            7 => 'RightCenter',
7115            8 => 'CenterSurround',
7116            9 => 'LeftSurroundDirect',
7117            10 => 'RightSurroundDirect',
7118            11 => 'TopCenterSurround',
7119            12 => 'VerticalHeightLeft',
7120            13 => 'VerticalHeightCenter',
7121            14 => 'VerticalHeightRight',
7122            15 => 'TopBackLeft',
7123            16 => 'TopBackCenter',
7124            17 => 'TopBackRight',
7125        }},
7126    },
7127    12  => {
7128        Name => 'NumChannelDescriptions',
7129        Condition => '$$self{LayoutFlags} == 1',
7130        Format => 'int32u',
7131        RawConv => '$$self{NumChannelDescriptions} = $val',
7132    },
7133    16 => {
7134        Name => 'Channel1Label',
7135        Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 0',
7136        Format => 'int32u',
7137        SeparateTable => 'ChannelLabel',
7138        PrintConv => \%channelLabel,
7139    },
7140    20 => {
7141        Name => 'Channel1Flags',
7142        Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 0',
7143        Format => 'int32u',
7144        PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }},
7145    },
7146    24 => {
7147        Name => 'Channel1Coordinates',
7148        Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 0',
7149        Notes => q{
7150            3 numbers:  for rectangular coordinates left/right, back/front, down/up; for
7151            spherical coordinates left/right degrees, down/up degrees, distance
7152        },
7153        Format => 'float[3]',
7154    },
7155    36 => {
7156        Name => 'Channel2Label',
7157        Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 1',
7158        Format => 'int32u',
7159        SeparateTable => 'ChannelLabel',
7160        PrintConv => \%channelLabel,
7161    },
7162    40 => {
7163        Name => 'Channel2Flags',
7164        Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 1',
7165        Format => 'int32u',
7166        PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }},
7167    },
7168    44 => {
7169        Name => 'Channel2Coordinates',
7170        Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 1',
7171        Format => 'float[3]',
7172    },
7173    56 => {
7174        Name => 'Channel3Label',
7175        Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 2',
7176        Format => 'int32u',
7177        SeparateTable => 'ChannelLabel',
7178        PrintConv => \%channelLabel,
7179    },
7180    60 => {
7181        Name => 'Channel3Flags',
7182        Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 2',
7183        Format => 'int32u',
7184        PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }},
7185    },
7186    64 => {
7187        Name => 'Channel3Coordinates',
7188        Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 2',
7189        Format => 'float[3]',
7190    },
7191    76 => {
7192        Name => 'Channel4Label',
7193        Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 3',
7194        Format => 'int32u',
7195        SeparateTable => 'ChannelLabel',
7196        PrintConv => \%channelLabel,
7197    },
7198    80 => {
7199        Name => 'Channel4Flags',
7200        Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 3',
7201        Format => 'int32u',
7202        PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }},
7203    },
7204    84 => {
7205        Name => 'Channel4Coordinates',
7206        Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 3',
7207        Format => 'float[3]',
7208    },
7209    96 => {
7210        Name => 'Channel5Label',
7211        Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 4',
7212        Format => 'int32u',
7213        SeparateTable => 'ChannelLabel',
7214        PrintConv => \%channelLabel,
7215    },
7216    100 => {
7217        Name => 'Channel5Flags',
7218        Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 4',
7219        Format => 'int32u',
7220        PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }},
7221    },
7222    104 => {
7223        Name => 'Channel5Coordinates',
7224        Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 4',
7225        Format => 'float[3]',
7226    },
7227    116 => {
7228        Name => 'Channel6Label',
7229        Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 5',
7230        Format => 'int32u',
7231        SeparateTable => 'ChannelLabel',
7232        PrintConv => \%channelLabel,
7233    },
7234    120 => {
7235        Name => 'Channel6Flags',
7236        Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 5',
7237        Format => 'int32u',
7238        PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }},
7239    },
7240    124 => {
7241        Name => 'Channel6Coordinates',
7242        Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 5',
7243        Format => 'float[3]',
7244    },
7245    136 => {
7246        Name => 'Channel7Label',
7247        Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 6',
7248        Format => 'int32u',
7249        SeparateTable => 'ChannelLabel',
7250        PrintConv => \%channelLabel,
7251    },
7252    140 => {
7253        Name => 'Channel7Flags',
7254        Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 6',
7255        Format => 'int32u',
7256        PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }},
7257    },
7258    144 => {
7259        Name => 'Channel7Coordinates',
7260        Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 6',
7261        Format => 'float[3]',
7262    },
7263    156 => {
7264        Name => 'Channel8Label',
7265        Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 7',
7266        Format => 'int32u',
7267        SeparateTable => 'ChannelLabel',
7268        PrintConv => \%channelLabel,
7269    },
7270    160 => {
7271        Name => 'Channel8Flags',
7272        Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 7',
7273        Format => 'int32u',
7274        PrintConv => { BITMASK => { 0 => 'Rectangular', 1 => 'Spherical', 2 => 'Meters' }},
7275    },
7276    164 => {
7277        Name => 'Channel8Coordinates',
7278        Condition => '$$self{LayoutFlags} == 1 and $$self{NumChannelDescriptions} > 7',
7279        Format => 'float[3]',
7280    },
7281    # (arbitrarily decode only first 8 channels)
7282);
7283
7284# scheme type atom
7285# ref http://xhelmboyx.tripod.com/formats/mp4-layout.txt
7286%Image::ExifTool::QuickTime::SchemeType = (
7287    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
7288    GROUPS => { 2 => 'Audio' },
7289    # 0 - 4 bytes version
7290    4 => { Name => 'SchemeType',    Format => 'undef[4]' },
7291    8 => { Name => 'SchemeVersion', Format => 'int16u' },
7292    10 => { Name => 'SchemeURL',    Format => 'string[$size-10]' },
7293);
7294
7295%Image::ExifTool::QuickTime::SchemeInfo = (
7296    PROCESS_PROC => \&ProcessMOV,
7297    GROUPS => { 2 => 'Audio' },
7298    user => {
7299        Name => 'UserID',
7300        Groups => { 2 => 'Author' },
7301        ValueConv => '"0x" . unpack("H*",$val)',
7302    },
7303    cert => { # ref http://www.onvif.org/specs/stream/ONVIF-ExportFileFormat-Spec-v100.pdf
7304        Name => 'Certificate',
7305        ValueConv => '"0x" . unpack("H*",$val)',
7306    },
7307    'key ' => {
7308        Name => 'KeyID',
7309        ValueConv => '"0x" . unpack("H*",$val)',
7310    },
7311    iviv => {
7312        Name => 'InitializationVector',
7313        ValueConv => 'unpack("H*",$val)',
7314    },
7315    righ => {
7316        Name => 'Rights',
7317        Groups => { 2 => 'Author' },
7318        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Rights' },
7319    },
7320    name => { Name => 'UserName', Groups => { 2 => 'Author' } },
7321    # chtb
7322    # priv - private data
7323    # sign
7324    # adkm - Adobe DRM key management system (ref http://download.macromedia.com/f4v/video_file_format_spec_v10_1.pdf)
7325    # iKMS
7326    # iSFM
7327    # iSLT
7328);
7329
7330%Image::ExifTool::QuickTime::Rights = (
7331    PROCESS_PROC => \&ProcessRights,
7332    GROUPS => { 2 => 'Audio' },
7333    veID => 'ItemVendorID', #PH ("VendorID" ref 19)
7334    plat => 'Platform', #18?
7335    aver => 'VersionRestrictions', #19 ("appversion?" ref 18)
7336    tran => 'TransactionID', #18
7337    song => 'ItemID', #19 ("appid" ref 18)
7338    tool => {
7339        Name => 'ItemTool', #PH (guess) ("itunes build?" ref 18)
7340        Format => 'string',
7341    },
7342    medi => 'MediaFlags', #PH (?)
7343    mode => 'ModeFlags', #PH (?) 0x04 is HD flag (https://compilr.com/heksesang/requiem-mac/UnDrm.java)
7344);
7345
7346# MP4 hint sample description box (ref 5)
7347# (ref https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html#//apple_ref/doc/uid/TP40000939-CH205-SW1)
7348%Image::ExifTool::QuickTime::HintSampleDesc = (
7349    PROCESS_PROC => \&ProcessHybrid,
7350    VARS => { ID_LABEL => 'ID/Index' },
7351    NOTES => 'MP4 hint sample description.',
7352    4  => { Name => 'HintFormat', Format => 'undef[4]' },
7353    # 14 - int16u DataReferenceIndex
7354    16 => { Name => 'HintTrackVersion', Format => 'int16u' },
7355    # 18 - int16u LastCompatibleHintTrackVersion
7356    20 => { Name => 'MaxPacketSize', Format => 'int32u' },
7357#
7358# Observed offsets for child atoms of various HintFormat types:
7359#
7360#   HintFormat   Offset  Child atoms
7361#   -----------  ------  ----------------
7362#   "rtp "       24      tims
7363#
7364    tims => { Name => 'RTPTimeScale',               Format => 'int32u' },
7365    tsro => { Name => 'TimestampRandomOffset',      Format => 'int32u' },
7366    snro => { Name => 'SequenceNumberRandomOffset', Format => 'int32u' },
7367);
7368
7369# MP4 metadata sample description box
7370%Image::ExifTool::QuickTime::MetaSampleDesc = (
7371    PROCESS_PROC => \&ProcessHybrid,
7372    NOTES => 'MP4 metadata sample description.',
7373    4 => {
7374        Name => 'MetaFormat',
7375        Format => 'undef[4]',
7376        RawConv => '$$self{MetaFormat} = $val',
7377    },
7378#
7379# Observed offsets for child atoms of various MetaFormat types:
7380#
7381#   MetaFormat   Offset  Child atoms
7382#   -----------  ------  ----------------
7383#   mebx         24      keys,btrt,lidp,lidl
7384#   fdsc         -       -
7385#   gpmd         -       -
7386#   rtmd         -       -
7387#   CTMD         -       -
7388#
7389   'keys' => { #PH (iPhone7+ hevc)
7390        Name => 'Keys',
7391        SubDirectory => {
7392            TagTable => 'Image::ExifTool::QuickTime::Keys',
7393            ProcessProc => \&ProcessMetaKeys,
7394        },
7395    },
7396    btrt => {
7397        Name => 'BitrateInfo',
7398        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Bitrate' },
7399    },
7400);
7401
7402# MP4 generic sample description box
7403%Image::ExifTool::QuickTime::OtherSampleDesc = (
7404    PROCESS_PROC => \&ProcessHybrid,
7405    4 => {
7406        Name => 'OtherFormat',
7407        Format => 'undef[4]',
7408        RawConv => '$$self{MetaFormat} = $val', # (yes, use MetaFormat for this too)
7409    },
7410#
7411# Observed offsets for child atoms of various OtherFormat types:
7412#
7413#   OtherFormat  Offset  Child atoms
7414#   -----------  ------  ----------------
7415#   avc1         86      avcC
7416#   mp4a         36      esds
7417#   mp4s         16      esds
7418#   tmcd         34      name
7419#   data         -       -
7420#
7421    ftab => { Name => 'FontTable',  Format => 'undef', ValueConv => 'substr($val, 5)' },
7422    name => { Name => 'OtherName',  Format => 'undef', ValueConv => 'substr($val, 4)' },
7423    # mrlh = GM header?
7424    # mrlv = GM data
7425    # mrld = GM data (448-byte records):
7426    #            0 - int32u count
7427    #            4 - int32u ? (related to units) 0=none,1=m/km,2=L,3=kph,4=C,7=deg,8=rpm,9=kPa,10=G,11=V,15=Nm,16=%
7428    #            8 - int32u ? (0,1,3,4,5)
7429    #           12 - string[64] units
7430    #           76 - int32u ? (1,3,7,15)
7431    #           80 - int32u 0
7432    #           84 - undef[4] ?
7433    #           88 - int16u[6] ?
7434    #           100 - undef[32] ?
7435    #           132 - string[64] measurement name
7436    #           196 - string[64] measurement name
7437);
7438
7439# MP4 data information box (ref 5)
7440%Image::ExifTool::QuickTime::DataInfo = (
7441    PROCESS_PROC => \&ProcessMOV,
7442    WRITE_PROC => \&WriteQuickTime, # (necessary to parse dref even though we don't change it)
7443    NOTES => 'MP4 data information box.',
7444    dref => {
7445        Name => 'DataRef',
7446        SubDirectory => {
7447            TagTable => 'Image::ExifTool::QuickTime::DataRef',
7448            Start => 8,
7449        },
7450    },
7451);
7452
7453# Generic media header
7454%Image::ExifTool::QuickTime::GenMediaHeader = (
7455    PROCESS_PROC => \&ProcessMOV,
7456    gmin => {
7457        Name => 'GenMediaInfo',
7458        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::GenMediaInfo' },
7459    },
7460    text => {
7461        Name => 'Text',
7462        Flags => ['Binary','Unknown'],
7463    },
7464    tmcd => {
7465        Name => 'TimeCode',
7466        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TimeCode' },
7467    },
7468);
7469
7470# TimeCode header
7471%Image::ExifTool::QuickTime::TimeCode = (
7472    PROCESS_PROC => \&ProcessMOV,
7473    tcmi => {
7474        Name => 'TCMediaInfo',
7475        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TCMediaInfo' },
7476    },
7477);
7478
7479# TimeCode media info (ref 12)
7480%Image::ExifTool::QuickTime::TCMediaInfo = (
7481    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
7482    GROUPS => { 2 => 'Video' },
7483    4 => {
7484        Name => 'TextFont',
7485        Format => 'int16u',
7486        PrintConv => { 0 => 'System' },
7487    },
7488    6 => {
7489        Name => 'TextFace',
7490        Format => 'int16u',
7491        PrintConv => {
7492            0 => 'Plain',
7493            BITMASK => {
7494                0 => 'Bold',
7495                1 => 'Italic',
7496                2 => 'Underline',
7497                3 => 'Outline',
7498                4 => 'Shadow',
7499                5 => 'Condense',
7500                6 => 'Extend',
7501            },
7502        },
7503    },
7504    8 => {
7505        Name => 'TextSize',
7506        Format => 'int16u',
7507    },
7508    # 10 - reserved
7509    12 => {
7510        Name => 'TextColor',
7511        Format => 'int16u[3]',
7512    },
7513    18 => {
7514        Name => 'BackgroundColor',
7515        Format => 'int16u[3]',
7516    },
7517    24 => {
7518        Name => 'FontName',
7519        Format => 'pstring',
7520        ValueConv => '$self->Decode($val, $self->Options("CharsetQuickTime"))',
7521    },
7522);
7523
7524# Generic media info (ref http://sourceforge.jp/cvs/view/ntvrec/ntvrec/libqtime/gmin.h?view=co)
7525%Image::ExifTool::QuickTime::GenMediaInfo = (
7526    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
7527    GROUPS => { 2 => 'Video' },
7528    0  => 'GenMediaVersion',
7529    1  => { Name => 'GenFlags',   Format => 'int8u[3]' },
7530    4  => { Name => 'GenGraphicsMode',
7531        Format => 'int16u',
7532        PrintHex => 1,
7533        SeparateTable => 'GraphicsMode',
7534        PrintConv => \%graphicsMode,
7535    },
7536    6  => { Name => 'GenOpColor', Format => 'int16u[3]' },
7537    12 => { Name => 'GenBalance', Format => 'fixed16s' },
7538);
7539
7540# MP4 data reference box (ref 5)
7541%Image::ExifTool::QuickTime::DataRef = (
7542    PROCESS_PROC => \&ProcessMOV,
7543    WRITE_PROC => \&WriteQuickTime, # (necessary to parse dref even though we don't change it)
7544    NOTES => 'MP4 data reference box.',
7545    'url ' => {
7546        Name => 'URL',
7547        Format => 'undef',  # (necessary to prevent decoding as string!)
7548        RawConv => q{
7549            # ignore if self-contained (flags bit 0 set)
7550            return undef if unpack("N",$val) & 0x01;
7551            $_ = substr($val,4); s/\0.*//s; $_;
7552        },
7553    },
7554    "url\0" => { # (written by GoPro)
7555        Name => 'URL',
7556        Format => 'undef',  # (necessary to prevent decoding as string!)
7557        RawConv => q{
7558            # ignore if self-contained (flags bit 0 set)
7559            return undef if unpack("N",$val) & 0x01;
7560            $_ = substr($val,4); s/\0.*//s; $_;
7561        },
7562    },
7563    'urn ' => {
7564        Name => 'URN',
7565        Format => 'undef',  # (necessary to prevent decoding as string!)
7566        RawConv => q{
7567            return undef if unpack("N",$val) & 0x01;
7568            $_ = substr($val,4); s/\0+/; /; s/\0.*//s; $_;
7569        },
7570    },
7571);
7572
7573# MP4 handler box (ref 5)
7574%Image::ExifTool::QuickTime::Handler = (
7575    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
7576    GROUPS => { 2 => 'Video' },
7577    4 => { #PH
7578        Name => 'HandlerClass',
7579        Format => 'undef[4]',
7580        RawConv => '$val eq "\0\0\0\0" ? undef : $val',
7581        PrintConv => {
7582            mhlr => 'Media Handler',
7583            dhlr => 'Data Handler',
7584        },
7585    },
7586    8 => {
7587        Name => 'HandlerType',
7588        Format => 'undef[4]',
7589        RawConv => '$$self{HandlerType} = $val unless $val eq "alis" or $val eq "url "; $val',
7590        PrintConvColumns => 2,
7591        PrintConv => {
7592            alis => 'Alias Data', #PH
7593            crsm => 'Clock Reference', #3
7594            hint => 'Hint Track',
7595            ipsm => 'IPMP', #3
7596            m7sm => 'MPEG-7 Stream', #3
7597            meta => 'NRT Metadata', #PH
7598            mdir => 'Metadata', #3
7599            mdta => 'Metadata Tags', #PH
7600            mjsm => 'MPEG-J', #3
7601            ocsm => 'Object Content', #3
7602            odsm => 'Object Descriptor', #3
7603            priv => 'Private', #PH
7604            sdsm => 'Scene Description', #3
7605            soun => 'Audio Track',
7606            text => 'Text', #PH (but what type? subtitle?)
7607            tmcd => 'Time Code', #PH
7608           'url '=> 'URL', #3
7609            vide => 'Video Track',
7610            subp => 'Subpicture', #http://www.google.nl/patents/US7778526
7611            nrtm => 'Non-Real Time Metadata', #PH (Sony ILCE-7S) [how is this different from "meta"?]
7612            pict => 'Picture', # (HEIC images)
7613            camm => 'Camera Metadata', # (Insta360 MP4)
7614            psmd => 'Panasonic Static Metadata', #PH (Leica C-Lux CAM-DC25)
7615            data => 'Data', #PH (GPS and G-sensor data from DataKam)
7616            sbtl => 'Subtitle', #PH (TomTom Bandit Action Cam)
7617        },
7618    },
7619    12 => { #PH
7620        Name => 'HandlerVendorID',
7621        Format => 'undef[4]',
7622        RawConv => '$val eq "\0\0\0\0" ? undef : $val',
7623        PrintConv => \%vendorID,
7624        SeparateTable => 'VendorID',
7625    },
7626    24 => {
7627        Name => 'HandlerDescription',
7628        Format => 'string',
7629        # (sometimes this is a Pascal string, and sometimes it is a C string)
7630        RawConv => q{
7631            $val=substr($val,1,ord($1)) if $val=~/^([\0-\x1f])/ and ord($1)<length($val);
7632            length $val ? $val : undef;
7633        },
7634    },
7635);
7636
7637# Flip uuid data (ref PH)
7638%Image::ExifTool::QuickTime::Flip = (
7639    PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
7640    FORMAT => 'int32u',
7641    FIRST_ENTRY => 0,
7642    NOTES => 'Found in MP4 files from Flip Video cameras.',
7643    GROUPS => { 1 => 'MakerNotes', 2 => 'Image' },
7644    1 => 'PreviewImageWidth',
7645    2 => 'PreviewImageHeight',
7646    13 => 'PreviewImageLength',
7647    14 => { # (confirmed for FlipVideoMinoHD)
7648        Name => 'SerialNumber',
7649        Groups => { 2 => 'Camera' },
7650        Format => 'string[16]',
7651    },
7652    28 => {
7653        Name => 'PreviewImage',
7654        Groups => { 2 => 'Preview' },
7655        Format => 'undef[$val{13}]',
7656        RawConv => '$self->ValidateImage(\$val, $tag)',
7657    },
7658);
7659
7660# atoms in Pittasoft "free" atom
7661%Image::ExifTool::QuickTime::Pittasoft = (
7662    PROCESS_PROC => \&ProcessMOV,
7663    NOTES => 'Tags found in Pittasoft Blackvue dashcam "free" data.',
7664    cprt => 'Copyright',
7665    thum => {
7666        Name => 'PreviewImage',
7667        Groups => { 2 => 'Preview' },
7668        Binary => 1,
7669        RawConv => q{
7670            return undef unless length $val > 4;
7671            my $len = unpack('N', $val);
7672            return undef unless length $val >= 4 + $len;
7673            return substr($val, 4, $len);
7674        },
7675    },
7676    ptnm => {
7677        Name => 'OriginalFileName',
7678        ValueConv => 'substr($val, 4, -1)',
7679    },
7680    ptrh => {
7681        SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Pittasoft' },
7682        # contains these atoms:
7683        # ptvi - 27 bytes: '..avc1...'
7684        # ptso - 16 bytes: '..mp4a...'
7685    },
7686    'gps ' => {
7687        Name => 'GPSLog',
7688        Binary => 1,    # (ASCII NMEA track log with leading timestamps)
7689        Notes => 'parsed to extract GPS separately when ExtractEmbedded is used',
7690        RawConv => q{
7691            $val =~ s/\0+$//;   # remove trailing nulls
7692            if (length $val and $$self{OPTIONS}{ExtractEmbedded}) {
7693                my $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream');
7694                Image::ExifTool::QuickTime::ProcessNMEA($self, { DataPt => \$val }, $tagTbl);
7695            }
7696            return $val;
7697        },
7698    },
7699    '3gf ' => {
7700        Name => 'AccelData',
7701        SubDirectory => {
7702            TagTable => 'Image::ExifTool::QuickTime::Stream',
7703            ProcessProc => \&Process_3gf,
7704        },
7705    },
7706    sttm => {
7707        Name => 'StartTime',
7708        Format => 'int64u',
7709        Groups => { 2 => 'Time' },
7710        RawConv => '$$self{StartTime} = $val',
7711        # (ms since Jan 1, 1970, in local time zone - PH)
7712        ValueConv => q{
7713            my $secs = int($val / 1000);
7714            return ConvertUnixTime($secs) . sprintf(".%03d",$val - $secs * 1000);
7715        },
7716        PrintConv => '$self->ConvertDateTime($val)',
7717    },
7718);
7719
7720# QuickTime composite tags
7721%Image::ExifTool::QuickTime::Composite = (
7722    GROUPS => { 2 => 'Video' },
7723    Rotation => {
7724        Notes => q{
7725            writing this tag updates QuickTime MatrixStructure for all tracks with a
7726            non-zero image size
7727        },
7728        Require => {
7729            0 => 'QuickTime:MatrixStructure',
7730            1 => 'QuickTime:HandlerType',
7731        },
7732        Writable => 1,
7733        Protected => 1,
7734        WriteAlso => {
7735            MatrixStructure => 'Image::ExifTool::QuickTime::GetRotationMatrix($val)',
7736        },
7737        ValueConv => 'Image::ExifTool::QuickTime::CalcRotation($self)',
7738        ValueConvInv => '$val',
7739    },
7740    AvgBitrate => {
7741        Priority => 0,  # let QuickTime::AvgBitrate take priority
7742        Require => {
7743            0 => 'QuickTime::MediaDataSize',
7744            1 => 'QuickTime::Duration',
7745        },
7746        RawConv => q{
7747            return undef unless $val[1];
7748            $val[1] /= $$self{TimeScale} if $$self{TimeScale};
7749            my $key = 'MediaDataSize';
7750            my $size = $val[0];
7751            for (;;) {
7752                $key = $self->NextTagKey($key) or last;
7753                $size += $self->GetValue($key, 'ValueConv');
7754            }
7755            return int($size * 8 / $val[1] + 0.5);
7756        },
7757        PrintConv => 'ConvertBitrate($val)',
7758    },
7759    GPSLatitude => {
7760        Require => 'QuickTime:GPSCoordinates',
7761        Groups => { 2 => 'Location' },
7762        ValueConv => 'my @c = split " ", $val; $c[0]',
7763        PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")',
7764    },
7765    GPSLongitude => {
7766        Require => 'QuickTime:GPSCoordinates',
7767        Groups => { 2 => 'Location' },
7768        ValueConv => 'my @c = split " ", $val; $c[1]',
7769        PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")',
7770    },
7771    # split altitude into GPSAltitude/GPSAltitudeRef like EXIF and XMP
7772    GPSAltitude => {
7773        Require => 'QuickTime:GPSCoordinates',
7774        Groups => { 2 => 'Location' },
7775        Priority => 0, # (because it may not exist)
7776        ValueConv => 'my @c = split " ", $val; defined $c[2] ? abs($c[2]) : undef',
7777        PrintConv => '"$val m"',
7778    },
7779    GPSAltitudeRef  => {
7780        Require => 'QuickTime:GPSCoordinates',
7781        Groups => { 2 => 'Location' },
7782        Priority => 0, # (because altitude information may not exist)
7783        ValueConv => 'my @c = split " ", $val; defined $c[2] ? ($c[2] < 0 ? 1 : 0) : undef',
7784        PrintConv => {
7785            0 => 'Above Sea Level',
7786            1 => 'Below Sea Level',
7787        },
7788    },
7789    GPSLatitude2 => {
7790        Name => 'GPSLatitude',
7791        Require => 'QuickTime:LocationInformation',
7792        Groups => { 2 => 'Location' },
7793        ValueConv => '$val =~ /Lat=([-+.\d]+)/; $1',
7794        PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")',
7795    },
7796    GPSLongitude2 => {
7797        Name => 'GPSLongitude',
7798        Require => 'QuickTime:LocationInformation',
7799        Groups => { 2 => 'Location' },
7800        ValueConv => '$val =~ /Lon=([-+.\d]+)/; $1',
7801        PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")',
7802    },
7803    GPSAltitude2 => {
7804        Name => 'GPSAltitude',
7805        Require => 'QuickTime:LocationInformation',
7806        Groups => { 2 => 'Location' },
7807        ValueConv => '$val =~ /Alt=([-+.\d]+)/; abs($1)',
7808        PrintConv => '"$val m"',
7809    },
7810    GPSAltitudeRef2  => {
7811        Name => 'GPSAltitudeRef',
7812        Require => 'QuickTime:LocationInformation',
7813        Groups => { 2 => 'Location' },
7814        ValueConv => '$val =~ /Alt=([-+.\d]+)/; $1 < 0 ? 1 : 0',
7815        PrintConv => {
7816            0 => 'Above Sea Level',
7817            1 => 'Below Sea Level',
7818        },
7819    },
7820    CDDBDiscPlayTime => {
7821        Require => 'CDDB1Info',
7822        Groups => { 2 => 'Audio' },
7823        ValueConv => '$val =~ /^..([a-z0-9]{4})/i ? hex($1) : undef',
7824        PrintConv => 'ConvertDuration($val)',
7825    },
7826    CDDBDiscTracks => {
7827        Require => 'CDDB1Info',
7828        Groups => { 2 => 'Audio' },
7829        ValueConv => '$val =~ /^.{6}([a-z0-9]{2})/i ? hex($1) : undef',
7830    },
7831);
7832
7833# add our composite tags
7834Image::ExifTool::AddCompositeTags('Image::ExifTool::QuickTime');
7835
7836
7837#------------------------------------------------------------------------------
7838# AutoLoad our routines when necessary
7839#
7840sub AUTOLOAD
7841{
7842    # (Note: no need to autoload routines in QuickTimeStream that use Stream table)
7843    if ($AUTOLOAD eq 'Image::ExifTool::QuickTime::Process_mebx') {
7844        require 'Image/ExifTool/QuickTimeStream.pl';
7845        no strict 'refs';
7846        return &$AUTOLOAD(@_);
7847    } else {
7848        return Image::ExifTool::DoAutoLoad($AUTOLOAD, @_);
7849    }
7850}
7851
7852#------------------------------------------------------------------------------
7853# Get rotation matrix
7854# Inputs: 0) angle in degrees
7855# Returns: 9-element rotation matrix as a string (with 0 x/y offsets)
7856sub GetRotationMatrix($)
7857{
7858    my $ang = 3.1415926536 * shift() / 180;
7859    my $cos = cos $ang;
7860    my $sin = sin $ang;
7861    my $msn = -$sin;
7862    return "$cos $sin 0 $msn $cos 0 0 0 1";
7863}
7864
7865#------------------------------------------------------------------------------
7866# Get rotation angle from a matrix
7867# Inputs: 0) rotation matrix as a string
7868# Return: positive rotation angle in degrees rounded to 3 decimal points,
7869#         or undef on error
7870sub GetRotationAngle($)
7871{
7872    my $rotMatrix = shift;
7873    my @a = split ' ', $rotMatrix;
7874    return undef if $a[0]==0 and $a[1]==0;
7875    # calculate the rotation angle (assume uniform rotation)
7876    my $angle = atan2($a[1], $a[0]) * 180 / 3.14159;
7877    $angle += 360 if $angle < 0;
7878    return int($angle * 1000 + 0.5) / 1000;
7879}
7880
7881#------------------------------------------------------------------------------
7882# Calculate rotation of video track
7883# Inputs: 0) ExifTool object ref
7884# Returns: rotation angle or undef
7885sub CalcRotation($)
7886{
7887    my $et = shift;
7888    my $value = $$et{VALUE};
7889    my ($i, $track);
7890    # get the video track family 1 group (eg. "Track1");
7891    for ($i=0; ; ++$i) {
7892        my $idx = $i ? " ($i)" : '';
7893        my $tag = "HandlerType$idx";
7894        last unless $$value{$tag};
7895        next unless $$value{$tag} eq 'vide';
7896        $track = $et->GetGroup($tag, 1);
7897        last;
7898    }
7899    return undef unless $track;
7900    # get the video track matrix
7901    for ($i=0; ; ++$i) {
7902        my $idx = $i ? " ($i)" : '';
7903        my $tag = "MatrixStructure$idx";
7904        last unless $$value{$tag};
7905        next unless $et->GetGroup($tag, 1) eq $track;
7906        return GetRotationAngle($$value{$tag});
7907    }
7908    return undef;
7909}
7910
7911#------------------------------------------------------------------------------
7912# Get MatrixStructure for a given rotation angle
7913# Inputs: 0) rotation angle (deg), 1) ExifTool ref
7914# Returns: matrix structure as a string, or undef if it can't be rotated
7915# - requires ImageSizeLookahead to determine the video image size, and doesn't
7916#   rotate matrix unless image size is valid
7917sub GetMatrixStructure($$)
7918{
7919    my ($val, $et) = @_;
7920    my @a = split ' ', $val;
7921    # pass straight through if it already has an offset
7922    return $val unless $a[6] == 0 and $a[7] == 0;
7923    my @s = split ' ', $$et{ImageSizeLookahead};
7924    my ($w, $h) = @s[12,13];
7925    return undef unless $w and $h;  # don't rotate 0-sized track
7926    $_ = Image::ExifTool::QuickTime::FixWrongFormat($_) foreach $w,$h;
7927    # apply necessary offsets for the standard rotations
7928    my $angle = GetRotationAngle($val);
7929    return undef unless defined $angle;
7930    if ($angle == 90) {
7931        @a[6,7] = ($h, 0);
7932    } elsif ($angle == 180) {
7933        @a[6,7] = ($w, $h);
7934    } elsif ($angle == 270) {
7935        @a[6,7] = (0, $w);
7936    }
7937    return "@a";
7938}
7939
7940#------------------------------------------------------------------------------
7941# Determine the average sample rate from a time-to-sample table
7942# Inputs: 0) ExifTool object ref, 1) time-to-sample table data ref
7943# Returns: average sample rate (in Hz)
7944sub CalcSampleRate($$)
7945{
7946    my ($et, $valPt) = @_;
7947    my @dat = unpack('N*', $$valPt);
7948    my ($num, $dur) = (0, 0);
7949    my $i;
7950    for ($i=2; $i<@dat-1; $i+=2) {
7951        $num += $dat[$i];               # total number of samples
7952        $dur += $dat[$i] * $dat[$i+1];  # total sample duration
7953    }
7954    return undef unless $num and $dur and $$et{MediaTS};
7955    return $num * $$et{MediaTS} / $dur;
7956}
7957
7958#------------------------------------------------------------------------------
7959# Fix incorrect format for ImageWidth/Height as written by Pentax
7960sub FixWrongFormat($)
7961{
7962    my $val = shift;
7963    return undef unless $val;
7964    return $val & 0xfff00000 ? unpack('n',pack('N',$val)) : $val;
7965}
7966
7967#------------------------------------------------------------------------------
7968# Convert ISO 6709 string to standard lag/lon format
7969# Inputs: 0) ISO 6709 string (lat, lon, and optional alt)
7970# Returns: position in decimal degrees with altitude if available
7971# Notes: Wikipedia indicates altitude may be in feet -- how is this specified?
7972sub ConvertISO6709($)
7973{
7974    my $val = shift;
7975    if ($val =~ /^([-+]\d{1,2}(?:\.\d*)?)([-+]\d{1,3}(?:\.\d*)?)([-+]\d+(?:\.\d*)?)?/) {
7976        # +DD.DDD+DDD.DDD+AA.AAA
7977        $val = ($1 + 0) . ' ' . ($2 + 0);
7978        $val .= ' ' . ($3 + 0) if $3;
7979    } elsif ($val =~ /^([-+])(\d{2})(\d{2}(?:\.\d*)?)([-+])(\d{3})(\d{2}(?:\.\d*)?)([-+]\d+(?:\.\d*)?)?/) {
7980        # +DDMM.MMM+DDDMM.MMM+AA.AAA
7981        my $lat = $2 + $3 / 60;
7982        $lat = -$lat if $1 eq '-';
7983        my $lon = $5 + $6 / 60;
7984        $lon = -$lon if $4 eq '-';
7985        $val = "$lat $lon";
7986        $val .= ' ' . ($7 + 0) if $7;
7987    } elsif ($val =~ /^([-+])(\d{2})(\d{2})(\d{2}(?:\.\d*)?)([-+])(\d{3})(\d{2})(\d{2}(?:\.\d*)?)([-+]\d+(?:\.\d*)?)?/) {
7988        # +DDMMSS.SSS+DDDMMSS.SSS+AA.AAA
7989        my $lat = $2 + $3 / 60 + $4 / 3600;
7990        $lat = -$lat if $1 eq '-';
7991        my $lon = $6 + $7 / 60 + $8 / 3600;
7992        $lon = -$lon if $5 eq '-';
7993        $val = "$lat $lon";
7994        $val .= ' ' . ($9 + 0) if $9;
7995    }
7996    return $val;
7997}
7998
7999#------------------------------------------------------------------------------
8000# Convert Nero chapter list (ref ffmpeg libavformat/movenc.c)
8001# Inputs: 0) binary chpl data
8002# Returns: chapter list
8003sub ConvertChapterList($)
8004{
8005    my $val = shift;
8006    my $size = length $val;
8007    return '<invalid>' if $size < 9;
8008    my $num = Get8u(\$val, 8);
8009    my ($i, @chapters);
8010    my $pos = 9;
8011    for ($i=0; $i<$num; ++$i) {
8012        last if $pos + 9 > $size;
8013        my $dur = Get64u(\$val, $pos) / 10000000;
8014        my $len = Get8u(\$val, $pos + 8);
8015        last if $pos + 9 + $len > $size;
8016        my $title = substr($val, $pos + 9, $len);
8017        $pos += 9 + $len;
8018        push @chapters, "$dur $title";
8019    }
8020    return \@chapters;  # return as a list
8021}
8022
8023#------------------------------------------------------------------------------
8024# Print conversion for a Nero chapter list item
8025# Inputs: 0) ValueConv chapter string
8026# Returns: formatted chapter string
8027sub PrintChapter($)
8028{
8029    my $val = shift;
8030    $val =~ /^(\S+) (.*)/ or return $val;
8031    my ($dur, $title) = ($1, $2);
8032    my $h = int($dur / 3600);
8033    $dur -= $h * 3600;
8034    my $m = int($dur / 60);
8035    my $s = $dur - $m * 60;
8036    my $ss = sprintf('%06.3f', $s);
8037    if ($ss >= 60) {
8038        $ss = '00.000';
8039        ++$m >= 60 and $m -= 60, ++$h;
8040    }
8041    return sprintf("[%d:%.2d:%s] %s",$h,$m,$ss,$title);
8042}
8043
8044#------------------------------------------------------------------------------
8045# Format GPSCoordinates for printing
8046# Inputs: 0) string with numerical lat, lon and optional alt, separated by spaces
8047#         1) ExifTool object reference
8048# Returns: PrintConv value
8049sub PrintGPSCoordinates($)
8050{
8051    my ($val, $et) = @_;
8052    my @v = split ' ', $val;
8053    my $prt = Image::ExifTool::GPS::ToDMS($et, $v[0], 1, "N") . ', ' .
8054              Image::ExifTool::GPS::ToDMS($et, $v[1], 1, "E");
8055    if (defined $v[2]) {
8056        $prt .= ', ' . ($v[2] < 0 ? -$v[2] . ' m Below' : $v[2] . ' m Above') . ' Sea Level';
8057    }
8058    return $prt;
8059}
8060
8061#------------------------------------------------------------------------------
8062# Unpack packed ISO 639/T language code
8063# Inputs: 0) packed language code (or undef/0), 1) true to not treat 'und' and 'eng' as default
8064# Returns: language code, or undef/0 for default language, or 'err' for format error
8065sub UnpackLang($;$)
8066{
8067    my ($lang, $noDef) = @_;
8068    if ($lang) {
8069        # language code is packed in 5-bit characters
8070        $lang = pack 'C*', map { (($lang>>$_)&0x1f)+0x60 } 10, 5, 0;
8071        # validate language code
8072        if ($lang =~ /^[a-z]+$/) {
8073            # treat 'eng' or 'und' as the default language
8074            undef $lang if ($lang eq 'und' or $lang eq 'eng') and not $noDef;
8075        } else {
8076            $lang = 'err';  # invalid language code
8077        }
8078    }
8079    return $lang;
8080}
8081
8082#------------------------------------------------------------------------------
8083# Get language code string given QuickTime language and country codes
8084# Inputs: 0) numerical language code, 1) numerical country code, 2) no defaults
8085# Returns: language code string (ie. "fra-FR") or undef for default language
8086sub GetLangCode($;$$)
8087{
8088    my ($lang, $ctry, $noDef) = @_;
8089    # ignore country ('ctry') and language lists ('lang') for now
8090    undef $ctry if $ctry and $ctry <= 255;
8091    undef $lang if $lang and $lang <= 255;
8092    $lang = UnpackLang($lang, $noDef);
8093    # add country code if specified
8094    if ($ctry) {
8095        $ctry = unpack('a2',pack('n',$ctry)); # unpack as ISO 3166-1
8096        # treat 'ZZ' like a default country (see ref 12)
8097        undef $ctry if $ctry eq 'ZZ';
8098        if ($ctry and $ctry =~ /^[A-Z]{2}$/) {
8099            $lang or $lang = 'und';
8100            $lang .= "-$ctry";
8101        }
8102    }
8103    return $lang;
8104}
8105
8106#------------------------------------------------------------------------------
8107# Get langInfo hash and save details about alt-lang tags
8108# Inputs: 0) ExifTool ref, 1) tagInfo hash ref, 2) locale code
8109# Returns: new tagInfo hash ref, or undef if invalid
8110sub GetLangInfoQT($$$)
8111{
8112    my ($et, $tagInfo, $langCode) = @_;
8113    my $langInfo = Image::ExifTool::GetLangInfo($tagInfo, $langCode);
8114    if ($langInfo) {
8115        $$et{QTLang} or $$et{QTLang} = [ ];
8116        push @{$$et{QTLang}}, $$langInfo{Name};
8117    }
8118    return $langInfo;
8119}
8120
8121#------------------------------------------------------------------------------
8122# Get variable-length integer from data (used by ParseItemLocation)
8123# Inputs: 0) data ref, 1) start position, 2) integer size in bytes (0, 4 or 8),
8124#         3) default value
8125# Returns: integer value, and updates current position
8126sub GetVarInt($$$;$)
8127{
8128    my ($dataPt, $pos, $n, $default) = @_;
8129    my $len = length $$dataPt;
8130    $_[1] = $pos + $n;  # update current position
8131    return undef if $pos + $n > $len;
8132    if ($n == 0) {
8133        return $default || 0;
8134    } elsif ($n == 4) {
8135        return Get32u($dataPt, $pos);
8136    } elsif ($n == 8) {
8137        return Get64u($dataPt, $pos);
8138    }
8139    return undef;
8140}
8141
8142#------------------------------------------------------------------------------
8143# Get null-terminated string from binary data (used by ParseItemInfoEntry)
8144# Inputs: 0) data ref, 1) start position
8145# Returns: string, and updates current position
8146sub GetString($$)
8147{
8148    my ($dataPt, $pos) = @_;
8149    my $len = length $$dataPt;
8150    my $str = '';
8151    while ($pos < $len) {
8152        my $ch = substr($$dataPt, $pos, 1);
8153        ++$pos;
8154        last if ord($ch) == 0;
8155        $str .= $ch;
8156    }
8157    $_[1] = $pos;   # update current position
8158    return $str;
8159}
8160
8161#------------------------------------------------------------------------------
8162# Get a printable version of the tag ID
8163# Inputs: 0) tag ID, 1) Flag: 0x01 - print as 4- or 8-digit hex value if necessary
8164#                             0x02 - put leading backslash before escaped character
8165# Returns: Printable tag ID
8166sub PrintableTagID($;$)
8167{
8168    my $tag = $_[0];
8169    my $n = ($tag =~ s/([\x00-\x1f\x7f-\xff])/'x'.unpack('H*',$1)/eg);
8170    if ($n and $_[1]) {
8171        if ($n > 2 and $_[1] & 0x01) {
8172            $tag = '0x' . unpack('H8', $_[0]);
8173            $tag =~ s/^0x0000/0x/;
8174        } elsif ($_[1] & 0x02) {
8175            ($tag = $_[0]) =~ s/([\x00-\x1f\x7f-\xff])/'\\x'.unpack('H*',$1)/eg;
8176        }
8177    }
8178    return $tag;
8179}
8180
8181#==============================================================================
8182# The following ParseXxx routines parse various boxes to extract this
8183# information about embedded items in a $$et{ItemInfo} hash, keyed by item ID:
8184#
8185# iloc:
8186#  ConstructionMethod - offset type: 0=file, 1=idat, 2=item
8187#  DataReferenceIndex - 0 for "this file", otherwise index in dref box
8188#  BaseOffset         - base for file offsets
8189#  Extents            - list of details for data in file:
8190#                           0) index  (extent_index)
8191#                           1) offset (extent_offset)
8192#                           2) length (extent_length)
8193#                           3) nlen   (length_size)
8194#                           4) lenPt  (pointer to length word)
8195# infe:
8196#  ProtectionIndex    - index if item is protected (0 for unprotected)
8197#  Name               - item name
8198#  ContentType        - mime type of item
8199#  ContentEncoding    - item encoding
8200#  URI                - URI of a 'uri '-type item
8201# ipma:
8202#  Association        - list of associated properties in the ipco container
8203#  Essential          - list of "essential" flags for the associated properties
8204# cdsc:
8205#  RefersTo           - hash lookup of flags based on referred item ID
8206# other:
8207#  DocNum             - exiftool document number for this item
8208#
8209#------------------------------------------------------------------------------
8210# Parse item location (iloc) box (ref ISO 14496-12:2015 pg.79)
8211# Inputs: 0) iloc data, 1) ExifTool ref
8212# Returns: undef, and fills in ExifTool ItemInfo hash
8213# Notes: see also Handle_iloc() in WriteQuickTime.pl
8214sub ParseItemLocation($$)
8215{
8216    my ($val, $et) = @_;
8217    my ($i, $j, $num, $pos, $id);
8218    my ($extent_index, $extent_offset, $extent_length);
8219
8220    my $verbose = $$et{IsWriting} ? 0 : $et->Options('Verbose');
8221    my $items = $$et{ItemInfo} || ($$et{ItemInfo} = { });
8222    my $len = length $val;
8223    return undef if $len < 8;
8224    my $ver = Get8u(\$val, 0);
8225    my $siz = Get16u(\$val, 4);
8226    my $noff = ($siz >> 12);
8227    my $nlen = ($siz >> 8) & 0x0f;
8228    my $nbas = ($siz >> 4) & 0x0f;
8229    my $nind = $siz & 0x0f;
8230    if ($ver < 2) {
8231        $num = Get16u(\$val, 6);
8232        $pos = 8;
8233    } else {
8234        return undef if $len < 10;
8235        $num = Get32u(\$val, 6);
8236        $pos = 10;
8237    }
8238    for ($i=0; $i<$num; ++$i) {
8239        if ($ver < 2) {
8240            return undef if $pos + 2 > $len;
8241            $id = Get16u(\$val, $pos);
8242            $pos += 2;
8243        } else {
8244            return undef if $pos + 4 > $len;
8245            $id = Get32u(\$val, $pos);
8246            $pos += 4;
8247        }
8248        if ($ver == 1 or $ver == 2) {
8249            return undef if $pos + 2 > $len;
8250            $$items{$id}{ConstructionMethod} = Get16u(\$val, $pos) & 0x0f;
8251            $pos += 2;
8252        }
8253        return undef if $pos + 2 > $len;
8254        $$items{$id}{DataReferenceIndex} = Get16u(\$val, $pos);
8255        $pos += 2;
8256        $$items{$id}{BaseOffset} = GetVarInt(\$val, $pos, $nbas);
8257        return undef if $pos + 2 > $len;
8258        my $ext_num = Get16u(\$val, $pos);
8259        $pos += 2;
8260        my @extents;
8261        for ($j=0; $j<$ext_num; ++$j) {
8262            if ($ver == 1 or $ver == 2) {
8263                $extent_index = GetVarInt(\$val, $pos, $nind, 1);
8264            }
8265            $extent_offset = GetVarInt(\$val, $pos, $noff);
8266            $extent_length = GetVarInt(\$val, $pos, $nlen);
8267            return undef unless defined $extent_length;
8268            $et->VPrint(1, "$$et{INDENT}  Item $id: const_meth=",
8269                defined $$items{$id}{ConstructionMethod} ? $$items{$id}{ConstructionMethod} : '',
8270                sprintf(" base=0x%x offset=0x%x len=0x%x\n", $$items{$id}{BaseOffset},
8271                    $extent_offset, $extent_length)) if $verbose;
8272            push @extents, [ $extent_index, $extent_offset, $extent_length, $nlen, $pos-$nlen ];
8273        }
8274        # save item location information keyed on 1-based item ID:
8275        $$items{$id}{Extents} = \@extents;
8276    }
8277    return undef;
8278}
8279
8280#------------------------------------------------------------------------------
8281# Parse content describes entry (cdsc) box
8282# Inputs: 0) cdsc data, 1) ExifTool ref
8283# Returns: undef, and fills in ExifTool ItemInfo hash
8284sub ParseContentDescribes($$)
8285{
8286    my ($val, $et) = @_;
8287    my ($id, $count, @to);
8288    if ($$et{ItemRefVersion}) {
8289        return undef if length $val < 10;
8290        ($id, $count, @to) = unpack('NnN*', $val);
8291    } else {
8292        return undef if length $val < 6;
8293        ($id, $count, @to) = unpack('nnn*', $val);
8294    }
8295    if ($count > @to) {
8296        my $str = 'Missing values in ContentDescribes box';
8297        $$et{IsWriting} ? $et->Error($str) : $et->Warn($str);
8298    } elsif ($count < @to) {
8299        $et->Warn('Ignored extra values in ContentDescribes box', 1);
8300        @to = $count;
8301    }
8302    # add all referenced item ID's to a "RefersTo" lookup
8303    $$et{ItemInfo}{$id}{RefersTo}{$_} = 1 foreach @to;
8304    return undef;
8305}
8306
8307#------------------------------------------------------------------------------
8308# Parse item information entry (infe) box (ref ISO 14496-12:2015 pg.82)
8309# Inputs: 0) infe data, 1) ExifTool ref
8310# Returns: undef, and fills in ExifTool ItemInfo hash
8311sub ParseItemInfoEntry($$)
8312{
8313    my ($val, $et) = @_;
8314    my $id;
8315
8316    my $verbose = $$et{IsWriting} ? 0 : $et->Options('Verbose');
8317    my $items = $$et{ItemInfo} || ($$et{ItemInfo} = { });
8318    my $len = length $val;
8319    return undef if $len < 4;
8320    my $ver = Get8u(\$val, 0);
8321    my $pos = 4;
8322    return undef if $pos + 4 > $len;
8323    if ($ver == 0 or $ver == 1) {
8324        $id = Get16u(\$val, $pos);
8325        $$items{$id}{ProtectionIndex} = Get16u(\$val, $pos + 2);
8326        $pos += 4;
8327        $$items{$id}{Name} = GetString(\$val, $pos);
8328        $$items{$id}{ContentType} = GetString(\$val, $pos);
8329        $$items{$id}{ContentEncoding} = GetString(\$val, $pos);
8330    } else {
8331        if ($ver == 2) {
8332            $id = Get16u(\$val, $pos);
8333            $pos += 2;
8334        } elsif ($ver == 3) {
8335            $id = Get32u(\$val, $pos);
8336            $pos += 4;
8337        }
8338        return undef if $pos + 6 > $len;
8339        $$items{$id}{ProtectionIndex} = Get16u(\$val, $pos);
8340        my $type = substr($val, $pos + 2, 4);
8341        $$items{$id}{Type} = $type;
8342        $pos += 6;
8343        $$items{$id}{Name} = GetString(\$val, $pos);
8344        if ($type eq 'mime') {
8345            $$items{$id}{ContentType} = GetString(\$val, $pos);
8346            $$items{$id}{ContentEncoding} = GetString(\$val, $pos);
8347        } elsif ($type eq 'uri ') {
8348            $$items{$id}{URI} = GetString(\$val, $pos);
8349        }
8350    }
8351    $et->VPrint(1, "$$et{INDENT}  Item $id: Type=", $$items{$id}{Type} || '',
8352                   ' Name=', $$items{$id}{Name} || '',
8353                   ' ContentType=', $$items{$id}{ContentType} || '',
8354                   "\n") if $verbose > 1;
8355    return undef;
8356}
8357
8358#------------------------------------------------------------------------------
8359# Parse item property association (ipma) box (ref https://github.com/gpac/gpac/blob/master/src/isomedia/iff.c)
8360# Inputs: 0) ipma data, 1) ExifTool ref
8361# Returns: undef, and fills in ExifTool ItemInfo hash
8362sub ParseItemPropAssoc($$)
8363{
8364    my ($val, $et) = @_;
8365    my ($i, $j, $id);
8366
8367    my $verbose = $$et{IsWriting} ? 0 : $et->Options('Verbose');
8368    my $items = $$et{ItemInfo} || ($$et{ItemInfo} = { });
8369    my $len = length $val;
8370    return undef if $len < 8;
8371    my $ver = Get8u(\$val, 0);
8372    my $flg = Get32u(\$val, 0);
8373    my $num = Get32u(\$val, 4);
8374    my $pos = 8;
8375    for ($i=0; $i<$num; ++$i) {
8376        if ($ver == 0) {
8377            return undef if $pos + 3 > $len;
8378            $id = Get16u(\$val, $pos);
8379            $pos += 2;
8380        } else {
8381            return undef if $pos + 5 > $len;
8382            $id = Get32u(\$val, $pos);
8383            $pos += 4;
8384        }
8385        my $n = Get8u(\$val, $pos++);
8386        my (@association, @essential);
8387        if ($flg & 0x01) {
8388            return undef if $pos + $n * 2 > $len;
8389            for ($j=0; $j<$n; ++$j) {
8390                my $tmp = Get16u(\$val, $pos + $j * 2);
8391                push @association, $tmp & 0x7fff;
8392                push @essential, ($tmp & 0x8000) ? 1 : 0;
8393            }
8394            $pos += $n * 2;
8395        } else {
8396            return undef if $pos + $n > $len;
8397            for ($j=0; $j<$n; ++$j) {
8398                my $tmp = Get8u(\$val, $pos + $j);
8399                push @association, $tmp & 0x7f;
8400                push @essential, ($tmp & 0x80) ? 1 : 0;
8401            }
8402            $pos += $n;
8403        }
8404        $$items{$id}{Association} = \@association;
8405        $$items{$id}{Essential} = \@essential;
8406        $et->VPrint(1, "$$et{INDENT}  Item $id properties: @association\n") if $verbose > 1;
8407    }
8408    return undef;
8409}
8410
8411#------------------------------------------------------------------------------
8412# Process item information now
8413# Inputs: 0) ExifTool ref
8414sub HandleItemInfo($)
8415{
8416    my $et = shift;
8417    my $raf = $$et{RAF};
8418    my $items = $$et{ItemInfo};
8419    my $verbose = $et->Options('Verbose');
8420    my $buff;
8421
8422    # extract information from EXIF/XMP metadata items
8423    if ($items and $raf) {
8424        push @{$$et{PATH}}, 'ItemInformation';
8425        my $curPos = $raf->Tell();
8426        my $primary = $$et{PrimaryItem};
8427        my $id;
8428        $et->VerboseDir('Processing items from ItemInformation', scalar(keys %$items));
8429        foreach $id (sort { $a <=> $b } keys %$items) {
8430            my $item = $$items{$id};
8431            my $type = $$item{ContentType} || $$item{Type} || next;
8432            if ($verbose) {
8433                # add up total length of this item for the verbose output
8434                my $len = 0;
8435                if ($$item{Extents} and @{$$item{Extents}}) {
8436                    $len += $$_[2] foreach @{$$item{Extents}};
8437                }
8438                $et->VPrint(0, "$$et{INDENT}Item $id) '${type}' ($len bytes)\n");
8439            }
8440            # get ExifTool name for this item
8441            my $name = { Exif => 'EXIF', 'application/rdf+xml' => 'XMP' }->{$type} || '';
8442            my ($warn, $extent);
8443            $warn = "Can't currently decode encoded $type metadata" if $$item{ContentEncoding};
8444            $warn = "Can't currently decode protected $type metadata" if $$item{ProtectionIndex};
8445            $warn = "Can't currently extract $type with construction method $$item{ConstructionMethod}" if $$item{ConstructionMethod};
8446            $et->WarnOnce($warn) if $warn and $name;
8447            $warn = 'Not this file' if $$item{DataReferenceIndex}; # (can only extract from "this file")
8448            unless (($$item{Extents} and @{$$item{Extents}}) or $warn) {
8449                $warn = "No Extents for $type item";
8450                $et->WarnOnce($warn) if $name;
8451            }
8452            if ($warn) {
8453                $et->VPrint(0, "$$et{INDENT}    [not extracted]  ($warn)\n") if $verbose > 2;
8454                next;
8455            }
8456            my $base = $$item{BaseOffset} || 0;
8457            if ($verbose > 2) {
8458                # do verbose hex dump
8459                my $len = 0;
8460                undef $buff;
8461                my $val = '';
8462                my $maxLen = $verbose > 3 ? 2048 : 96;
8463                foreach $extent (@{$$item{Extents}}) {
8464                    my $n = $$extent[2];
8465                    my $more = $maxLen - $len;
8466                    if ($more > 0 and $n) {
8467                        $more = $n if $more > $n;
8468                        $val .= $buff if defined $buff;
8469                        $raf->Seek($$extent[1] + $base, 0) or last;
8470                        $raf->Read($buff, $more) or last;
8471                    }
8472                    $len += $n;
8473                }
8474                if (defined $buff) {
8475                    $buff = $val . $buff if length $val;
8476                    $et->VerboseDump(\$buff, DataPos => $$item{Extents}[0][1] + $base);
8477                    my $snip = $len - length $buff;
8478                    $et->VPrint(0, "$$et{INDENT}    [snip $snip bytes]\n") if $snip;
8479                }
8480            }
8481            next unless $name;
8482            # assemble the data for this item
8483            undef $buff;
8484            my $val = '';
8485            foreach $extent (@{$$item{Extents}}) {
8486                $val .= $buff if defined $buff;
8487                $raf->Seek($$extent[1] + $base, 0) or last;
8488                $raf->Read($buff, $$extent[2]) or last;
8489            }
8490            next unless defined $buff;
8491            $buff = $val . $buff if length $val;
8492            next unless length $buff;   # ignore empty directories
8493            my ($start, $subTable, $proc);
8494            my $pos = $$item{Extents}[0][1] + $base;
8495            if ($name eq 'EXIF' and length $buff >= 4) {
8496                if ($buff =~ /^(MM\0\x2a|II\x2a\0)/) {
8497                    $et->Warn('Missing Exif header');
8498                    $start = 0;
8499                } elsif ($buff =~ /^Exif\0\0/) {
8500                    # (haven't seen this yet, but it is just a matter of time
8501                    #  until someone screws it up like this)
8502                    $et->Warn('Missing Exif header size');
8503                    $start = 6;
8504                } else {
8505                    my $n = unpack('N', $buff);
8506                    $start = 4 + $n; # skip "Exif\0\0" header if it exists
8507                    if ($start > length($buff)) {
8508                        $et->Warn('Invalid EXIF header');
8509                        next;
8510                    }
8511                    if ($$et{HTML_DUMP}) {
8512                        $et->HDump($pos, 4, 'Exif header length', "Value: $n");
8513                        $et->HDump($pos+4, $start-4, 'Exif header') if $n;
8514                    }
8515                }
8516                $subTable = GetTagTable('Image::ExifTool::Exif::Main');
8517                $proc = \&Image::ExifTool::ProcessTIFF;
8518            } else {
8519                $start = 0;
8520                $subTable = GetTagTable('Image::ExifTool::XMP::Main');
8521            }
8522            my %dirInfo = (
8523                DataPt   => \$buff,
8524                DataLen  => length $buff,
8525                DirStart => $start,
8526                DirLen   => length($buff) - $start,
8527                DataPos  => $pos,
8528                Base     => $pos + $start, # (needed for HtmlDump and IsOffset tags in binary data)
8529            );
8530            # handle processing of metadata for sub-documents
8531            if (defined $primary and $$item{RefersTo} and not $$item{RefersTo}{$primary}) {
8532                # set document number if this doesn't refer to the primary document
8533                $$et{DOC_NUM} = ++$$et{DOC_COUNT};
8534                # associate this document number with the lowest item index
8535                my ($lowest) = sort { $a <=> $b } keys %{$$item{RefersTo}};
8536                $$items{$lowest}{DocNum} = $$et{DOC_NUM};
8537            }
8538            $et->ProcessDirectory(\%dirInfo, $subTable, $proc);
8539            delete $$et{DOC_NUM};
8540        }
8541        $raf->Seek($curPos, 0);     # seek back to original position
8542        pop @{$$et{PATH}};
8543    }
8544    # process the item properties now that we should know their associations and document numbers
8545    if ($$et{ItemPropertyContainer}) {
8546        my ($dirInfo, $subTable, $proc) = @{$$et{ItemPropertyContainer}};
8547        $$et{IsItemProperty} = 1;   # set item property flag
8548        $et->ProcessDirectory($dirInfo, $subTable, $proc);
8549        delete $$et{ItemPropertyContainer};
8550        delete $$et{IsItemProperty};
8551        delete $$et{DOC_NUM};
8552    }
8553    delete $$et{ItemInfo};
8554}
8555
8556#------------------------------------------------------------------------------
8557# Warn if ExtractEmbedded option isn't used
8558# Inputs: 0) ExifTool ref
8559sub EEWarn($)
8560{
8561    my $et = shift;
8562    $et->WarnOnce('The ExtractEmbedded option may find more tags in the media data',3);
8563}
8564
8565#------------------------------------------------------------------------------
8566# Get quicktime format from flags word
8567# Inputs: 0) quicktime atom flags, 1) data length
8568# Returns: ExifTool format string
8569sub QuickTimeFormat($$)
8570{
8571    my ($flags, $len) = @_;
8572    my $format;
8573    if ($flags == 0x15 or $flags == 0x16) {
8574        $format = { 1=>'int8', 2=>'int16', 4=>'int32' }->{$len};
8575        $format .= $flags == 0x15 ? 's' : 'u' if $format;
8576    } elsif ($flags == 0x17) {
8577        $format = 'float';
8578    } elsif ($flags == 0x18) {
8579        $format = 'double';
8580    } elsif ($flags == 0x00) {
8581        $format = { 1=>'int8u', 2=>'int16u' }->{$len};
8582    }
8583    return $format;
8584}
8585
8586#------------------------------------------------------------------------------
8587# Process MPEG-4 MTDT atom (ref 11)
8588# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
8589# Returns: 1 on success
8590sub ProcessMetaData($$$)
8591{
8592    my ($et, $dirInfo, $tagTablePtr) = @_;
8593    my $dataPt = $$dirInfo{DataPt};
8594    my $dirLen = length $$dataPt;
8595    my $verbose = $et->Options('Verbose');
8596    return 0 unless $dirLen >= 2;
8597    my $count = Get16u($dataPt, 0);
8598    $verbose and $et->VerboseDir('MetaData', $count);
8599    my $i;
8600    my $pos = 2;
8601    for ($i=0; $i<$count; ++$i) {
8602        last if $pos + 10 > $dirLen;
8603        my $size = Get16u($dataPt, $pos);
8604        last if $size < 10 or $size + $pos > $dirLen;
8605        my $tag  = Get32u($dataPt, $pos + 2);
8606        my $lang = Get16u($dataPt, $pos + 6);
8607        my $enc  = Get16u($dataPt, $pos + 8);
8608        my $val  = substr($$dataPt, $pos + 10, $size);
8609        my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
8610        if ($tagInfo) {
8611            # convert language code to ASCII (ignore read-only bit)
8612            $lang = UnpackLang($lang);
8613            # handle alternate languages
8614            if ($lang) {
8615                my $langInfo = GetLangInfoQT($et, $tagInfo, $lang);
8616                $tagInfo = $langInfo if $langInfo;
8617            }
8618            $verbose and $et->VerboseInfo($tag, $tagInfo,
8619                Value  => $val,
8620                DataPt => $dataPt,
8621                Start  => $pos + 10,
8622                Size   => $size - 10,
8623            );
8624            # convert from UTF-16 BE if necessary
8625            $val = $et->Decode($val, 'UCS2') if $enc == 1;
8626            if ($enc == 0 and $$tagInfo{Unknown}) {
8627                # binary data
8628                $et->FoundTag($tagInfo, \$val);
8629            } else {
8630                $et->FoundTag($tagInfo, $val);
8631            }
8632        }
8633        $pos += $size;
8634    }
8635    return 1;
8636}
8637
8638#------------------------------------------------------------------------------
8639# Process sample description table
8640# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
8641# Returns: 1 on success
8642# (ref https://developer.apple.com/library/content/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-25691)
8643sub ProcessSampleDesc($$$)
8644{
8645    my ($et, $dirInfo, $tagTablePtr) = @_;
8646    my $dataPt = $$dirInfo{DataPt};
8647    my $pos = $$dirInfo{DirStart} || 0;
8648    my $dirLen = $$dirInfo{DirLen} || (length($$dataPt) - $pos);
8649    return 0 if $pos + 8 > $dirLen;
8650
8651    my $num = Get32u($dataPt, 4);   # get number of sample entries in table
8652    $pos += 8;
8653    my $i;
8654    for ($i=0; $i<$num; ++$i) {     # loop through sample entries
8655        last if $pos + 8 > $dirLen;
8656        my $size = Get32u($dataPt, $pos);
8657        last if $pos + $size > $dirLen;
8658        $$dirInfo{DirStart} = $pos;
8659        $$dirInfo{DirLen} = $size;
8660        ProcessHybrid($et, $dirInfo, $tagTablePtr);
8661        $pos += $size;
8662    }
8663    return 1;
8664}
8665
8666#------------------------------------------------------------------------------
8667# Process hybrid binary data + QuickTime container (ref PH)
8668# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
8669# Returns: 1 on success
8670sub ProcessHybrid($$$)
8671{
8672    my ($et, $dirInfo, $tagTablePtr) = @_;
8673    # brute-force search for child atoms after first 8 bytes of binary data
8674    my $dataPt = $$dirInfo{DataPt};
8675    my $dirStart = $$dirInfo{DirStart} || 0;
8676    my $dirLen = $$dirInfo{DirLen} || length($$dataPt) - $dirStart;
8677    my $end = $dirStart + $dirLen;
8678    my $pos = $dirStart + 8;   # skip length/version
8679    my $try = $pos;
8680    my $childPos;
8681
8682    while ($pos <= $end - 8) {
8683        my $tag = substr($$dataPt, $try+4, 4);
8684        # look only for well-behaved tag ID's
8685        $tag =~ /[^\w ]/ and $try = ++$pos, next;
8686        my $size = Get32u($dataPt, $try);
8687        if ($size + $try == $end) {
8688            # the atom ends exactly at the end of the parent -- this must be it
8689            $childPos = $pos;
8690            $$dirInfo{DirLen} = $pos;   # the binary data ends at the first child atom
8691            last;
8692        }
8693        if ($size < 8 or $size + $try > $end - 8) {
8694            $try = ++$pos;  # fail.  try next position
8695        } else {
8696            $try += $size;  # could be another atom following this
8697        }
8698    }
8699    # process binary data
8700    $$dirInfo{MixedTags} = 1; # ignore non-integer tag ID's
8701    $et->ProcessBinaryData($dirInfo, $tagTablePtr);
8702    # process child atoms if found
8703    if ($childPos) {
8704        $$dirInfo{DirStart} = $childPos;
8705        $$dirInfo{DirLen} = $end - $childPos;
8706        ProcessMOV($et, $dirInfo, $tagTablePtr);
8707    }
8708    return 1;
8709}
8710
8711#------------------------------------------------------------------------------
8712# Process iTunes 'righ' atom (ref PH)
8713# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
8714# Returns: 1 on success
8715sub ProcessRights($$$)
8716{
8717    my ($et, $dirInfo, $tagTablePtr) = @_;
8718    my $dataPt = $$dirInfo{DataPt};
8719    my $dataPos = $$dirInfo{Base};
8720    my $dirLen = length $$dataPt;
8721    my $unknown = $$et{OPTIONS}{Unknown} || $$et{OPTIONS}{Verbose};
8722    my $pos;
8723    $et->VerboseDir('righ', $dirLen / 8);
8724    for ($pos = 0; $pos + 8 <= $dirLen; $pos += 8) {
8725        my $tag = substr($$dataPt, $pos, 4);
8726        last if $tag eq "\0\0\0\0";
8727        my $val = substr($$dataPt, $pos + 4, 4);
8728        my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
8729        unless ($tagInfo) {
8730            next unless $unknown;
8731            my $name = PrintableTagID($tag);
8732            $tagInfo = {
8733                Name => "Unknown_$name",
8734                Description => "Unknown $name",
8735                Unknown => 1,
8736            },
8737            AddTagToTable($tagTablePtr, $tag, $tagInfo);
8738        }
8739        $val = '0x' . unpack('H*', $val) unless $$tagInfo{Format};
8740        $et->HandleTag($tagTablePtr, $tag, $val,
8741            DataPt  => $dataPt,
8742            DataPos => $dataPos,
8743            Start   => $pos + 4,
8744            Size    => 4,
8745        );
8746    }
8747    return 1;
8748}
8749
8750#------------------------------------------------------------------------------
8751# Process iTunes Encoding Params (ref PH)
8752# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
8753# Returns: 1 on success
8754sub ProcessEncodingParams($$$)
8755{
8756    my ($et, $dirInfo, $tagTablePtr) = @_;
8757    my $dataPt = $$dirInfo{DataPt};
8758    my $dirLen = length $$dataPt;
8759    my $pos;
8760    $et->VerboseDir('Encoding Params', $dirLen / 8);
8761    for ($pos = 0; $pos + 8 <= $dirLen; $pos += 8) {
8762        my ($tag, $val) = unpack("x${pos}a4N", $$dataPt);
8763        $et->HandleTag($tagTablePtr, $tag, $val);
8764    }
8765    return 1;
8766}
8767
8768#------------------------------------------------------------------------------
8769# Read Meta Keys and add tags to ItemList table ('mdta' handler) (ref PH)
8770# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
8771# Returns: 1 on success
8772sub ProcessKeys($$$)
8773{
8774    local $_;
8775    my ($et, $dirInfo, $tagTablePtr) = @_;
8776    my $dataPt = $$dirInfo{DataPt};
8777    my $dirLen = length $$dataPt;
8778    my $out;
8779    if ($et->Options('Verbose')) {
8780        $et->VerboseDir('Keys');
8781        $out = $et->Options('TextOut');
8782    }
8783    my $pos = 8;
8784    my $index = 1;
8785    ++$$et{KeysCount};  # increment key count for this directory
8786    my $itemList = GetTagTable('Image::ExifTool::QuickTime::ItemList');
8787    my $userData = GetTagTable('Image::ExifTool::QuickTime::UserData');
8788    while ($pos < $dirLen - 4) {
8789        my $len = unpack("x${pos}N", $$dataPt);
8790        last if $len < 8 or $pos + $len > $dirLen;
8791        delete $$tagTablePtr{$index};
8792        my $ns  = substr($$dataPt, $pos + 4, 4);
8793        my $tag = substr($$dataPt, $pos + 8, $len - 8);
8794        $tag =~ s/\0.*//s; # truncate at null
8795        $tag =~ s/^com\.(apple\.quicktime\.)?// if $ns eq 'mdta'; # remove apple quicktime domain
8796        $tag = "Tag_$ns" unless $tag;
8797        # (I have some samples where the tag is a reversed ItemList or UserData tag ID)
8798        my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
8799        unless ($tagInfo) {
8800            $tagInfo = $et->GetTagInfo($itemList, $tag);
8801            unless ($tagInfo) {
8802                $tagInfo = $et->GetTagInfo($userData, $tag);
8803                if (not $tagInfo and $tag =~ /^\w{3}\xa9$/) {
8804                    $tag = pack('N', unpack('V', $tag));
8805                    $tagInfo = $et->GetTagInfo($itemList, $tag);
8806                    $tagInfo or $tagInfo = $et->GetTagInfo($userData, $tag);
8807                }
8808            }
8809        }
8810        my ($newInfo, $msg);
8811        if ($tagInfo) {
8812            # copy tag information into new Keys tag
8813            $newInfo = {
8814                Name      => $$tagInfo{Name},
8815                Format    => $$tagInfo{Format},
8816                ValueConv => $$tagInfo{ValueConv},
8817                ValueConvInv => $$tagInfo{ValueConvInv},
8818                PrintConv => $$tagInfo{PrintConv},
8819                PrintConvInv => $$tagInfo{PrintConvInv},
8820                Writable  => defined $$tagInfo{Writable} ? $$tagInfo{Writable} : 1,
8821                SubDirectory => $$tagInfo{SubDirectory},
8822            };
8823            my $groups = $$tagInfo{Groups};
8824            $$newInfo{Groups} = $groups ? { %$groups } : { };
8825            $$newInfo{Groups}{$_} or $$newInfo{Groups}{$_} = $$tagTablePtr{GROUPS}{$_} foreach 0..2;
8826            $$newInfo{Groups}{1} = 'Keys';
8827        } elsif ($tag =~ /^[-\w. ]+$/ or $tag =~ /\w{4}/) {
8828            # create info for tags with reasonable id's
8829            my $name = ucfirst $tag;
8830            $name =~ tr/-0-9a-zA-Z_. //dc;
8831            $name =~ s/[. ]+(.?)/\U$1/g;
8832            $name =~ s/_([a-z])/_\U$1/g;
8833            $name =~ s/([a-z])_([A-Z])/$1$2/g;
8834            $name = "Tag_$name" if length $name < 2;
8835            $newInfo = { Name => $name, Groups => { 1 => 'Keys' } };
8836            $msg = ' (Unknown)';
8837        }
8838        # substitute this tag in the ItemList table with the given index
8839        my $id = $$et{KeysCount} . '.' . $index;
8840        if (ref $$itemList{$id} eq 'HASH') {
8841            # delete other languages too if they exist
8842            my $oldInfo = $$itemList{$id};
8843            if ($$oldInfo{OtherLang}) {
8844                delete $$itemList{$_} foreach @{$$oldInfo{OtherLang}};
8845            }
8846            delete $$itemList{$id};
8847        }
8848        if ($newInfo) {
8849            AddTagToTable($itemList, $id, $newInfo);
8850            $msg or $msg = '';
8851            $out and print $out "$$et{INDENT}Added ItemList Tag $id = ($ns) $tag$msg\n";
8852        }
8853        $pos += $len;
8854        ++$index;
8855    }
8856    return 1;
8857}
8858
8859#------------------------------------------------------------------------------
8860# Process keys in MetaSampleDesc directory
8861# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
8862# Returns: 1 on success
8863sub ProcessMetaKeys($$$)
8864{
8865    my ($et, $dirInfo, $tagTablePtr) = @_;
8866    # save this information to decode timed metadata samples when ExtractEmbedded is used
8867    SaveMetaKeys($et, $dirInfo, $tagTablePtr) if $$et{OPTIONS}{ExtractEmbedded};
8868    return 1;
8869}
8870
8871#------------------------------------------------------------------------------
8872# Process a QuickTime atom
8873# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) optional tag table ref
8874# Returns: 1 on success
8875sub ProcessMOV($$;$)
8876{
8877    local $_;
8878    my ($et, $dirInfo, $tagTablePtr) = @_;
8879    my $raf = $$dirInfo{RAF};
8880    my $dataPt = $$dirInfo{DataPt};
8881    my $verbose = $et->Options('Verbose');
8882    my $validate = $$et{OPTIONS}{Validate};
8883    my $dataPos = $$dirInfo{Base} || 0;
8884    my $dirID = $$dirInfo{DirID} || '';
8885    my $charsetQuickTime = $et->Options('CharsetQuickTime');
8886    my ($buff, $tag, $size, $track, $isUserData, %triplet, $doDefaultLang, $index);
8887    my ($dirEnd, $ee, $unkOpt, %saveOptions, $atomCount);
8888
8889    my $topLevel = not $$et{InQuickTime};
8890    $$et{InQuickTime} = 1;
8891    $$et{HandlerType} = $$et{MetaFormat} = '' unless defined $$et{HandlerType};
8892
8893    unless (defined $$et{KeysCount}) {
8894        $$et{KeysCount} = 0;    # initialize ItemList key directory count
8895        $doDefaultLang = 1;     # flag to generate default language tags
8896    }
8897    # more convenient to package data as a RandomAccess file
8898    unless ($raf) {
8899        $raf = new File::RandomAccess($dataPt);
8900        $dirEnd = $dataPos + $$dirInfo{DirLen} + ($$dirInfo{DirStart} || 0) if $$dirInfo{DirLen};
8901    }
8902    # skip leading bytes if necessary
8903    if ($$dirInfo{DirStart}) {
8904        $raf->Seek($$dirInfo{DirStart}, 1) or return 0;
8905        $dataPos += $$dirInfo{DirStart};
8906    }
8907    # read size/tag name atom header
8908    $raf->Read($buff,8) == 8 or return 0;
8909    $dataPos += 8;
8910    if ($tagTablePtr) {
8911        $isUserData = ($tagTablePtr eq \%Image::ExifTool::QuickTime::UserData);
8912    } else {
8913        $tagTablePtr = GetTagTable('Image::ExifTool::QuickTime::Main');
8914    }
8915    ($size, $tag) = unpack('Na4', $buff);
8916    if ($dataPt) {
8917        $verbose and $et->VerboseDir($$dirInfo{DirName});
8918    } else {
8919        # check on file type if called with a RAF
8920        $$tagTablePtr{$tag} or return 0;
8921        if ($tag eq 'ftyp' and $size >= 12) {
8922            # read ftyp atom to see what type of file this is
8923            my $fileType;
8924            if ($raf->Read($buff, $size-8) == $size-8) {
8925                $raf->Seek(-($size-8), 1);
8926                my $type = substr($buff, 0, 4);
8927                # see if we know the extension for this file type
8928                if ($ftypLookup{$type} and $ftypLookup{$type} =~ /\(\.(\w+)/) {
8929                    $fileType = $1;
8930                # check compatible brands
8931                } elsif ($buff =~ /^.{8}(.{4})+(mp41|mp42|avc1)/s) {
8932                    $fileType = 'MP4';
8933                } elsif ($buff =~ /^.{8}(.{4})+(f4v )/s) {
8934                    $fileType = 'F4V';
8935                } elsif ($buff =~ /^.{8}(.{4})+(qt  )/s) {
8936                    $fileType = 'MOV';
8937                }
8938            }
8939            $fileType or $fileType = 'MP4'; # default to MP4
8940            $et->SetFileType($fileType, $mimeLookup{$fileType} || 'video/mp4');
8941            # temporarily set ExtractEmbedded option for CRX files
8942            $saveOptions{ExtractEmbedded} = $et->Options(ExtractEmbedded => 1) if $fileType eq 'CRX';
8943        } else {
8944            $et->SetFileType();       # MOV
8945        }
8946        SetByteOrder('MM');
8947        $$et{PRIORITY_DIR} = 'XMP';   # have XMP take priority
8948    }
8949    $$raf{NoBuffer} = 1 if $et->Options('FastScan'); # disable buffering in FastScan mode
8950
8951    if ($$et{OPTIONS}{ExtractEmbedded}) {
8952        $ee = 1;
8953        $unkOpt = $$et{OPTIONS}{Unknown};
8954        require 'Image/ExifTool/QuickTimeStream.pl';
8955    }
8956    if ($$tagTablePtr{VARS}) {
8957        $index = $$tagTablePtr{VARS}{START_INDEX};
8958        $atomCount = $$tagTablePtr{VARS}{ATOM_COUNT};
8959    }
8960    for (;;) {
8961        my ($eeTag, $ignore);
8962        last if defined $atomCount and --$atomCount < 0;
8963        if ($size < 8) {
8964            if ($size == 0) {
8965                if ($dataPt) {
8966                    # a zero size isn't legal for contained atoms, but Canon uses it to
8967                    # terminate the CNTH atom (eg. CanonEOS100D.mov), so tolerate it here
8968                    my $pos = $raf->Tell() - 4;
8969                    $raf->Seek(0,2);
8970                    my $str = $$dirInfo{DirName} . ' with ' . ($raf->Tell() - $pos) . ' bytes';
8971                    $et->VPrint(0,"$$et{INDENT}\[Terminator found in $str remaining]");
8972                } else {
8973                    my $t = PrintableTagID($tag,2);
8974                    $et->VPrint(0,"$$et{INDENT}Tag '${t}' extends to end of file");
8975                }
8976                last;
8977            }
8978            $size == 1 or $et->Warn('Invalid atom size'), last;
8979            # read extended atom size
8980            $raf->Read($buff, 8) == 8 or $et->Warn('Truncated atom header'), last;
8981            $dataPos += 8;
8982            my ($hi, $lo) = unpack('NN', $buff);
8983            if ($hi or $lo > 0x7fffffff) {
8984                if ($hi > 0x7fffffff) {
8985                    $et->Warn('Invalid atom size');
8986                    last;
8987                } elsif (not $et->Options('LargeFileSupport')) {
8988                    $et->Warn('End of processing at large atom (LargeFileSupport not enabled)');
8989                    last;
8990                }
8991            }
8992            $size = $hi * 4294967296 + $lo - 16;
8993            $size < 0 and $et->Warn('Invalid extended size'), last;
8994        } else {
8995            $size -= 8;
8996        }
8997        if ($validate) {
8998            $$et{ValidatePath} or $$et{ValidatePath} = { };
8999            my $path = join('-', @{$$et{PATH}}, $tag);
9000            $path =~ s/-Track-/-$$et{SET_GROUP1}-/ if $$et{SET_GROUP1};
9001            if ($$et{ValidatePath}{$path} and not $dupTagOK{$tag} and not $dupDirOK{$dirID}) {
9002                my $i = Get32u(\$tag,0);
9003                my $str = $i < 255 ? "index $i" : "tag '" . PrintableTagID($tag,2) . "'";
9004                $et->WarnOnce("Duplicate $str at " . join('-', @{$$et{PATH}}));
9005                $$et{ValidatePath} = { } if $path eq 'MOV-moov'; # avoid warnings for all contained dups
9006            }
9007            $$et{ValidatePath}{$path} = 1;
9008        }
9009        if ($isUserData and $$et{SET_GROUP1}) {
9010            my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
9011            # add track name to UserData tags inside tracks
9012            $tag = $$et{SET_GROUP1} . $tag;
9013            if (not $$tagTablePtr{$tag} and $tagInfo) {
9014                my %newInfo = %$tagInfo;
9015                foreach ('Name', 'Description') {
9016                    next unless $$tagInfo{$_};
9017                    $newInfo{$_} = $$et{SET_GROUP1} . $$tagInfo{$_};
9018                    $newInfo{$_} =~ s/^(Track\d+)Track/$1/; # remove duplicate "Track" in name
9019                }
9020                AddTagToTable($tagTablePtr, $tag, \%newInfo);
9021            }
9022        }
9023        # set flag to store additional information for ExtractEmbedded option
9024        my $handlerType = $$et{HandlerType};
9025        if ($eeBox{$handlerType} and $eeBox{$handlerType}{$tag}) {
9026            if ($ee) {
9027                # (there is another 'gps ' box with a track log that doesn't contain offsets)
9028                if ($tag ne 'gps ' or $eeBox{$handlerType}{$tag} eq $dirID) {
9029                    $eeTag = 1;
9030                    $$et{OPTIONS}{Unknown} = 1; # temporarily enable "Unknown" option
9031                }
9032            } elsif ($handlerType ne 'vide' and not $$et{OPTIONS}{Validate}) {
9033                EEWarn($et);
9034            }
9035        }
9036        my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
9037
9038        $$et{OPTIONS}{Unknown} = $unkOpt if $eeTag;     # restore Unknown option
9039
9040        # allow numerical tag ID's
9041        unless ($tagInfo) {
9042            my $id = $$et{KeysCount} . '.' . unpack('N', $tag);
9043            if ($$tagTablePtr{$id}) {
9044                $tagInfo = $et->GetTagInfo($tagTablePtr, $id);
9045                $tag = $id;
9046            }
9047        }
9048        # generate tagInfo if Unknown option set
9049        if (not defined $tagInfo and ($$et{OPTIONS}{Unknown} or
9050            $verbose or $tag =~ /^\xa9/))
9051        {
9052            my $name = PrintableTagID($tag,1);
9053            if ($name =~ /^xa9(.*)/) {
9054                $tagInfo = {
9055                    Name => "UserData_$1",
9056                    Description => "User Data $1",
9057                };
9058            } else {
9059                $tagInfo = {
9060                    Name => "Unknown_$name",
9061                    Description => "Unknown $name",
9062                    %unknownInfo,
9063                };
9064            }
9065            AddTagToTable($tagTablePtr, $tag, $tagInfo);
9066        }
9067        # save required tag sizes
9068        if ($$tagTablePtr{"$tag-size"}) {
9069            $et->HandleTag($tagTablePtr, "$tag-size", $size);
9070            $et->HandleTag($tagTablePtr, "$tag-offset", $raf->Tell()) if $$tagTablePtr{"$tag-offset"};
9071        }
9072        # load values only if associated with a tag (or verbose) and not too big
9073        if ($size > 0x2000000) {    # start to get worried above 32 MB
9074            # check for RIFF trailer (written by Auto-Vox dashcam)
9075            if ($buff =~ /^(gpsa|gps0|gsen|gsea)...\0/s) { # (yet seen only gpsa as first record)
9076                $et->VPrint(0, "Found RIFF trailer");
9077                if ($et->Options('ExtractEmbedded')) {
9078                    $raf->Seek(-8, 1) or last;  # seek back to start of trailer
9079                    my $tbl = GetTagTable('Image::ExifTool::QuickTime::Stream');
9080                    ProcessRIFFTrailer($et, { RAF => $raf }, $tbl);
9081                } else {
9082                    EEWarn($et);
9083                }
9084                last;
9085            }
9086            $ignore = 1;
9087            if ($tagInfo and not $$tagInfo{Unknown} and not $eeTag) {
9088                my $t = PrintableTagID($tag,2);
9089                if ($size > 0x8000000) {
9090                    $et->Warn("Skipping '${t}' atom > 128 MB", 1);
9091                } else {
9092                    $et->Warn("Skipping '${t}' atom > 32 MB", 2) or $ignore = 0;
9093                }
9094            }
9095        }
9096        if (defined $tagInfo and not $ignore) {
9097            # set document number for this item property if necessary
9098            if ($$et{IsItemProperty}) {
9099                my $items = $$et{ItemInfo};
9100                my ($id, $prop, $docNum, $lowest);
9101                my $primary = $$et{PrimaryItem} || 0;
9102ItemID:         foreach $id (keys %$items) {
9103                    next unless $$items{$id}{Association};
9104                    my $item = $$items{$id};
9105                    foreach $prop (@{$$item{Association}}) {
9106                        next unless $prop == $index;
9107                        if ($id == $primary or (not $dontInherit{$tag} and
9108                            (not $$item{RefersTo} or $$item{RefersTo}{$primary})))
9109                        {
9110                            # this is associated with the primary item or an item describing
9111                            # the primary item, so consider this part of the main document
9112                            undef $docNum;
9113                            undef $lowest;
9114                            last ItemID;
9115                        } elsif ($$item{DocNum}) {
9116                            # this property is already associated with an item that has
9117                            # an ExifTool document number, so use the lowest associated DocNum
9118                            $docNum = $$item{DocNum} if not defined $docNum or $docNum > $$item{DocNum};
9119                        } elsif (not defined $lowest or $lowest > $id) {
9120                            # keep track of the lowest associated item ID
9121                            $lowest = $id;
9122                        }
9123                    }
9124                }
9125                if (not defined $docNum and defined $lowest) {
9126                    # this is the first time we've seen metadata from this item,
9127                    # so use a new document number
9128                    $docNum = ++$$et{DOC_COUNT};
9129                    $$items{$lowest}{DocNum} = $docNum;
9130                }
9131                $$et{DOC_NUM} = $docNum;
9132            }
9133            my $val;
9134            my $missing = $size - $raf->Read($val, $size);
9135            if ($missing) {
9136                my $t = PrintableTagID($tag,2);
9137                $et->Warn("Truncated '${t}' data (missing $missing bytes)");
9138                last;
9139            }
9140            # use value to get tag info if necessary
9141            $tagInfo or $tagInfo = $et->GetTagInfo($tagTablePtr, $tag, \$val);
9142            my $hasData = ($$dirInfo{HasData} and $val =~ /\0...data\0/s);
9143            if ($verbose and not $hasData) {
9144                my $tval;
9145                if ($tagInfo and $$tagInfo{Format}) {
9146                    $tval = ReadValue(\$val, 0, $$tagInfo{Format}, $$tagInfo{Count}, length($val));
9147                }
9148                $et->VerboseInfo($tag, $tagInfo,
9149                    Value   => $tval,
9150                    DataPt  => \$val,
9151                    DataPos => $dataPos,
9152                    Size    => $size,
9153                    Format  => $tagInfo ? $$tagInfo{Format} : undef,
9154                    Index   => $index,
9155                );
9156                # print iref item ID numbers
9157                if ($dirID eq 'iref') {
9158                    my ($id, $count, @to, $i);
9159                    if ($$et{ItemRefVersion}) {
9160                        ($id, $count, @to) = unpack('NnN*', $val) if length $val >= 10;
9161                    } else {
9162                        ($id, $count, @to) = unpack('nnn*', $val) if length $val >= 6;
9163                    }
9164                    defined $id or $id = '<err>', $count = 0;
9165                    $id .= " (wrong count: $count)" if $count != @to;
9166                    # convert sequential numbers to a range
9167                    for ($i=1; $i<@to; ) {
9168                        $to[$i-1] =~ /(\d+)$/ and $to[$i] == $1 + 1 or ++$i, next;
9169                        $to[$i-1] =~ s/(-.*)?$/-$to[$i]/;
9170                        splice @to, $i, 1;
9171                    }
9172                    $et->VPrint(1, "$$et{INDENT}  Item $id refers to: ",join(',',@to),"\n");
9173                }
9174            }
9175            # extract metadata from stream if ExtractEmbedded option is enabled
9176            if ($eeTag) {
9177                ParseTag($et, $tag, \$val);
9178                # forget this tag if we generated it only for ExtractEmbedded
9179                undef $tagInfo if $tagInfo and $$tagInfo{Unknown} and not $unkOpt;
9180            }
9181
9182            # handle iTunesInfo mean/name/data triplets
9183            if ($tagInfo and $$tagInfo{Triplet}) {
9184                if ($tag eq 'data' and $triplet{mean} and $triplet{name}) {
9185                    $tag = $triplet{name};
9186                    # add 'mean' to name unless it is 'com.apple.iTunes'
9187                    $tag = $triplet{mean} . '/' . $tag unless $triplet{mean} eq 'com.apple.iTunes';
9188                    $tagInfo = $et->GetTagInfo($tagTablePtr, $tag, \$val);
9189                    unless ($tagInfo) {
9190                        my $name = $triplet{name};
9191                        my $desc = $name;
9192                        $name =~ tr/-_a-zA-Z0-9//dc;
9193                        $desc =~ tr/_/ /;
9194                        $tagInfo = {
9195                            Name => $name,
9196                            Description => $desc,
9197                        };
9198                        AddTagToTable($tagTablePtr, $tag, $tagInfo);
9199                    }
9200                    # ignore 8-byte header
9201                    $val = substr($val, 8) if length($val) >= 8;
9202                    unless ($$tagInfo{Format} or $$tagInfo{SubDirectory}) {
9203                        # extract as binary if it contains any non-ASCII or control characters
9204                        if ($val =~ /[^\x20-\x7e]/) {
9205                            my $buff = $val;
9206                            $val = \$buff;
9207                        }
9208                    }
9209                    undef %triplet;
9210                } else {
9211                    undef %triplet if $tag eq 'mean';
9212                    $triplet{$tag} = substr($val,4) if length($val) > 4;
9213                    undef $tagInfo;  # don't store this tag
9214                }
9215            }
9216            if ($tagInfo) {
9217                my $subdir = $$tagInfo{SubDirectory};
9218                if ($subdir) {
9219                    my $start = $$subdir{Start} || 0;
9220                    my ($base, $dPos) = ($dataPos, 0);
9221                    if ($$subdir{Base}) {
9222                        $dPos -= eval $$subdir{Base};
9223                        $base -= $dPos;
9224                    }
9225                    my %dirInfo = (
9226                        DataPt     => \$val,
9227                        DataLen    => $size,
9228                        DirStart   => $start,
9229                        DirLen     => $size - $start,
9230                        DirName    => $$subdir{DirName} || $$tagInfo{Name},
9231                        DirID      => $tag,
9232                        HasData    => $$subdir{HasData},
9233                        Multi      => $$subdir{Multi},
9234                        IgnoreProp => $$subdir{IgnoreProp}, # (XML hack)
9235                        DataPos    => $dPos,
9236                        Base       => $base, # (needed for IsOffset tags in binary data)
9237                    );
9238                    $dirInfo{BlockInfo} = $tagInfo if $$tagInfo{BlockExtract};
9239                    if ($$subdir{ByteOrder} and $$subdir{ByteOrder} =~ /^Little/) {
9240                        SetByteOrder('II');
9241                    }
9242                    my $oldGroup1 = $$et{SET_GROUP1};
9243                    if ($$tagInfo{SubDirectory} and $$tagInfo{SubDirectory}{TagTable} and
9244                        $$tagInfo{SubDirectory}{TagTable} eq 'Image::ExifTool::QuickTime::Track')
9245                    {
9246                        $track or $track = 0;
9247                        $$et{SET_GROUP1} = 'Track' . (++$track);
9248                    }
9249                    my $subTable = GetTagTable($$subdir{TagTable});
9250                    my $proc = $$subdir{ProcessProc};
9251                    # make ProcessMOV() the default processing procedure for subdirectories
9252                    $proc = \&ProcessMOV unless $proc or $$subTable{PROCESS_PROC};
9253                    if ($size > $start) {
9254                        # delay processing of ipco box until after all other boxes
9255                        if ($tag eq 'ipco' and not $$et{IsItemProperty}) {
9256                            $$et{ItemPropertyContainer} = [ \%dirInfo, $subTable, $proc ];
9257                            $et->VPrint(0,"$$et{INDENT}\[Process ipco box later]");
9258                        } else {
9259                            $et->ProcessDirectory(\%dirInfo, $subTable, $proc);
9260                        }
9261                    }
9262                    if ($tag eq 'stbl') {
9263                        # process sample data when exiting SampleTable box if extracting embedded
9264                        ProcessSamples($et) if $ee;
9265                    } elsif ($tag eq 'minf') {
9266                        $$et{HandlerType} = ''; # reset handler type at end of media info box
9267                    }
9268                    $$et{SET_GROUP1} = $oldGroup1;
9269                    SetByteOrder('MM');
9270                } elsif ($hasData) {
9271                    # handle atoms containing 'data' tags
9272                    # (currently ignore contained atoms: 'itif', 'name', etc.)
9273                    my $pos = 0;
9274                    for (;;) {
9275                        last if $pos + 16 > $size;
9276                        my ($len, $type, $flags, $ctry, $lang) = unpack("x${pos}Na4Nnn", $val);
9277                        last if $pos + $len > $size;
9278                        my ($value, $langInfo, $oldDir);
9279                        my $format = $$tagInfo{Format};
9280                        if ($type eq 'data' and $len >= 16) {
9281                            $pos += 16;
9282                            $len -= 16;
9283                            $value = substr($val, $pos, $len);
9284                            # format flags (ref 12):
9285                            # 0x0=binary, 0x1=UTF-8, 0x2=UTF-16, 0x3=ShiftJIS,
9286                            # 0x4=UTF-8  0x5=UTF-16, 0xd=JPEG, 0xe=PNG,
9287                            # 0x15=signed int, 0x16=unsigned int, 0x17=float,
9288                            # 0x18=double, 0x1b=BMP, 0x1c='meta' atom
9289                            if ($stringEncoding{$flags}) {
9290                                # handle all string formats
9291                                $value = $et->Decode($value, $stringEncoding{$flags});
9292                                # (shouldn't be null terminated, but some software writes it anyway)
9293                                $value =~ s/\0$// unless $$tagInfo{Binary};
9294                            } else {
9295                                $format = QuickTimeFormat($flags, $len) unless $format;
9296                                if ($format) {
9297                                    $value = ReadValue(\$value, 0, $format, $$tagInfo{Count}, $len);
9298                                } elsif (not $$tagInfo{ValueConv}) {
9299                                    # make binary data a scalar reference unless a ValueConv exists
9300                                    my $buf = $value;
9301                                    $value = \$buf;
9302                                }
9303                            }
9304                        }
9305                        if ($ctry or $lang) {
9306                            my $langCode = GetLangCode($lang, $ctry);
9307                            if ($langCode) {
9308                                # get tagInfo for other language
9309                                $langInfo = GetLangInfoQT($et, $tagInfo, $langCode);
9310                                # save other language tag ID's so we can delete later if necessary
9311                                if ($langInfo) {
9312                                    $$tagInfo{OtherLang} or $$tagInfo{OtherLang} = [ ];
9313                                    push @{$$tagInfo{OtherLang}}, $$langInfo{TagID};
9314                                }
9315                            }
9316                        }
9317                        $langInfo or $langInfo = $tagInfo;
9318                        $et->VerboseInfo($tag, $langInfo,
9319                            Value   => ref $value ? $$value : $value,
9320                            DataPt  => \$val,
9321                            DataPos => $dataPos,
9322                            Start   => $pos,
9323                            Size    => $len,
9324                            Format  => $format,
9325                            Index   => $index,
9326                            Extra   => sprintf(", Type='${type}', Flags=0x%x, Lang=0x%.4x",$flags,$lang),
9327                        ) if $verbose;
9328                        # use "Keys" in path instead of ItemList if this was defined by a Keys tag
9329                        my $isKey = $$tagInfo{Groups} && $$tagInfo{Groups}{1} && $$tagInfo{Groups}{1} eq 'Keys';
9330                        if ($isKey) {
9331                            $oldDir = $$et{PATH}[-1];
9332                            $$et{PATH}[-1] = 'Keys';
9333                        }
9334                        $et->FoundTag($langInfo, $value) if defined $value;
9335                        $$et{PATH}[-1] = $oldDir if $isKey;
9336                        $pos += $len;
9337                    }
9338                } elsif ($tag =~ /^\xa9/ or $$tagInfo{IText}) {
9339                    # parse international text to extract all languages
9340                    my $pos = 0;
9341                    if ($$tagInfo{Format}) {
9342                        $et->FoundTag($tagInfo, ReadValue(\$val, 0, $$tagInfo{Format}, undef, length($val)));
9343                        $pos = $size;
9344                    }
9345                    for (;;) {
9346                        my ($len, $lang);
9347                        if ($$tagInfo{IText} and $$tagInfo{IText} == 6) {
9348                            last if $pos + 6 > $size;
9349                            $pos += 4;
9350                            $lang = unpack("x${pos}n", $val);
9351                            $pos += 2;
9352                            $len = $size - $pos;
9353                        } else {
9354                            last if $pos + 4 > $size;
9355                            ($len, $lang) = unpack("x${pos}nn", $val);
9356                            $pos += 4;
9357                            # according to the QuickTime spec (ref 12), $len should include
9358                            # 4 bytes for length and type words, but nobody (including
9359                            # Apple, Pentax and Kodak) seems to add these in, so try
9360                            # to allow for either
9361                            if ($pos + $len > $size) {
9362                                $len -= 4;
9363                                last if $pos + $len > $size or $len < 0;
9364                            }
9365                        }
9366                        # ignore any empty entries (or null padding) after the first
9367                        next if not $len and $pos;
9368                        my $str = substr($val, $pos, $len);
9369                        my $langInfo;
9370                        if (($lang < 0x400 or $lang == 0x7fff) and $str !~ /^\xfe\xff/) {
9371                            # this is a Macintosh language code
9372                            # a language code of 0 is Macintosh english, so treat as default
9373                            if ($lang) {
9374                                if ($lang == 0x7fff) {
9375                                    # technically, ISO 639-2 doesn't have a 2-character
9376                                    # equivalent for 'und', but use 'un' anyway
9377                                    $lang = 'un';
9378                                } else {
9379                                    # use Font.pm to look up language string
9380                                    require Image::ExifTool::Font;
9381                                    $lang = $Image::ExifTool::Font::ttLang{Macintosh}{$lang};
9382                                }
9383                            }
9384                            # the spec says only "Macintosh text encoding", but
9385                            # allow this to be configured by the user
9386                            $str = $et->Decode($str, $charsetQuickTime);
9387                        } else {
9388                            # convert language code to ASCII (ignore read-only bit)
9389                            $lang = UnpackLang($lang);
9390                            # may be either UTF-8 or UTF-16BE
9391                            my $enc = $str=~s/^\xfe\xff// ? 'UTF16' : 'UTF8';
9392                            $str = $et->Decode($str, $enc);
9393                        }
9394                        $str =~ s/\0+$//;   # remove any trailing nulls (eg. 3gp tags)
9395                        $langInfo = GetLangInfoQT($et, $tagInfo, $lang) if $lang;
9396                        $et->FoundTag($langInfo || $tagInfo, $str);
9397                        $pos += $len;
9398                    }
9399                } else {
9400                    my $format = $$tagInfo{Format};
9401                    if ($format) {
9402                        $val = ReadValue(\$val, 0, $format, $$tagInfo{Count}, length($val));
9403                    }
9404                    my $oldBase;
9405                    if ($$tagInfo{SetBase}) {
9406                        $oldBase = $$et{BASE};
9407                        $$et{BASE} = $dataPos;
9408                    }
9409                    my $key = $et->FoundTag($tagInfo, $val);
9410                    $$et{BASE} = $oldBase if defined $oldBase;
9411                    # decode if necessary (NOTE: must be done after RawConv)
9412                    if (defined $key and (not $format or $format =~ /^string/) and
9413                        not $$tagInfo{Unknown} and not $$tagInfo{ValueConv} and
9414                        not $$tagInfo{Binary} and defined $$et{VALUE}{$key} and not ref $val)
9415                    {
9416                        my $vp = \$$et{VALUE}{$key};
9417                        if (not ref $$vp and length($$vp) <= 65536 and $$vp =~ /[\x80-\xff]/) {
9418                            # the encoding of this is not specified, so use CharsetQuickTime
9419                            # unless the string is valid UTF-8
9420                            require Image::ExifTool::XMP;
9421                            my $enc = Image::ExifTool::XMP::IsUTF8($vp) > 0 ? 'UTF8' : $charsetQuickTime;
9422                            $$vp = $et->Decode($$vp, $enc);
9423                        }
9424                    }
9425                }
9426            }
9427        } else {
9428            $et->VerboseInfo($tag, $tagInfo,
9429                Size  => $size,
9430                Extra => sprintf(' at offset 0x%.4x', $raf->Tell()),
9431            ) if $verbose;
9432            if ($size and (not $raf->Seek($size-1, 1) or $raf->Read($buff, 1) != 1)) {
9433                my $t = PrintableTagID($tag,2);
9434                $et->Warn("Truncated '${t}' data");
9435                last;
9436            }
9437        }
9438        $dataPos += $size + 8;  # point to start of next atom data
9439        last if $dirEnd and $dataPos >= $dirEnd; # (note: ignores last value if 0 bytes)
9440        $raf->Read($buff, 8) == 8 or last;
9441        ($size, $tag) = unpack('Na4', $buff);
9442        ++$index if defined $index;
9443    }
9444    # fill in missing defaults for alternate language tags
9445    # (the first language is taken as the default)
9446    if ($doDefaultLang and $$et{QTLang}) {
9447QTLang: foreach $tag (@{$$et{QTLang}}) {
9448            next unless defined $$et{VALUE}{$tag};
9449            my $langInfo = $$et{TAG_INFO}{$tag} or next;
9450            my $tagInfo = $$langInfo{SrcTagInfo} or next;
9451            my $infoHash = $$et{TAG_INFO};
9452            my $name = $$tagInfo{Name};
9453            # loop through all instances of this tag name and generate the default-language
9454            # version only if we don't already have a QuickTime tag with this name
9455            my ($i, $key);
9456            for ($i=0, $key=$name; $$infoHash{$key}; ++$i, $key="$name ($i)") {
9457                next QTLang if $et->GetGroup($key, 0) eq 'QuickTime';
9458            }
9459            $et->FoundTag($tagInfo, $$et{VALUE}{$tag});
9460        }
9461        delete $$et{QTLang};
9462    }
9463    # process item information now that we are done processing its 'meta' container
9464    HandleItemInfo($et) if $topLevel or $dirID eq 'meta';
9465
9466    ScanMediaData($et) if $ee and $topLevel;  # brute force scan for metadata embedded in media data
9467
9468    # restore any changed options
9469    $et->Options($_ => $saveOptions{$_}) foreach keys %saveOptions;
9470    return 1;
9471}
9472
9473#------------------------------------------------------------------------------
9474# Process a QuickTime Image File
9475# Inputs: 0) ExifTool object reference, 1) directory information reference
9476# Returns: 1 on success
9477sub ProcessQTIF($$)
9478{
9479    my ($et, $dirInfo) = @_;
9480    my $table = GetTagTable('Image::ExifTool::QuickTime::ImageFile');
9481    return ProcessMOV($et, $dirInfo, $table);
9482}
9483
94841;  # end
9485
9486__END__
9487
9488=head1 NAME
9489
9490Image::ExifTool::QuickTime - Read QuickTime and MP4 meta information
9491
9492=head1 SYNOPSIS
9493
9494This module is used by Image::ExifTool
9495
9496=head1 DESCRIPTION
9497
9498This module contains routines required by Image::ExifTool to extract
9499information from QuickTime and MP4 video, M4A audio, and HEIC image files.
9500
9501=head1 AUTHOR
9502
9503Copyright 2003-2021, Phil Harvey (philharvey66 at gmail.com)
9504
9505This library is free software; you can redistribute it and/or modify it
9506under the same terms as Perl itself.
9507
9508=head1 REFERENCES
9509
9510=over 4
9511
9512=item L<http://developer.apple.com/mac/library/documentation/QuickTime/QTFF/QTFFChap1/qtff1.html>
9513
9514=item L<http://search.cpan.org/dist/MP4-Info-1.04/>
9515
9516=item L<http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt>
9517
9518=item L<http://wiki.multimedia.cx/index.php?title=Apple_QuickTime>
9519
9520=item L<http://atomicparsley.sourceforge.net/mpeg-4files.html>
9521
9522=item L<http://wiki.multimedia.cx/index.php?title=QuickTime_container>
9523
9524=item L<http://code.google.com/p/mp4v2/wiki/iTunesMetadata>
9525
9526=item L<http://www.canieti.com.mx/assets/files/1011/IEC_100_1384_DC.pdf>
9527
9528=item L<http://www.adobe.com/devnet/flv/pdf/video_file_format_spec_v10.pdf>
9529
9530=back
9531
9532=head1 SEE ALSO
9533
9534L<Image::ExifTool::TagNames/QuickTime Tags>,
9535L<Image::ExifTool(3pm)|Image::ExifTool>
9536
9537=cut
9538
9539