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.
- checksums.yaml +4 -4
- data/bin/Changes +100 -1
- data/bin/MANIFEST +2 -0
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +39 -38
- data/bin/arg_files/exif2iptc.args +3 -0
- data/bin/arg_files/iptc2exif.args +3 -0
- data/bin/config_files/example.config +16 -14
- data/bin/config_files/photoshop_paths.config +10 -0
- data/bin/exiftool +71 -65
- data/bin/lib/Image/ExifTool/APE.pm +5 -0
- data/bin/lib/Image/ExifTool/BuildTagLookup.pm +31 -15
- data/bin/lib/Image/ExifTool/Canon.pm +18 -4
- data/bin/lib/Image/ExifTool/CanonCustom.pm +3 -0
- data/bin/lib/Image/ExifTool/Charset/DOSLatin1.pm +49 -0
- data/bin/lib/Image/ExifTool/Charset/DOSLatinUS.pm +49 -0
- data/bin/lib/Image/ExifTool/Charset.pm +8 -5
- data/bin/lib/Image/ExifTool/Exif.pm +37 -18
- data/bin/lib/Image/ExifTool/FLAC.pm +47 -37
- data/bin/lib/Image/ExifTool/FLIR.pm +3 -3
- data/bin/lib/Image/ExifTool/FujiFilm.pm +5 -2
- data/bin/lib/Image/ExifTool/GPS.pm +6 -6
- data/bin/lib/Image/ExifTool/Geotag.pm +1 -1
- data/bin/lib/Image/ExifTool/H264.pm +2 -0
- data/bin/lib/Image/ExifTool/ID3.pm +8 -3
- data/bin/lib/Image/ExifTool/IPTC.pm +1 -1
- data/bin/lib/Image/ExifTool/Import.pm +4 -1
- data/bin/lib/Image/ExifTool/InDesign.pm +11 -7
- data/bin/lib/Image/ExifTool/Kodak.pm +4 -1
- data/bin/lib/Image/ExifTool/Lang/de.pm +31 -31
- data/bin/lib/Image/ExifTool/MWG.pm +12 -4
- data/bin/lib/Image/ExifTool/MakerNotes.pm +3 -3
- data/bin/lib/Image/ExifTool/Matroska.pm +2 -1
- data/bin/lib/Image/ExifTool/Microsoft.pm +3 -3
- data/bin/lib/Image/ExifTool/Minolta.pm +71 -61
- data/bin/lib/Image/ExifTool/Nikon.pm +286 -43
- data/bin/lib/Image/ExifTool/NikonCustom.pm +1049 -0
- data/bin/lib/Image/ExifTool/Olympus.pm +4 -1
- data/bin/lib/Image/ExifTool/PNG.pm +4 -7
- data/bin/lib/Image/ExifTool/PanasonicRaw.pm +24 -1
- data/bin/lib/Image/ExifTool/Pentax.pm +20 -6
- data/bin/lib/Image/ExifTool/Photoshop.pm +24 -3
- data/bin/lib/Image/ExifTool/QuickTime.pm +545 -14
- data/bin/lib/Image/ExifTool/README +16 -9
- data/bin/lib/Image/ExifTool/RIFF.pm +8 -1
- data/bin/lib/Image/ExifTool/Samsung.pm +5 -4
- data/bin/lib/Image/ExifTool/Sigma.pm +9 -1
- data/bin/lib/Image/ExifTool/Sony.pm +327 -153
- data/bin/lib/Image/ExifTool/TagLookup.pm +3273 -3220
- data/bin/lib/Image/ExifTool/TagNames.pod +317 -38
- data/bin/lib/Image/ExifTool/Validate.pm +15 -1
- data/bin/lib/Image/ExifTool/WriteExif.pl +5 -0
- data/bin/lib/Image/ExifTool/WriteIPTC.pl +23 -1
- data/bin/lib/Image/ExifTool/WriteQuickTime.pl +8 -2
- data/bin/lib/Image/ExifTool/WriteXMP.pl +7 -0
- data/bin/lib/Image/ExifTool/Writer.pl +96 -18
- data/bin/lib/Image/ExifTool/XMP.pm +20 -11
- data/bin/lib/Image/ExifTool/XMP2.pl +634 -583
- data/bin/lib/Image/ExifTool.pm +124 -17
- data/bin/lib/Image/ExifTool.pod +86 -82
- data/bin/perl-Image-ExifTool.spec +38 -37
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +4 -2
@@ -1,7 +1,7 @@
|
|
1
1
|
#------------------------------------------------------------------------------
|
2
2
|
# File: QuickTime.pm
|
3
3
|
#
|
4
|
-
# Description: Read QuickTime
|
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.
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
#
|
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
|
-
|
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,
|
7221
|
+
information from QuickTime and MP4 video, M4A audio, and HEIC image files.
|
6691
7222
|
|
6692
7223
|
=head1 AUTHOR
|
6693
7224
|
|