exiftool_vendored 10.58.0 → 10.65.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of exiftool_vendored might be problematic. Click here for more details.

Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +100 -1
  3. data/bin/MANIFEST +2 -0
  4. data/bin/META.json +1 -1
  5. data/bin/META.yml +1 -1
  6. data/bin/README +39 -38
  7. data/bin/arg_files/exif2iptc.args +3 -0
  8. data/bin/arg_files/iptc2exif.args +3 -0
  9. data/bin/config_files/example.config +16 -14
  10. data/bin/config_files/photoshop_paths.config +10 -0
  11. data/bin/exiftool +71 -65
  12. data/bin/lib/Image/ExifTool/APE.pm +5 -0
  13. data/bin/lib/Image/ExifTool/BuildTagLookup.pm +31 -15
  14. data/bin/lib/Image/ExifTool/Canon.pm +18 -4
  15. data/bin/lib/Image/ExifTool/CanonCustom.pm +3 -0
  16. data/bin/lib/Image/ExifTool/Charset/DOSLatin1.pm +49 -0
  17. data/bin/lib/Image/ExifTool/Charset/DOSLatinUS.pm +49 -0
  18. data/bin/lib/Image/ExifTool/Charset.pm +8 -5
  19. data/bin/lib/Image/ExifTool/Exif.pm +37 -18
  20. data/bin/lib/Image/ExifTool/FLAC.pm +47 -37
  21. data/bin/lib/Image/ExifTool/FLIR.pm +3 -3
  22. data/bin/lib/Image/ExifTool/FujiFilm.pm +5 -2
  23. data/bin/lib/Image/ExifTool/GPS.pm +6 -6
  24. data/bin/lib/Image/ExifTool/Geotag.pm +1 -1
  25. data/bin/lib/Image/ExifTool/H264.pm +2 -0
  26. data/bin/lib/Image/ExifTool/ID3.pm +8 -3
  27. data/bin/lib/Image/ExifTool/IPTC.pm +1 -1
  28. data/bin/lib/Image/ExifTool/Import.pm +4 -1
  29. data/bin/lib/Image/ExifTool/InDesign.pm +11 -7
  30. data/bin/lib/Image/ExifTool/Kodak.pm +4 -1
  31. data/bin/lib/Image/ExifTool/Lang/de.pm +31 -31
  32. data/bin/lib/Image/ExifTool/MWG.pm +12 -4
  33. data/bin/lib/Image/ExifTool/MakerNotes.pm +3 -3
  34. data/bin/lib/Image/ExifTool/Matroska.pm +2 -1
  35. data/bin/lib/Image/ExifTool/Microsoft.pm +3 -3
  36. data/bin/lib/Image/ExifTool/Minolta.pm +71 -61
  37. data/bin/lib/Image/ExifTool/Nikon.pm +286 -43
  38. data/bin/lib/Image/ExifTool/NikonCustom.pm +1049 -0
  39. data/bin/lib/Image/ExifTool/Olympus.pm +4 -1
  40. data/bin/lib/Image/ExifTool/PNG.pm +4 -7
  41. data/bin/lib/Image/ExifTool/PanasonicRaw.pm +24 -1
  42. data/bin/lib/Image/ExifTool/Pentax.pm +20 -6
  43. data/bin/lib/Image/ExifTool/Photoshop.pm +24 -3
  44. data/bin/lib/Image/ExifTool/QuickTime.pm +545 -14
  45. data/bin/lib/Image/ExifTool/README +16 -9
  46. data/bin/lib/Image/ExifTool/RIFF.pm +8 -1
  47. data/bin/lib/Image/ExifTool/Samsung.pm +5 -4
  48. data/bin/lib/Image/ExifTool/Sigma.pm +9 -1
  49. data/bin/lib/Image/ExifTool/Sony.pm +327 -153
  50. data/bin/lib/Image/ExifTool/TagLookup.pm +3273 -3220
  51. data/bin/lib/Image/ExifTool/TagNames.pod +317 -38
  52. data/bin/lib/Image/ExifTool/Validate.pm +15 -1
  53. data/bin/lib/Image/ExifTool/WriteExif.pl +5 -0
  54. data/bin/lib/Image/ExifTool/WriteIPTC.pl +23 -1
  55. data/bin/lib/Image/ExifTool/WriteQuickTime.pl +8 -2
  56. data/bin/lib/Image/ExifTool/WriteXMP.pl +7 -0
  57. data/bin/lib/Image/ExifTool/Writer.pl +96 -18
  58. data/bin/lib/Image/ExifTool/XMP.pm +20 -11
  59. data/bin/lib/Image/ExifTool/XMP2.pl +634 -583
  60. data/bin/lib/Image/ExifTool.pm +124 -17
  61. data/bin/lib/Image/ExifTool.pod +86 -82
  62. data/bin/perl-Image-ExifTool.spec +38 -37
  63. data/lib/exiftool_vendored/version.rb +1 -1
  64. metadata +4 -2
@@ -1,7 +1,7 @@
1
1
  #------------------------------------------------------------------------------
2
2
  # File: QuickTime.pm
3
3
  #
4
- # Description: Read QuickTime, MP4 and M4A meta information
4
+ # Description: Read QuickTime and MP4 meta information
5
5
  #
6
6
  # Revisions: 10/04/2005 - P. Harvey Created
7
7
  # 12/19/2005 - P. Harvey Added MP4 support
@@ -42,7 +42,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
42
42
  use Image::ExifTool::Exif;
43
43
  use Image::ExifTool::GPS;
44
44
 
45
- $VERSION = '2.02';
45
+ $VERSION = '2.05';
46
46
 
47
47
  sub FixWrongFormat($);
48
48
  sub ProcessMOV($$;$);
@@ -51,6 +51,9 @@ sub ProcessMetaData($$$);
51
51
  sub ProcessEncodingParams($$$);
52
52
  sub ProcessHybrid($$$);
53
53
  sub ProcessRights($$$);
54
+ sub ParseItemLocation($$);
55
+ sub ParseItemInfoEntry($$);
56
+ sub ParseItemPropAssoc($$);
54
57
  sub ConvertISO6709($);
55
58
  sub ConvertChapterList($);
56
59
  sub PrintChapter($);
@@ -77,6 +80,9 @@ my %mimeLookup = (
77
80
  M4V => 'video/x-m4v',
78
81
  MOV => 'video/quicktime',
79
82
  MQV => 'video/quicktime',
83
+ HEIC => 'image/heic',
84
+ HEVC => 'image/heic-sequence',
85
+ HEIF => 'image/heif',
80
86
  );
81
87
 
82
88
  # look up file type from ftyp atom type, with MIME type in comment if known
@@ -171,6 +177,10 @@ my %ftypLookup = (
171
177
  'ssc1' => 'Samsung stereoscopic, single stream',
172
178
  'ssc2' => 'Samsung stereoscopic, dual stream',
173
179
  'XAVC' => 'Sony XAVC', #PH
180
+ 'heic' => 'High Efficiency Image Format HEVC still image (.HEIC)', # image/heic
181
+ 'hevc' => 'High Efficiency Image Format HEVC sequence (.HEICS)', # image/heic-sequence
182
+ 'mif1' => 'High Efficiency Image Format still image (.HEIF)', # image/heif
183
+ 'msf1' => 'High Efficiency Image Format sequence (.HEIFS)', # image/heif-sequence
174
184
  );
175
185
 
176
186
  # information for time/date-based tags (time zero is Jan 1, 1904)
@@ -364,6 +374,7 @@ my %graphicsMode = (
364
374
  Groups => { 2 => 'Preview' },
365
375
  Binary => 1,
366
376
  },
377
+ # (note that moov is present for an HEIF sequence)
367
378
  moov => {
368
379
  Name => 'Movie',
369
380
  SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Movie' },
@@ -561,6 +572,7 @@ my %graphicsMode = (
561
572
  # v410 => "Uncompressed Y'CbCr, 10-bit 4:4:4",
562
573
  # v210 => "Uncompressed Y'CbCr, 10-bit 4:2:2",
563
574
  # },
575
+ # (HEVC-encoded videos have a CompressorID of 'hvc1')
564
576
  },
565
577
  10 => {
566
578
  Name => 'VendorID',
@@ -628,6 +640,7 @@ my %graphicsMode = (
628
640
  gama => { Name => 'Gamma', Format => 'fixed32u' },
629
641
  # mjqt - default quantization table for MJPEG
630
642
  # mjht - default Huffman table for MJPEG
643
+ # csgm ? (seen in hevc video)
631
644
  #
632
645
  # spherical video v2 stuff (untested)
633
646
  #
@@ -639,6 +652,7 @@ my %graphicsMode = (
639
652
  0 => 'Monoscopic',
640
653
  1 => 'Stereoscopic Top-Bottom',
641
654
  2 => 'Stereoscopic Left-Right',
655
+ 3 => 'Stereoscopic Stereo-Custom', # (provisional in spec as of 2017-10-10)
642
656
  },
643
657
  },
644
658
  sv3d => {
@@ -682,6 +696,7 @@ my %graphicsMode = (
682
696
  Name => 'EquirectangularProj',
683
697
  SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::equi' },
684
698
  },
699
+ # mshp - MeshProjection (P.I.T.A. to decode, for not much reward, see ref)
685
700
  );
686
701
 
687
702
  # 'prhd' atom information (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md)
@@ -929,6 +944,7 @@ my %graphicsMode = (
929
944
  Name => 'SphericalVideoXML',
930
945
  Condition => '$$valPt=~/^\xff\xcc\x82\x63\xf8\x55\x4a\x93\x88\x14\x58\x7a\x02\x52\x1f\xdd/',
931
946
  Flags => [ 'Binary', 'BlockExtract' ],
947
+ Writable => 0,
932
948
  SubDirectory => {
933
949
  TagTable => 'Image::ExifTool::XMP::Main',
934
950
  Start => 16,
@@ -1931,16 +1947,27 @@ my %graphicsMode = (
1931
1947
  },
1932
1948
  iloc => {
1933
1949
  Name => 'ItemLocation',
1934
- Flags => ['Binary','Unknown'],
1950
+ RawConv => \&ParseItemLocation,
1951
+ Notes => 'parsed, but not extracted as a tag',
1935
1952
  },
1936
1953
  ipro => {
1937
1954
  Name => 'ItemProtection',
1938
1955
  Flags => ['Binary','Unknown'],
1939
1956
  },
1940
- iinf => {
1957
+ iinf => [{
1941
1958
  Name => 'ItemInformation',
1942
- Flags => ['Binary','Unknown'],
1943
- },
1959
+ Condition => '$$valPt =~ /^\0/', # (version 0?)
1960
+ SubDirectory => {
1961
+ TagTable => 'Image::ExifTool::QuickTime::ItemInfo',
1962
+ Start => 6, # (4-byte version/flags + 2-byte count)
1963
+ },
1964
+ },{
1965
+ Name => 'ItemInformation',
1966
+ SubDirectory => {
1967
+ TagTable => 'Image::ExifTool::QuickTime::ItemInfo',
1968
+ Start => 8, # (4-byte version/flags + 4-byte count)
1969
+ },
1970
+ }],
1944
1971
  'xml ' => {
1945
1972
  Name => 'XML',
1946
1973
  Flags => [ 'Binary', 'Protected', 'BlockExtract' ],
@@ -1957,14 +1984,144 @@ my %graphicsMode = (
1957
1984
  Name => 'BinaryXML',
1958
1985
  Flags => ['Binary','Unknown'],
1959
1986
  },
1960
- pitm => {
1987
+ pitm => [{
1961
1988
  Name => 'PrimaryItemReference',
1962
- Flags => ['Binary','Unknown'],
1963
- },
1989
+ Condition => '$$valPt =~ /^\0/', # (version 0?)
1990
+ RawConv => '$$self{PrimaryItem} = unpack("x4n",$val)',
1991
+ },{
1992
+ Name => 'PrimaryItemReference',
1993
+ RawConv => '$$self{PrimaryItem} = unpack("x4N",$val)',
1994
+ }],
1964
1995
  free => { #PH
1965
1996
  Name => 'Free',
1966
1997
  Flags => ['Binary','Unknown'],
1967
1998
  },
1999
+ iprp => {
2000
+ Name => 'ItemProperties',
2001
+ SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ItemProp' },
2002
+ },
2003
+ iref => {
2004
+ Name => 'ItemReference',
2005
+ # the version is needed to parse some of the item references
2006
+ Condition => '$$self{ItemRefVersion} = ord($$valPt); 1',
2007
+ SubDirectory => {
2008
+ TagTable => 'Image::ExifTool::QuickTime::ItemRef',
2009
+ Start => 4,
2010
+ },
2011
+ },
2012
+ # idat
2013
+ );
2014
+
2015
+ %Image::ExifTool::QuickTime::ItemProp = (
2016
+ PROCESS_PROC => \&ProcessMOV,
2017
+ GROUPS => { 2 => 'Image' },
2018
+ ipco => {
2019
+ Name => 'ItemPropertyContainer',
2020
+ SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ItemPropCont' },
2021
+ },
2022
+ ipma => {
2023
+ Name => 'ItemPropertyAssociation',
2024
+ RawConv => \&ParseItemPropAssoc,
2025
+ Notes => 'parsed, but not extracted as a tag',
2026
+ },
2027
+ );
2028
+
2029
+ %Image::ExifTool::QuickTime::ItemPropCont = (
2030
+ PROCESS_PROC => \&ProcessMOV,
2031
+ GROUPS => { 2 => 'Image' },
2032
+ VARS => { START_INDEX => 1 }, # show verbose indices starting at 1
2033
+ colr => [{
2034
+ Name => 'ICC_Profile',
2035
+ Condition => '$$valPt =~ /^(prof|rICC)/',
2036
+ SubDirectory => {
2037
+ TagTable => 'Image::ExifTool::ICC_Profile::Main',
2038
+ Start => 4,
2039
+ },
2040
+ },{
2041
+ Name => 'Unknown_colr',
2042
+ Flags => ['Binary','Unknown','Hidden'],
2043
+ }],
2044
+ irot => {
2045
+ Name => 'Rotation',
2046
+ Format => 'int8u',
2047
+ ValueConv => '$val * 90',
2048
+ },
2049
+ ispe => {
2050
+ Name => 'ImageSpatialExtent',
2051
+ Condition => '$$valPt =~ /^\0{4}/', # (version/flags == 0/0)
2052
+ RawConv => 'join " ", unpack("x4N*", $val)',
2053
+ PrintConv => '$val =~ tr/ /x/; $val',
2054
+ },
2055
+ pixi => {
2056
+ Name => 'ImagePixelDepth',
2057
+ Condition => '$$valPt =~ /^\0{4}./s', # (version/flags == 0/0 and count)
2058
+ RawConv => 'join " ", unpack("x5C*", $val)',
2059
+ },
2060
+ auxC => {
2061
+ Name => 'AuxiliaryImageType',
2062
+ Format => 'undef',
2063
+ RawConv => '$val = substr($val, 4); $val =~ s/\0.*//s; $val',
2064
+ },
2065
+ pasp => {
2066
+ Name => 'PixelAspectRatio',
2067
+ Format => 'int32u',
2068
+ },
2069
+ rloc => {
2070
+ Name => 'RelativeLocation',
2071
+ Format => 'int32u',
2072
+ RawConv => '$val =~ s/^\S+\s+//; $val', # remove version/flags
2073
+ },
2074
+ clap => {
2075
+ Name => 'CleanAperture',
2076
+ Format => 'rational64u',
2077
+ Notes => '4 numbers: width, height, left and top',
2078
+ },
2079
+ hvcC => {
2080
+ Name => 'HEVCConfiguration',
2081
+ Flags => ['Binary','Unknown'],
2082
+ },
2083
+ );
2084
+
2085
+ %Image::ExifTool::QuickTime::ItemRef = (
2086
+ PROCESS_PROC => \&ProcessMOV,
2087
+ GROUPS => { 2 => 'Image' },
2088
+ # (Note: ExifTool's ItemRefVersion may be used to test the iref version number)
2089
+ # dimg - DerivedImage
2090
+ # thmb - Thumbnail
2091
+ # auxl - AuxiliaryImage
2092
+ cdsc => {
2093
+ Name => 'ContentDescribes',
2094
+ Notes => 'parsed, but not extracted as a tag',
2095
+ RawConv => sub {
2096
+ my ($val, $et) = @_;
2097
+ my ($id, $count, @to);
2098
+ if ($$et{ItemRefVersion}) {
2099
+ return undef if length $val < 10;
2100
+ ($id, $count, @to) = unpack('NnN*', $val);
2101
+ } else {
2102
+ return undef if length $val < 6;
2103
+ ($id, $count, @to) = unpack('nnn*', $val);
2104
+ }
2105
+ # add all referenced item ID's to a "RefersTo" lookup
2106
+ $$et{ItemInfo}{$id}{RefersTo}{$_} = 1 foreach @to;
2107
+ return undef;
2108
+ },
2109
+ },
2110
+ );
2111
+
2112
+ %Image::ExifTool::QuickTime::ItemInfo = (
2113
+ PROCESS_PROC => \&ProcessMOV,
2114
+ GROUPS => { 2 => 'Image' },
2115
+ # avc1 - AVC image
2116
+ # hvc1 - HEVC image
2117
+ # lhv1 - L-HEVC image
2118
+ # infe - ItemInformationEntry
2119
+ # infe types: avc1,hvc1,lhv1,Exif,xml1,iovl(overlay image),grid,mime,hvt1(tile image)
2120
+ infe => {
2121
+ Name => 'ItemInfoEntry',
2122
+ RawConv => \&ParseItemInfoEntry,
2123
+ Notes => 'parsed, but not extracted as a tag',
2124
+ },
1968
2125
  );
1969
2126
 
1970
2127
  # track reference atoms
@@ -1979,6 +2136,12 @@ my %graphicsMode = (
1979
2136
  ValueConv => '$val =~ s/^1 //; $val', # (why 2 numbers? -- ignore the first if "1")
1980
2137
  },
1981
2138
  # also: sync, scpt, ssrc, iTunesInfo
2139
+ cdsc => {
2140
+ Name => 'ContentDescribes',
2141
+ Format => 'int32u',
2142
+ PrintConv => '"Track $val"',
2143
+ },
2144
+ # cdep (Structural Dependency QT tag?)
1982
2145
  );
1983
2146
 
1984
2147
  # track aperture mode dimensions atoms
@@ -5307,7 +5470,7 @@ my %graphicsMode = (
5307
5470
  Name => 'ProtectionInfo', #3
5308
5471
  SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ProtectionInfo' },
5309
5472
  },
5310
- # chan - 16/36 bytes
5473
+ # f - 16/36 bytes
5311
5474
  # esds - 31/40/42/43 bytes - ES descriptor (ref 3)
5312
5475
  damr => { #3
5313
5476
  Name => 'DecodeConfig',
@@ -5580,7 +5743,7 @@ my %graphicsMode = (
5580
5743
  Format => 'undef', # (necessary to prevent decoding as string!)
5581
5744
  RawConv => q{
5582
5745
  return undef if unpack("N",$val) & 0x01;
5583
- $_ = substr($val,4); s/\0.*//s; $_;
5746
+ $_ = substr($val,4); s/\0+/; /; s/\0.*//s; $_;
5584
5747
  },
5585
5748
  },
5586
5749
  );
@@ -5624,6 +5787,7 @@ my %graphicsMode = (
5624
5787
  vide => 'Video Track',
5625
5788
  subp => 'Subpicture', #http://www.google.nl/patents/US7778526
5626
5789
  nrtm => 'Non-Real Time Metadata', #PH (Sony ILCE-7S) [how is this different from "meta"?]
5790
+ pict => 'Picture', # (HEIC images)
5627
5791
  },
5628
5792
  },
5629
5793
  12 => { #PH
@@ -5972,6 +6136,321 @@ sub GetLangInfoQT($$$)
5972
6136
  return $langInfo;
5973
6137
  }
5974
6138
 
6139
+ #------------------------------------------------------------------------------
6140
+ # Get variable-length integer from data (used by ParseItemLocation)
6141
+ # Inputs: 0) data ref, 1) start position, 2) integer size in bytes (0, 4 or 8),
6142
+ # 3) default value
6143
+ # Returns: integer value, and updates current position
6144
+ sub GetVarInt($$$;$)
6145
+ {
6146
+ my ($dataPt, $pos, $n, $default) = @_;
6147
+ my $len = length $$dataPt;
6148
+ $_[1] = $pos + $n; # update current position
6149
+ return undef if $pos + $n > $len;
6150
+ if ($n == 0) {
6151
+ return $default || 0;
6152
+ } elsif ($n == 4) {
6153
+ return Get32u($dataPt, $pos);
6154
+ } elsif ($n == 8) {
6155
+ return Get64u($dataPt, $pos);
6156
+ }
6157
+ return undef;
6158
+ }
6159
+
6160
+ #------------------------------------------------------------------------------
6161
+ # Get null-terminated string from binary data (used by ParseItemInfoEntry)
6162
+ # Inputs: 0) data ref, 1) start position
6163
+ # Returns: string, and updates current position
6164
+ sub GetString($$)
6165
+ {
6166
+ my ($dataPt, $pos) = @_;
6167
+ my $len = length $$dataPt;
6168
+ my $str = '';
6169
+ while ($pos < $len) {
6170
+ my $ch = substr($$dataPt, $pos, 1);
6171
+ ++$pos;
6172
+ last if ord($ch) == 0;
6173
+ $str .= $ch;
6174
+ }
6175
+ $_[1] = $pos; # update current position
6176
+ return $str;
6177
+ }
6178
+
6179
+ #==============================================================================
6180
+ # The following ParseXxx routines parse various boxes to extract this
6181
+ # information about embedded items in a $$et{ItemInfo} hash, keyed by item ID:
6182
+ #
6183
+ # iloc:
6184
+ # ConstructionMethod - offset type: 0=file, 1=idat, 2=item
6185
+ # DataReferenceIndex - 0 for "this file", otherwise index in dref box
6186
+ # BaseOffset - base for file offsets
6187
+ # Extents - list of index,offset,length details for data in file
6188
+ # infe:
6189
+ # ProtectionIndex - index if item is protected (0 for unprotected)
6190
+ # Name - item name
6191
+ # ContentType - mime type of item
6192
+ # ContentEncoding - item encoding
6193
+ # URI - URI of a 'uri '-type item
6194
+ # ipma:
6195
+ # Association - list of associated properties in the ipco container
6196
+ # Essential - list of "essential" flags for the associated properties
6197
+ # cdsc:
6198
+ # RefersTo - hash lookup of flags based on referred item ID
6199
+ # other:
6200
+ # DocNum - exiftool document number for this item
6201
+ #
6202
+ #------------------------------------------------------------------------------
6203
+ # Parse item location (iloc) box (ref ISO 14496-12:2015 pg.79)
6204
+ # Inputs: 0) iloc data, 1) ExifTool ref
6205
+ # Returns: undef, and fills in ExifTool ItemInfo hash
6206
+ sub ParseItemLocation($$)
6207
+ {
6208
+ my ($val, $et) = @_;
6209
+ my ($i, $j, $num, $pos, $id);
6210
+ my ($extent_index, $extent_offset, $extent_length);
6211
+
6212
+ my $items = $$et{ItemInfo} || ($$et{ItemInfo} = { });
6213
+ my $len = length $val;
6214
+ return undef if $len < 8;
6215
+ my $ver = Get8u(\$val, 0);
6216
+ my $siz = Get16u(\$val, 4);
6217
+ my $noff = ($siz >> 12);
6218
+ my $nlen = ($siz >> 8) & 0x0f;
6219
+ my $nbas = ($siz >> 4) & 0x0f;
6220
+ my $nind = $siz & 0x0f;
6221
+ if ($ver < 2) {
6222
+ $num = Get16u(\$val, 6);
6223
+ $pos = 8;
6224
+ } else {
6225
+ return undef if $len < 10;
6226
+ $num = Get32u(\$val, 6);
6227
+ $pos = 10;
6228
+ }
6229
+ for ($i=0; $i<$num; ++$i) {
6230
+ if ($ver < 2) {
6231
+ return undef if $pos + 2 > $len;
6232
+ $id = Get16u(\$val, $pos);
6233
+ $pos += 2;
6234
+ } else {
6235
+ return undef if $pos + 4 > $len;
6236
+ $id = Get32u(\$val, $pos);
6237
+ $pos += 4;
6238
+ }
6239
+ if ($ver == 1 or $ver == 2) {
6240
+ return undef if $pos + 2 > $len;
6241
+ $$items{$id}{ConstructionMethod} = Get16u(\$val, $pos) & 0x0f;
6242
+ $pos += 2;
6243
+ }
6244
+ return undef if $pos + 2 > $len;
6245
+ $$items{$id}{DataReferenceIndex} = Get16u(\$val, $pos);
6246
+ $pos += 2;
6247
+ $$items{$id}{BaseOffset} = GetVarInt(\$val, $pos, $nbas);
6248
+ return undef if $pos + 2 > $len;
6249
+ my $ext_num = Get16u(\$val, $pos);
6250
+ $pos += 2;
6251
+ my @extents;
6252
+ for ($j=0; $j<$ext_num; ++$j) {
6253
+ if ($ver == 1 or $ver == 2) {
6254
+ $extent_index = GetVarInt(\$val, $pos, $nind, 1);
6255
+ }
6256
+ $extent_offset = GetVarInt(\$val, $pos, $noff);
6257
+ $extent_length = GetVarInt(\$val, $pos, $nlen);
6258
+ return undef unless defined $extent_length;
6259
+ push @extents, [ $extent_index, $extent_offset, $extent_length ];
6260
+ }
6261
+ # save item location information keyed on 1-based item ID:
6262
+ $$items{$id}{Extents} = \@extents;
6263
+ }
6264
+ return undef;
6265
+ }
6266
+
6267
+ #------------------------------------------------------------------------------
6268
+ # Parse item information entry (infe) box (ref ISO 14496-12:2015 pg.82)
6269
+ # Inputs: 0) infe data, 1) ExifTool ref
6270
+ # Returns: undef, and fills in ExifTool ItemInfo hash
6271
+ sub ParseItemInfoEntry($$)
6272
+ {
6273
+ my ($val, $et) = @_;
6274
+ my $id;
6275
+
6276
+ my $verbose = $et->Options('Verbose');
6277
+ my $items = $$et{ItemInfo} || ($$et{ItemInfo} = { });
6278
+ my $len = length $val;
6279
+ return undef if $len < 4;
6280
+ my $ver = Get8u(\$val, 0);
6281
+ my $pos = 4;
6282
+ return undef if $pos + 4 > $len;
6283
+ if ($ver == 0 or $ver == 1) {
6284
+ $id = Get16u(\$val, $pos);
6285
+ $$items{$id}{ProtectionIndex} = Get16u(\$val, $pos + 2);
6286
+ $pos += 4;
6287
+ $$items{$id}{Name} = GetString(\$val, $pos);
6288
+ $$items{$id}{ContentType} = GetString(\$val, $pos);
6289
+ $$items{$id}{ContentEncoding} = GetString(\$val, $pos);
6290
+ } else {
6291
+ if ($ver == 2) {
6292
+ $id = Get16u(\$val, $pos);
6293
+ $pos += 2;
6294
+ } elsif ($ver == 3) {
6295
+ $id = Get32u(\$val, $pos);
6296
+ $pos += 4;
6297
+ }
6298
+ return undef if $pos + 6 > $len;
6299
+ $$items{$id}{ProtectionIndex} = Get16u(\$val, $pos);
6300
+ my $type = substr($val, $pos + 2, 4);
6301
+ $$items{$id}{Type} = $type;
6302
+ $pos += 6;
6303
+ $$items{$id}{Name} = GetString(\$val, $pos);
6304
+ if ($type eq 'mime') {
6305
+ $$items{$id}{ContentType} = GetString(\$val, $pos);
6306
+ $$items{$id}{ContentEncoding} = GetString(\$val, $pos);
6307
+ } elsif ($type eq 'uri ') {
6308
+ $$items{$id}{URI} = GetString(\$val, $pos);
6309
+ }
6310
+ }
6311
+ $et->VPrint(1, "$$et{INDENT} Item $id: Type=", $$items{$id}{Type} || '',
6312
+ ' Name=', $$items{$id}{Name} || '',
6313
+ ' ContentType=', $$items{$id}{ContentType} || '',
6314
+ "\n") if $verbose > 1;
6315
+ return undef;
6316
+ }
6317
+
6318
+ #------------------------------------------------------------------------------
6319
+ # Parse item property association (ipma) box (ref https://github.com/gpac/gpac/blob/master/src/isomedia/iff.c)
6320
+ # Inputs: 0) infe data, 1) ExifTool ref
6321
+ # Returns: undef, and fills in ExifTool ItemInfo hash
6322
+ # Note: this information is currently not used by ExifTool (must figure out how to do this)
6323
+ sub ParseItemPropAssoc($$)
6324
+ {
6325
+ my ($val, $et) = @_;
6326
+ my ($i, $j, $id);
6327
+
6328
+ my $verbose = $et->Options('Verbose');
6329
+ my $items = $$et{ItemInfo} || ($$et{ItemInfo} = { });
6330
+ my $len = length $val;
6331
+ return undef if $len < 8;
6332
+ my $ver = Get8u(\$val, 0);
6333
+ my $flg = Get32u(\$val, 0);
6334
+ my $num = Get32u(\$val, 4);
6335
+ my $pos = 8;
6336
+ for ($i=0; $i<$num; ++$i) {
6337
+ if ($ver == 0) {
6338
+ return undef if $pos + 3 > $len;
6339
+ $id = Get16u(\$val, $pos);
6340
+ $pos += 2;
6341
+ } else {
6342
+ return undef if $pos + 5 > $len;
6343
+ $id = Get32u(\$val, $pos);
6344
+ $pos += 4;
6345
+ }
6346
+ my $n = Get8u(\$val, $pos++);
6347
+ my (@association, @essential);
6348
+ if ($flg & 0x01) {
6349
+ return undef if $pos + $n * 2 > $len;
6350
+ for ($j=0; $j<$n; ++$j) {
6351
+ my $tmp = Get16u(\$val, $pos + $j * 2);
6352
+ push @association, $tmp & 0x7fff;
6353
+ push @essential, ($tmp & 0x8000) ? 1 : 0;
6354
+ }
6355
+ $pos += $n * 2;
6356
+ } else {
6357
+ return undef if $pos + $n > $len;
6358
+ for ($j=0; $j<$n; ++$j) {
6359
+ my $tmp = Get8u(\$val, $pos + $j);
6360
+ push @association, $tmp & 0x7f;
6361
+ push @essential, ($tmp & 0x80) ? 1 : 0;
6362
+ }
6363
+ $pos += $n;
6364
+ }
6365
+ $$items{$id}{Association} = \@association;
6366
+ $$items{$id}{Essential} = \@essential;
6367
+ $et->VPrint(1, "$$et{INDENT} Item $id properties: @association\n") if $verbose > 1;
6368
+ }
6369
+ return undef;
6370
+ }
6371
+
6372
+ #------------------------------------------------------------------------------
6373
+ # Process item information now
6374
+ # Inputs: 0) ExifTool ref, 1) RAF ref
6375
+ sub HandleItemInfo($$)
6376
+ {
6377
+ my ($et, $raf) = @_;
6378
+ my $items = $$et{ItemInfo};
6379
+ my $buff;
6380
+
6381
+ # extract information from EXIF/XMP metadata items
6382
+ if ($items and $raf) {
6383
+ my $curPos = $raf->Tell();
6384
+ my $primary = $$et{PrimaryItem};
6385
+ my $id;
6386
+ foreach $id (sort { $a <=> $b } keys %$items) {
6387
+ my $item = $$items{$id};
6388
+ my $type = $$item{ContentType} || $$item{Type} || next;
6389
+ unless ($type eq 'Exif') {
6390
+ next unless $type eq 'application/rdf+xml';
6391
+ $type = 'XMP';
6392
+ }
6393
+ if ($$item{ContentEncoding}) {
6394
+ $et->WarnOnce("Can't currently decode encoded $type metadata");
6395
+ next;
6396
+ }
6397
+ if ($$item{ProtectionIndex}) {
6398
+ $et->WarnOnce("Can't currently decode protected $type metadata");
6399
+ next;
6400
+ }
6401
+ if ($$item{ConstructionMethod}) {
6402
+ $et->WarnOnce("Can't currently extract $type with construction method $$item{ConstructionMethod}");
6403
+ next;
6404
+ }
6405
+ next if $$item{DataReferenceIndex}; # (can only extract information from "this file")
6406
+ my ($extent, $proc);
6407
+ my $base = $$item{BaseOffset} || 0;
6408
+ undef $buff;
6409
+ my $val = '';
6410
+ foreach $extent (@{$$item{Extents}}) {
6411
+ $val .= $buff if defined $buff;
6412
+ $raf->Seek($$extent[1] + $base, 0) or last;
6413
+ $raf->Read($buff, $$extent[2]) or last;
6414
+ }
6415
+ next unless defined $buff;
6416
+ $buff = $val . $buff if length $val;
6417
+ my $start = $type eq 'Exif' ? 10 : 0; # skip count and "Exif\0\0" header
6418
+ my $pos = $$item{Extents}[0][1] + $base;
6419
+ my %dirInfo = (
6420
+ DataPt => \$buff,
6421
+ DataLen => length $buff,
6422
+ DirStart => $start,
6423
+ DirLen => length($buff) - $start,
6424
+ DataPos => $pos,
6425
+ Base => $pos, # (needed for IsOffset tags in binary data)
6426
+ );
6427
+ # handle processing of metadata for sub-documents
6428
+ if (defined $primary and $$item{RefersTo} and not $$item{RefersTo}{$primary}) {
6429
+ # set document number if this doesn't refer to the primary document
6430
+ $$et{DOC_NUM} = ++$$et{DOC_COUNT};
6431
+ # associate this document number with the lowest item index
6432
+ my ($lowest) = sort { $a <=> $b } keys %{$$item{RefersTo}};
6433
+ $$items{$lowest}{DocNum} = $$et{DOC_NUM};
6434
+ }
6435
+ my $subTable = GetTagTable('Image::ExifTool::' . $type . '::Main');
6436
+ $proc = \&Image::ExifTool::ProcessTIFF if $type eq 'Exif';
6437
+ $et->ProcessDirectory(\%dirInfo, $subTable, $proc);
6438
+ delete $$et{DOC_NUM};
6439
+ }
6440
+ $raf->Seek($curPos, 0); # seek back to original position
6441
+ }
6442
+ # process the item properties now that we should know their associations and document numbers
6443
+ if ($$et{ItemPropertyContainer}) {
6444
+ my ($dirInfo, $subTable, $proc) = @{$$et{ItemPropertyContainer}};
6445
+ $$et{IsItemProperty} = 1; # set item property flag
6446
+ $et->ProcessDirectory($dirInfo, $subTable, $proc);
6447
+ delete $$et{ItemPropertyContainer};
6448
+ delete $$et{IsItemProperty};
6449
+ delete $$et{DOC_NUM};
6450
+ }
6451
+ delete $$et{ItemInfo};
6452
+ }
6453
+
5975
6454
  #------------------------------------------------------------------------------
5976
6455
  # Process MPEG-4 MTDT atom (ref 11)
5977
6456
  # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
@@ -6219,7 +6698,10 @@ sub ProcessMOV($$;$)
6219
6698
  my $verbose = $et->Options('Verbose');
6220
6699
  my $dataPos = $$dirInfo{Base} || 0;
6221
6700
  my $charsetQuickTime = $et->Options('CharsetQuickTime');
6222
- my ($buff, $tag, $size, $track, $isUserData, %triplet, $doDefaultLang);
6701
+ my ($buff, $tag, $size, $track, $isUserData, %triplet, $doDefaultLang, $index);
6702
+
6703
+ my $topLevel = not $$et{InQuickTime};
6704
+ $$et{InQuickTime} = 1;
6223
6705
 
6224
6706
  unless (defined $$et{KeyCount}) {
6225
6707
  $$et{KeyCount} = 0; # initialize ItemList key directory count
@@ -6272,6 +6754,7 @@ sub ProcessMOV($$;$)
6272
6754
  SetByteOrder('MM');
6273
6755
  $$et{PRIORITY_DIR} = 'XMP'; # have XMP take priority
6274
6756
  }
6757
+ $index = $$tagTablePtr{VARS}{START_INDEX} if $$tagTablePtr{VARS};
6275
6758
  for (;;) {
6276
6759
  if ($size < 8) {
6277
6760
  if ($size == 0) {
@@ -6372,6 +6855,40 @@ sub ProcessMOV($$;$)
6372
6855
  }
6373
6856
  }
6374
6857
  if (defined $tagInfo and not $ignore) {
6858
+ # set document number for this item property if necessary
6859
+ if ($$et{IsItemProperty}) {
6860
+ my $items = $$et{ItemInfo};
6861
+ my ($id, $prop, $mainItem, $docNum, $lowest);
6862
+ my $primary = $$et{PrimaryItem} || 0;
6863
+ ItemID: foreach $id (keys %$items) {
6864
+ next unless $$items{$id}{Association};
6865
+ my $item = $$items{$id};
6866
+ foreach $prop (@{$$item{Association}}) {
6867
+ next unless $prop == $index;
6868
+ if ($id == $primary or (not $$item{RefersTo} or $$item{RefersTo}{$primary})) {
6869
+ # this is associated with the primary item or an item describing
6870
+ # the primary item, so consider this part of the main document
6871
+ undef $docNum;
6872
+ undef $lowest;
6873
+ last ItemID;
6874
+ } elsif ($$item{DocNum}) {
6875
+ # this property is already associated with an item that has
6876
+ # an ExifTool document number, so use the lowest assocated DocNum
6877
+ $docNum = $$item{DocNum} if not defined $docNum or $docNum > $$item{DocNum};
6878
+ } elsif (not defined $lowest or $lowest > $id) {
6879
+ # keep track of the lowest associated item ID
6880
+ $lowest = $id;
6881
+ }
6882
+ }
6883
+ }
6884
+ if (not defined $docNum and defined $lowest) {
6885
+ # this is the first time we've seen metadata from this item,
6886
+ # so use a new document number
6887
+ $docNum = ++$$et{DOC_COUNT};
6888
+ $$items{$lowest}{DocNum} = $docNum;
6889
+ }
6890
+ $$et{DOC_NUM} = $docNum;
6891
+ }
6375
6892
  my $val;
6376
6893
  my $missing = $size - $raf->Read($val, $size);
6377
6894
  if ($missing) {
@@ -6392,6 +6909,7 @@ sub ProcessMOV($$;$)
6392
6909
  DataPos => $dataPos,
6393
6910
  Size => $size,
6394
6911
  Format => $tagInfo ? $$tagInfo{Format} : undef,
6912
+ Index => $index,
6395
6913
  );
6396
6914
  }
6397
6915
  # handle iTunesInfo mean/name/data triplets
@@ -6462,9 +6980,19 @@ sub ProcessMOV($$;$)
6462
6980
  my $proc = $$subdir{ProcessProc};
6463
6981
  # make ProcessMOV() the default processing procedure for subdirectories
6464
6982
  $proc = \&ProcessMOV unless $proc or $$subTable{PROCESS_PROC};
6465
- $et->ProcessDirectory(\%dirInfo, $subTable, $proc) if $size > $start;
6983
+ if ($size > $start) {
6984
+ # delay processing of ipco box until after all other boxes
6985
+ if ($tag eq 'ipco' and not $$et{IsItemProperty}) {
6986
+ $$et{ItemPropertyContainer} = [ \%dirInfo, $subTable, $proc ];
6987
+ $et->VPrint(0,"$$et{INDENT}\[Process ipco box later]");
6988
+ } else {
6989
+ $et->ProcessDirectory(\%dirInfo, $subTable, $proc);
6990
+ }
6991
+ }
6466
6992
  $$et{SET_GROUP1} = $oldGroup1;
6467
6993
  SetByteOrder('MM');
6994
+ # handle metadata now if iwe just processed the 'meta' box
6995
+ HandleItemInfo($et, $raf) if $tag eq 'meta';
6468
6996
  } elsif ($hasData) {
6469
6997
  # handle atoms containing 'data' tags
6470
6998
  # (currently ignore contained atoms: 'itif', 'name', etc.)
@@ -6550,6 +7078,7 @@ sub ProcessMOV($$;$)
6550
7078
  Start => $pos,
6551
7079
  Size => $len,
6552
7080
  Format => $format,
7081
+ Index => $index,
6553
7082
  Extra => sprintf(", Type='$type', Flags=0x%x",$flags)
6554
7083
  ) if $verbose;
6555
7084
  $et->FoundTag($langInfo, $value) if defined $value;
@@ -6638,6 +7167,7 @@ sub ProcessMOV($$;$)
6638
7167
  $raf->Read($buff, 8) == 8 or last;
6639
7168
  $dataPos += $size + 8;
6640
7169
  ($size, $tag) = unpack('Na4', $buff);
7170
+ ++$index if defined $index;
6641
7171
  }
6642
7172
  # fill in missing defaults for alternate language tags
6643
7173
  # (the first language is taken as the default)
@@ -6658,6 +7188,7 @@ QTLang: foreach $tag (@{$$et{QTLang}}) {
6658
7188
  }
6659
7189
  delete $$et{QTLang};
6660
7190
  }
7191
+ HandleItemInfo($et, $raf) if $topLevel;
6661
7192
  return 1;
6662
7193
  }
6663
7194
 
@@ -6687,7 +7218,7 @@ This module is used by Image::ExifTool
6687
7218
  =head1 DESCRIPTION
6688
7219
 
6689
7220
  This module contains routines required by Image::ExifTool to extract
6690
- information from QuickTime and MP4 video, and M4A audio files.
7221
+ information from QuickTime and MP4 video, M4A audio, and HEIC image files.
6691
7222
 
6692
7223
  =head1 AUTHOR
6693
7224