exiftool_vendored 12.18.0 → 12.33.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/Changes +236 -4
- data/bin/MANIFEST +23 -0
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +45 -43
- data/bin/arg_files/xmp2exif.args +2 -1
- data/bin/config_files/acdsee.config +193 -6
- data/bin/config_files/convert_regions.config +25 -14
- data/bin/config_files/cuepointlist.config +70 -0
- data/bin/config_files/example.config +2 -9
- data/bin/exiftool +152 -97
- data/bin/fmt_files/gpx.fmt +2 -2
- data/bin/fmt_files/gpx_wpt.fmt +2 -2
- data/bin/fmt_files/kml.fmt +1 -1
- data/bin/fmt_files/kml_track.fmt +1 -1
- data/bin/lib/Image/ExifTool/Apple.pm +3 -2
- data/bin/lib/Image/ExifTool/BuildTagLookup.pm +31 -13
- data/bin/lib/Image/ExifTool/CBOR.pm +331 -0
- data/bin/lib/Image/ExifTool/Canon.pm +44 -19
- data/bin/lib/Image/ExifTool/DJI.pm +6 -6
- data/bin/lib/Image/ExifTool/DPX.pm +13 -2
- data/bin/lib/Image/ExifTool/DjVu.pm +6 -5
- data/bin/lib/Image/ExifTool/Exif.pm +124 -13
- data/bin/lib/Image/ExifTool/FITS.pm +13 -2
- data/bin/lib/Image/ExifTool/FlashPix.pm +35 -10
- data/bin/lib/Image/ExifTool/FujiFilm.pm +19 -8
- data/bin/lib/Image/ExifTool/GPS.pm +22 -11
- data/bin/lib/Image/ExifTool/Geotag.pm +13 -2
- data/bin/lib/Image/ExifTool/GoPro.pm +16 -1
- data/bin/lib/Image/ExifTool/ICC_Profile.pm +2 -2
- data/bin/lib/Image/ExifTool/ID3.pm +15 -3
- data/bin/lib/Image/ExifTool/JPEG.pm +74 -4
- data/bin/lib/Image/ExifTool/JSON.pm +30 -5
- data/bin/lib/Image/ExifTool/Jpeg2000.pm +395 -16
- data/bin/lib/Image/ExifTool/LIF.pm +153 -0
- data/bin/lib/Image/ExifTool/Lang/nl.pm +60 -59
- data/bin/lib/Image/ExifTool/M2TS.pm +137 -5
- data/bin/lib/Image/ExifTool/MIE.pm +4 -3
- data/bin/lib/Image/ExifTool/MRC.pm +341 -0
- data/bin/lib/Image/ExifTool/MWG.pm +3 -3
- data/bin/lib/Image/ExifTool/MXF.pm +1 -1
- data/bin/lib/Image/ExifTool/MacOS.pm +3 -3
- data/bin/lib/Image/ExifTool/Microsoft.pm +298 -82
- data/bin/lib/Image/ExifTool/Nikon.pm +18 -5
- data/bin/lib/Image/ExifTool/NikonSettings.pm +19 -2
- data/bin/lib/Image/ExifTool/Olympus.pm +10 -3
- data/bin/lib/Image/ExifTool/Other.pm +93 -0
- data/bin/lib/Image/ExifTool/PDF.pm +9 -12
- data/bin/lib/Image/ExifTool/PNG.pm +8 -7
- data/bin/lib/Image/ExifTool/Panasonic.pm +28 -3
- data/bin/lib/Image/ExifTool/Pentax.pm +28 -5
- data/bin/lib/Image/ExifTool/PhaseOne.pm +4 -3
- data/bin/lib/Image/ExifTool/Photoshop.pm +6 -0
- data/bin/lib/Image/ExifTool/QuickTime.pm +234 -75
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +283 -141
- data/bin/lib/Image/ExifTool/README +5 -2
- data/bin/lib/Image/ExifTool/RIFF.pm +89 -12
- data/bin/lib/Image/ExifTool/Samsung.pm +48 -10
- data/bin/lib/Image/ExifTool/Shortcuts.pm +9 -0
- data/bin/lib/Image/ExifTool/Sony.pm +230 -69
- data/bin/lib/Image/ExifTool/TagInfoXML.pm +1 -0
- data/bin/lib/Image/ExifTool/TagLookup.pm +4145 -4029
- data/bin/lib/Image/ExifTool/TagNames.pod +671 -287
- data/bin/lib/Image/ExifTool/Torrent.pm +18 -11
- data/bin/lib/Image/ExifTool/WriteExif.pl +1 -1
- data/bin/lib/Image/ExifTool/WriteIPTC.pl +1 -1
- data/bin/lib/Image/ExifTool/WritePDF.pl +1 -0
- data/bin/lib/Image/ExifTool/WritePNG.pl +2 -0
- data/bin/lib/Image/ExifTool/WritePostScript.pl +1 -0
- data/bin/lib/Image/ExifTool/WriteQuickTime.pl +55 -21
- data/bin/lib/Image/ExifTool/WriteXMP.pl +7 -3
- data/bin/lib/Image/ExifTool/Writer.pl +47 -10
- data/bin/lib/Image/ExifTool/XMP.pm +45 -15
- data/bin/lib/Image/ExifTool/XMP2.pl +3 -1
- data/bin/lib/Image/ExifTool/XMPStruct.pl +3 -1
- data/bin/lib/Image/ExifTool/ZISRAW.pm +121 -2
- data/bin/lib/Image/ExifTool.pm +233 -81
- data/bin/lib/Image/ExifTool.pod +114 -93
- data/bin/perl-Image-ExifTool.spec +43 -42
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +28 -13
@@ -47,7 +47,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
|
|
47
47
|
use Image::ExifTool::Exif;
|
48
48
|
use Image::ExifTool::GPS;
|
49
49
|
|
50
|
-
$VERSION = '2.
|
50
|
+
$VERSION = '2.70';
|
51
51
|
|
52
52
|
sub ProcessMOV($$;$);
|
53
53
|
sub ProcessKeys($$$);
|
@@ -65,6 +65,7 @@ sub Process_gsen($$$);
|
|
65
65
|
sub ProcessRIFFTrailer($$$);
|
66
66
|
sub ProcessTTAD($$$);
|
67
67
|
sub ProcessNMEA($$$);
|
68
|
+
sub ProcessGPSLog($$$);
|
68
69
|
sub SaveMetaKeys($$$);
|
69
70
|
# ++^^^^^^^^^^^^++
|
70
71
|
sub ParseItemLocation($$);
|
@@ -160,8 +161,15 @@ my %ftypLookup = (
|
|
160
161
|
'F4P ' => 'Protected Video for Adobe Flash Player 9+ (.F4P)', # video/mp4
|
161
162
|
'F4V ' => 'Video for Adobe Flash Player 9+ (.F4V)', # video/mp4
|
162
163
|
'isc2' => 'ISMACryp 2.0 Encrypted File', # ?/enc-isoff-generic
|
163
|
-
'iso2' => 'MP4 Base Media v2 [ISO 14496-12:2005]', # video/mp4
|
164
|
-
'
|
164
|
+
'iso2' => 'MP4 Base Media v2 [ISO 14496-12:2005]', # video/mp4 (or audio)
|
165
|
+
'iso3' => 'MP4 Base Media v3', # video/mp4 (or audio)
|
166
|
+
'iso4' => 'MP4 Base Media v4', # video/mp4 (or audio)
|
167
|
+
'iso5' => 'MP4 Base Media v5', # video/mp4 (or audio)
|
168
|
+
'iso6' => 'MP4 Base Media v6', # video/mp4 (or audio)
|
169
|
+
'iso7' => 'MP4 Base Media v7', # video/mp4 (or audio)
|
170
|
+
'iso8' => 'MP4 Base Media v8', # video/mp4 (or audio)
|
171
|
+
'iso9' => 'MP4 Base Media v9', # video/mp4 (or audio)
|
172
|
+
'isom' => 'MP4 Base Media v1 [IS0 14496-12:2003]', # video/mp4 (or audio)
|
165
173
|
'JP2 ' => 'JPEG 2000 Image (.JP2) [ISO 15444-1 ?]', # image/jp2
|
166
174
|
'JP20' => 'Unknown, from GPAC samples (prob non-existent)',
|
167
175
|
'jpm ' => 'JPEG 2000 Compound Image (.JPM) [ISO 15444-6]', # image/jpm
|
@@ -221,9 +229,10 @@ my %timeInfo = (
|
|
221
229
|
Writable => 1,
|
222
230
|
Permanent => 1,
|
223
231
|
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
|
232
|
+
# It is not uncommon for brain-dead software to use the wrong time zero, it should be
|
233
|
+
# Jan 1, 1904, so assume a time zero of Jan 1, 1970 if the date is before this
|
226
234
|
# Note: This value will be in UTC if generated by a system that is aware of the time zone
|
235
|
+
# (also note: this code is duplicated for the CreateDate tag)
|
227
236
|
RawConv => q{
|
228
237
|
my $offset = (66 * 365 + 17) * 24 * 3600;
|
229
238
|
return $val - $offset if $val >= $offset or $$self{OPTIONS}{QuickTimeUTC};
|
@@ -243,7 +252,11 @@ my %timeInfo = (
|
|
243
252
|
},
|
244
253
|
# (all CR3 files store UTC times - PH)
|
245
254
|
ValueConv => 'ConvertUnixTime($val, $self->Options("QuickTimeUTC") || $$self{FileType} eq "CR3")',
|
246
|
-
ValueConvInv =>
|
255
|
+
ValueConvInv => q{
|
256
|
+
$val = GetUnixTime($val, $self->Options("QuickTimeUTC"));
|
257
|
+
return undef unless defined $val;
|
258
|
+
return $val + (66 * 365 + 17) * 24 * 3600;
|
259
|
+
},
|
247
260
|
PrintConv => '$self->ConvertDateTime($val)',
|
248
261
|
PrintConvInv => '$self->InverseDateTime($val)',
|
249
262
|
# (can't put Groups here because they aren't constant!)
|
@@ -674,6 +687,15 @@ my %eeBox2 = (
|
|
674
687
|
udat => { #PH (GPS NMEA-format log written by Datakam Player software)
|
675
688
|
Name => 'GPSLog',
|
676
689
|
Binary => 1, # (actually ASCII, but very lengthy)
|
690
|
+
Notes => 'parsed to extract GPS separately when ExtractEmbedded is used',
|
691
|
+
RawConv => q{
|
692
|
+
$val =~ s/\0+$//; # remove trailing nulls
|
693
|
+
if (length $val and $$self{OPTIONS}{ExtractEmbedded}) {
|
694
|
+
my $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream');
|
695
|
+
Image::ExifTool::QuickTime::ProcessGPSLog($self, { DataPt => \$val }, $tagTbl);
|
696
|
+
}
|
697
|
+
return $val;
|
698
|
+
},
|
677
699
|
},
|
678
700
|
# meta - proprietary XML information written by some Flip cameras - PH
|
679
701
|
# beam - 16 bytes found in an iPhone video
|
@@ -712,6 +734,11 @@ my %eeBox2 = (
|
|
712
734
|
Unknown => 1,
|
713
735
|
Binary => 1,
|
714
736
|
},
|
737
|
+
sefd => {
|
738
|
+
Name => 'SamsungTrailer',
|
739
|
+
SubDirectory => { TagTable => 'Image::ExifTool::Samsung::Trailer' },
|
740
|
+
},
|
741
|
+
# 'samn'? - seen in Vantrue N2S sample video
|
715
742
|
);
|
716
743
|
|
717
744
|
# MPEG-4 'ftyp' atom
|
@@ -1173,6 +1200,15 @@ my %eeBox2 = (
|
|
1173
1200
|
Name => 'CreateDate',
|
1174
1201
|
Groups => { 2 => 'Time' },
|
1175
1202
|
%timeInfo,
|
1203
|
+
RawConv => q{
|
1204
|
+
my $offset = (66 * 365 + 17) * 24 * 3600;
|
1205
|
+
if ($val >= $offset or $$self{OPTIONS}{QuickTimeUTC}) {
|
1206
|
+
$val -= $offset;
|
1207
|
+
} elsif ($val and not $$self{IsWriting}) {
|
1208
|
+
$self->WarnOnce('Patched incorrect time zero for QuickTime date/time tag',1);
|
1209
|
+
}
|
1210
|
+
return $$self{CreateDate} = $val;
|
1211
|
+
},
|
1176
1212
|
# this is int64u if MovieHeaderVersion == 1 (ref 13)
|
1177
1213
|
Hook => '$$self{MovieHeaderVersion} and $format = "int64u", $varSize += 4',
|
1178
1214
|
},
|
@@ -1560,36 +1596,29 @@ my %eeBox2 = (
|
|
1560
1596
|
coll => { Name => 'CollectionName', %langText3gp }, #17
|
1561
1597
|
rtng => {
|
1562
1598
|
Name => 'Rating',
|
1599
|
+
Writable => 'undef',
|
1600
|
+
Avoid => 1,
|
1563
1601
|
# (4-byte flags, 4-char entity, 4-char criteria, 2-byte lang, string)
|
1564
|
-
|
1565
|
-
|
1566
|
-
|
1567
|
-
|
1568
|
-
my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 12));
|
1569
|
-
$lang = $lang ? "($lang) " : '';
|
1570
|
-
$val = substr($val, 14);
|
1571
|
-
$val = $self->Decode($val, 'UCS2') if $val =~ /^\xfe\xff/;
|
1572
|
-
return $lang . $str . ' ' . $val;
|
1573
|
-
},
|
1602
|
+
IText => 14, # (14 bytes before string)
|
1603
|
+
Notes => 'string in the form "Entity=XXXX Criteria=XXXX XXXXX", used in 3gp videos',
|
1604
|
+
ValueConv => '$val=~s/^(.{4})(.{4})/Entity=$1 Criteria=$2 /i; $val',
|
1605
|
+
ValueConvInv => '$val=~s/Entity=(.{4}) Criteria=(.{4}) ?/$1$2/i; $val',
|
1574
1606
|
},
|
1575
1607
|
clsf => {
|
1576
1608
|
Name => 'Classification',
|
1609
|
+
Writable => 'undef',
|
1610
|
+
Avoid => 1,
|
1577
1611
|
# (4-byte flags, 4-char entity, 2-byte index, 2-byte lang, string)
|
1578
|
-
|
1579
|
-
|
1580
|
-
|
1581
|
-
|
1582
|
-
my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 10));
|
1583
|
-
$lang = $lang ? "($lang) " : '';
|
1584
|
-
$val = substr($val, 12);
|
1585
|
-
$val = $self->Decode($val, 'UCS2') if $val =~ /^\xfe\xff/;
|
1586
|
-
return $lang . $str . ' ' . $val;
|
1587
|
-
},
|
1612
|
+
IText => 12,
|
1613
|
+
Notes => 'string in the form "Entity=XXXX Index=### XXXXX", used in 3gp videos',
|
1614
|
+
ValueConv => '$val=~s/^(.{4})(.{2})/"Entity=$1 Index=".unpack("n",$2)." "/ie; $val',
|
1615
|
+
ValueConvInv => '$val=~s/Entity=(.{4}) Index=(\d+) ?/$1.pack("n",$2)/ie; $val',
|
1588
1616
|
},
|
1589
1617
|
kywd => {
|
1590
1618
|
Name => 'Keywords',
|
1591
1619
|
# (4 byte flags, 2-byte lang, 1-byte count, count x pascal strings, ref 17)
|
1592
|
-
# (but I have also seen a simple string written by iPhone)
|
1620
|
+
# (but I have also seen a simple string written by iPhone, so don't make writable yet)
|
1621
|
+
Notes => "not writable because Apple doesn't follow the 3gp specification",
|
1593
1622
|
RawConv => q{
|
1594
1623
|
my $sep = $self->Options('ListSep');
|
1595
1624
|
return join($sep, split /\0+/, $val) unless $val =~ /^\0/; # (iPhone)
|
@@ -1614,20 +1643,24 @@ my %eeBox2 = (
|
|
1614
1643
|
loci => {
|
1615
1644
|
Name => 'LocationInformation',
|
1616
1645
|
Groups => { 2 => 'Location' },
|
1646
|
+
Writable => 'undef',
|
1647
|
+
IText => 6,
|
1648
|
+
Avoid => 1,
|
1649
|
+
NoDecode => 1, # (we'll decode the data ourself)
|
1650
|
+
Notes => q{
|
1651
|
+
string in the form "XXXXX Role=XXX Lat=XXX Lon=XXX Alt=XXX Body=XXX
|
1652
|
+
Notes=XXX", used in 3gp videos
|
1653
|
+
},
|
1617
1654
|
# (4-byte flags, 2-byte lang, location string, 1-byte role, 4-byte fixed longitude,
|
1618
1655
|
# 4-byte fixed latitude, 4-byte fixed altitude, body string, notes string)
|
1619
1656
|
RawConv => q{
|
1620
|
-
return '<err>' unless length $val >= 6;
|
1621
|
-
my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 4));
|
1622
|
-
$lang = $lang ? "($lang) " : '';
|
1623
|
-
$val = substr($val, 6);
|
1624
1657
|
my $str;
|
1625
1658
|
if ($val =~ /^\xfe\xff/) {
|
1626
1659
|
$val =~ s/^(\xfe\xff(.{2})*?)\0\0//s or return '<err>';
|
1627
1660
|
$str = $self->Decode($1, 'UCS2');
|
1628
1661
|
} else {
|
1629
1662
|
$val =~ s/^(.*?)\0//s or return '<err>';
|
1630
|
-
$str = $1;
|
1663
|
+
$str = $self->Decode($1, 'UTF8');
|
1631
1664
|
}
|
1632
1665
|
$str = '(none)' unless length $str;
|
1633
1666
|
return '<err>' if length $val < 13;
|
@@ -1642,27 +1675,52 @@ my %eeBox2 = (
|
|
1642
1675
|
if ($val =~ s/^(\xfe\xff(.{2})*?)\0\0//s) {
|
1643
1676
|
$str .= ' Body=' . $self->Decode($1, 'UCS2');
|
1644
1677
|
} elsif ($val =~ s/^(.*?)\0//s) {
|
1645
|
-
$str .=
|
1678
|
+
$str .= ' Body=' . $self->Decode($1, 'UTF8');
|
1646
1679
|
}
|
1647
1680
|
if ($val =~ s/^(\xfe\xff(.{2})*?)\0\0//s) {
|
1648
1681
|
$str .= ' Notes=' . $self->Decode($1, 'UCS2');
|
1649
1682
|
} elsif ($val =~ s/^(.*?)\0//s) {
|
1650
|
-
$str .=
|
1683
|
+
$str .= ' Notes=' . $self->Decode($1, 'UTF8');
|
1651
1684
|
}
|
1652
|
-
return $
|
1685
|
+
return $str;
|
1686
|
+
},
|
1687
|
+
RawConvInv => q{
|
1688
|
+
my ($role, $lat, $lon, $alt, $body, $note);
|
1689
|
+
$lat = $1 if $val =~ s/ Lat=([-+]?[.\d]+)//i;
|
1690
|
+
$lon = $1 if $val =~ s/ Lon=([-+]?[.\d]+)//i;
|
1691
|
+
$alt = $1 if $val =~ s/ Alt=([-+]?[.\d]+)//i;
|
1692
|
+
$note = $val =~ s/ Notes=(.*)//i ? $1 : '';
|
1693
|
+
$body = $val =~ s/ Body=(.*)//i ? $1 : '';
|
1694
|
+
$role = $val =~ s/ Role=(.*)//i ? $1 : '';
|
1695
|
+
$val = '' if $val eq '(none)';
|
1696
|
+
$role = {shooting=>0,real=>1,fictional=>2}->{lc $role} || 0;
|
1697
|
+
return $self->Encode($val, 'UTF8') . "\0" . Set8u($role) .
|
1698
|
+
SetFixed32s(defined $lon ? $lon : 999) .
|
1699
|
+
SetFixed32s(defined $lat ? $lat : 999) .
|
1700
|
+
SetFixed32s(defined $alt ? $alt : 0) .
|
1701
|
+
$self->Encode($body) . "\0" .
|
1702
|
+
$self->Encode($note) . "\0";
|
1653
1703
|
},
|
1654
1704
|
},
|
1655
1705
|
yrrc => {
|
1656
1706
|
Name => 'Year',
|
1707
|
+
Writable => 'undef',
|
1657
1708
|
Groups => { 2 => 'Time' },
|
1658
|
-
|
1709
|
+
Avoid => 1,
|
1710
|
+
Notes => 'used in 3gp videos',
|
1711
|
+
ValueConv => 'length($val) >= 6 ? unpack("x4n",$val) : "<err>"',
|
1712
|
+
ValueConvInv => 'pack("Nn",0,$val)',
|
1659
1713
|
},
|
1660
1714
|
urat => { #17
|
1661
1715
|
Name => 'UserRating',
|
1662
|
-
|
1716
|
+
Writable => 'undef',
|
1717
|
+
Notes => 'used in 3gp videos',
|
1718
|
+
Avoid => 1,
|
1719
|
+
ValueConv => q{
|
1663
1720
|
return '<err>' unless length $val >= 8;
|
1664
|
-
|
1721
|
+
unpack('x7C', $val);
|
1665
1722
|
},
|
1723
|
+
ValueConvInv => 'pack("N2",0,$val)',
|
1666
1724
|
},
|
1667
1725
|
# tsel - TrackSelection (ref 17)
|
1668
1726
|
# Apple tags (ref 16[dead] -- see ref 25 instead)
|
@@ -1994,7 +2052,11 @@ my %eeBox2 = (
|
|
1994
2052
|
# ---- Microsoft ----
|
1995
2053
|
Xtra => { #PH (microsoft)
|
1996
2054
|
Name => 'MicrosoftXtra',
|
1997
|
-
|
2055
|
+
WriteGroup => 'Microsoft',
|
2056
|
+
SubDirectory => {
|
2057
|
+
DirName => 'Microsoft',
|
2058
|
+
TagTable => 'Image::ExifTool::Microsoft::Xtra',
|
2059
|
+
},
|
1998
2060
|
},
|
1999
2061
|
# ---- Minolta ----
|
2000
2062
|
MMA0 => { #PH (DiMage 7Hi)
|
@@ -2207,6 +2269,12 @@ my %eeBox2 = (
|
|
2207
2269
|
# opax - 164 bytes unknown (center and affine arrays? ref 26)
|
2208
2270
|
# opai - 32 bytes (maybe contains a serial number starting at byte 16? - PH) (rgb gains, degamma, gamma? ref 26)
|
2209
2271
|
# intv - 16 bytes all zero
|
2272
|
+
# ---- Xaiomi ----
|
2273
|
+
mcvr => {
|
2274
|
+
Name => 'PreviewImage',
|
2275
|
+
Groups => { 2 => 'Preview' },
|
2276
|
+
Binary => 1,
|
2277
|
+
},
|
2210
2278
|
# ---- Unknown ----
|
2211
2279
|
# CDET - 128 bytes (unknown origin)
|
2212
2280
|
# mtyp - 4 bytes all zero (some drone video)
|
@@ -2644,6 +2712,7 @@ my %eeBox2 = (
|
|
2644
2712
|
colr => [{
|
2645
2713
|
Name => 'ICC_Profile',
|
2646
2714
|
Condition => '$$valPt =~ /^(prof|rICC)/',
|
2715
|
+
Permanent => 0, # (in QuickTime, this writes a zero-length box instead of deleting)
|
2647
2716
|
SubDirectory => {
|
2648
2717
|
TagTable => 'Image::ExifTool::ICC_Profile::Main',
|
2649
2718
|
Start => 4,
|
@@ -3000,9 +3069,9 @@ my %eeBox2 = (
|
|
3000
3069
|
3-character ISO 639-2 language code and an optional ISO 3166-1 alpha 2
|
3001
3070
|
country code to the tag name (eg. "ItemList:Title-fra" or
|
3002
3071
|
"ItemList::Title-fra-FR"). When creating a new Meta box to contain the
|
3003
|
-
ItemList directory, by default ExifTool
|
3004
|
-
|
3005
|
-
|
3072
|
+
ItemList directory, by default ExifTool adds an 'mdir' (Metadata) Handler
|
3073
|
+
box because Apple software may ignore ItemList tags otherwise, but the API
|
3074
|
+
L<QuickTimeHandler|../ExifTool.html#QuickTimeHandler> option may be set to 0 to avoid this.
|
3006
3075
|
},
|
3007
3076
|
# in this table, binary 1 and 2-byte "data"-type tags are interpreted as
|
3008
3077
|
# int8u and int16u. Multi-byte binary "data" tags are extracted as binary data.
|
@@ -6163,13 +6232,12 @@ my %eeBox2 = (
|
|
6163
6232
|
PROCESS_PROC => \&ProcessKeys,
|
6164
6233
|
WRITE_PROC => \&WriteKeys,
|
6165
6234
|
CHECK_PROC => \&CheckQTValue,
|
6166
|
-
VARS => { LONG_TAGS =>
|
6235
|
+
VARS => { LONG_TAGS => 7 },
|
6167
6236
|
WRITABLE => 1,
|
6168
6237
|
# (not PREFERRED when writing)
|
6169
6238
|
GROUPS => { 1 => 'Keys' },
|
6170
6239
|
WRITE_GROUP => 'Keys',
|
6171
6240
|
LANG_INFO => \&GetLangInfo,
|
6172
|
-
FORMAT => 'string',
|
6173
6241
|
NOTES => q{
|
6174
6242
|
This directory contains a list of key names which are used to decode tags
|
6175
6243
|
written by the "mdta" handler. Also in this table are a few tags found in
|
@@ -6235,6 +6303,10 @@ my %eeBox2 = (
|
|
6235
6303
|
'location.ISO6709' => {
|
6236
6304
|
Name => 'GPSCoordinates',
|
6237
6305
|
Groups => { 2 => 'Location' },
|
6306
|
+
Notes => q{
|
6307
|
+
Google Photos may ignore this if the coorinates have more than 5 digits
|
6308
|
+
after the decimal
|
6309
|
+
},
|
6238
6310
|
ValueConv => \&ConvertISO6709,
|
6239
6311
|
ValueConvInv => \&ConvInvISO6709,
|
6240
6312
|
PrintConv => \&PrintGPSCoordinates,
|
@@ -6271,6 +6343,11 @@ my %eeBox2 = (
|
|
6271
6343
|
PrintConv => '$self->ConvertDateTime($val)',
|
6272
6344
|
PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist)
|
6273
6345
|
},
|
6346
|
+
'location.accuracy.horizontal' => { Name => 'LocationAccuracyHorizontal' },
|
6347
|
+
'live-photo.auto' => { Name => 'LivePhotoAuto', Writable => 'int8u' },
|
6348
|
+
'live-photo.vitality-score' => { Name => 'LivePhotoVitalityScore', Writable => 'float' },
|
6349
|
+
'live-photo.vitality-scoring-version' => { Name => 'LivePhotoVitalityScoringVersion', Writable => 'int64s' },
|
6350
|
+
'apple.photos.variation-identifier' => { Name => 'ApplePhotosVariationIdentifier', Writable => 'int64s' },
|
6274
6351
|
'direction.facing' => { Name => 'CameraDirection', Groups => { 2 => 'Location' } },
|
6275
6352
|
'direction.motion' => { Name => 'CameraMotion', Groups => { 2 => 'Location' } },
|
6276
6353
|
'location.body' => { Name => 'LocationBody', Groups => { 2 => 'Location' } },
|
@@ -6306,11 +6383,15 @@ my %eeBox2 = (
|
|
6306
6383
|
# com.divergentmedia.clipwrap.manufacturer ('Sony')
|
6307
6384
|
# com.divergentmedia.clipwrap.originalDateTime ('2013/2/6 10:30:40+0200')
|
6308
6385
|
#
|
6309
|
-
# seen in timed metadata (mebx), and added dynamically to the table
|
6310
|
-
#
|
6386
|
+
# seen in timed metadata (mebx), and added dynamically to the table via SaveMetaKeys()
|
6387
|
+
# NOTE: these tags are not writable! (timed metadata cannot yet be written)
|
6311
6388
|
#
|
6312
6389
|
# (mdta)com.apple.quicktime.video-orientation (dtyp=66, int16s)
|
6313
|
-
'video-orientation' => {
|
6390
|
+
'video-orientation' => {
|
6391
|
+
Name => 'VideoOrientation',
|
6392
|
+
Writable => 0,
|
6393
|
+
PrintConv => \%Image::ExifTool::Exif::orientation, #PH (NC)
|
6394
|
+
},
|
6314
6395
|
# (mdta)com.apple.quicktime.live-photo-info (dtyp=com.apple.quicktime.com.apple.quicktime.live-photo-info)
|
6315
6396
|
'live-photo-info' => {
|
6316
6397
|
Name => 'LivePhotoInfo',
|
@@ -6370,10 +6451,11 @@ my %eeBox2 = (
|
|
6370
6451
|
# iTunes info ('----') atoms
|
6371
6452
|
%Image::ExifTool::QuickTime::iTunesInfo = (
|
6372
6453
|
PROCESS_PROC => \&ProcessMOV,
|
6373
|
-
GROUPS => { 2 => 'Audio' },
|
6454
|
+
GROUPS => { 1 => 'iTunes', 2 => 'Audio' },
|
6374
6455
|
NOTES => q{
|
6375
6456
|
ExifTool will extract any iTunesInfo tags that exist, even if they are not
|
6376
|
-
defined in this table.
|
6457
|
+
defined in this table. These tags belong to the family 1 "iTunes" group,
|
6458
|
+
and are not currently writable.
|
6377
6459
|
},
|
6378
6460
|
# 'mean'/'name'/'data' atoms form a triplet, but unfortunately
|
6379
6461
|
# I haven't been able to find any documentation on this.
|
@@ -6434,9 +6516,45 @@ my %eeBox2 = (
|
|
6434
6516
|
SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::EncodingParams' },
|
6435
6517
|
},
|
6436
6518
|
# also heard about 'iTunPGAP', but I haven't seen a sample
|
6437
|
-
|
6438
|
-
|
6439
|
-
|
6519
|
+
# all tags below were added based on samples I have seen - PH
|
6520
|
+
DISCNUMBER => 'DiscNumber',
|
6521
|
+
TRACKNUMBER => 'TrackNumber',
|
6522
|
+
ARTISTS => 'Artists',
|
6523
|
+
CATALOGNUMBER => 'CatalogNumber',
|
6524
|
+
RATING => 'Rating',
|
6525
|
+
MEDIA => 'Media',
|
6526
|
+
SCRIPT => 'Script', # character set? (seen 'Latn')
|
6527
|
+
BARCODE => 'Barcode',
|
6528
|
+
LABEL => 'Label',
|
6529
|
+
MOOD => 'Mood',
|
6530
|
+
popularimeter => 'Popularimeter',
|
6531
|
+
'Dynamic Range (DR)'=> 'DynamicRange',
|
6532
|
+
initialkey => 'InitialKey',
|
6533
|
+
originalyear => 'OriginalYear',
|
6534
|
+
originaldate => 'OriginalDate',
|
6535
|
+
'~length' => 'Length', # play length? (ie. duration?)
|
6536
|
+
replaygain_track_gain=>'ReplayTrackGain',
|
6537
|
+
replaygain_track_peak=>'ReplayTrackPeak',
|
6538
|
+
'Volume Level (ReplayGain)'=> 'ReplayVolumeLevel',
|
6539
|
+
'Dynamic Range (R128)'=> 'DynamicRangeR128',
|
6540
|
+
'Volume Level (R128)' => 'VolumeLevelR128',
|
6541
|
+
'Peak Level (Sample)' => 'PeakLevelSample',
|
6542
|
+
'Peak Level (R128)' => 'PeakLevelR128',
|
6543
|
+
# also seen (many from forum12777):
|
6544
|
+
# 'MusicBrainz Album Release Country'
|
6545
|
+
# 'MusicBrainz Album Type'
|
6546
|
+
# 'MusicBrainz Album Status'
|
6547
|
+
# 'MusicBrainz Track Id'
|
6548
|
+
# 'MusicBrainz Release Track Id'
|
6549
|
+
# 'MusicBrainz Album Id'
|
6550
|
+
# 'MusicBrainz Album Artist Id'
|
6551
|
+
# 'MusicBrainz Artist Id'
|
6552
|
+
# 'Acoustid Id' (sic)
|
6553
|
+
# 'Tool Version'
|
6554
|
+
# 'Tool Name'
|
6555
|
+
# 'ISRC'
|
6556
|
+
# 'HDCD'
|
6557
|
+
# 'Waveform'
|
6440
6558
|
);
|
6441
6559
|
|
6442
6560
|
# iTunes audio encoding parameters
|
@@ -7595,7 +7713,11 @@ my %eeBox2 = (
|
|
7595
7713
|
8 => {
|
7596
7714
|
Name => 'HandlerType',
|
7597
7715
|
Format => 'undef[4]',
|
7598
|
-
RawConv =>
|
7716
|
+
RawConv => q{
|
7717
|
+
$$self{HandlerType} = $val unless $val eq 'alis' or $val eq 'url ';
|
7718
|
+
$$self{HasHandler}{$val} = 1; # remember all our handlers
|
7719
|
+
return $val;
|
7720
|
+
},
|
7599
7721
|
PrintConvColumns => 2,
|
7600
7722
|
PrintConv => {
|
7601
7723
|
alis => 'Alias Data', #PH
|
@@ -7700,7 +7822,7 @@ my %eeBox2 = (
|
|
7700
7822
|
$val =~ s/\0+$//; # remove trailing nulls
|
7701
7823
|
if (length $val and $$self{OPTIONS}{ExtractEmbedded}) {
|
7702
7824
|
my $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream');
|
7703
|
-
Image::ExifTool::QuickTime::
|
7825
|
+
Image::ExifTool::QuickTime::ProcessGPSLog($self, { DataPt => \$val }, $tagTbl);
|
7704
7826
|
}
|
7705
7827
|
return $val;
|
7706
7828
|
},
|
@@ -8580,7 +8702,7 @@ sub QuickTimeFormat($$)
|
|
8580
8702
|
my ($flags, $len) = @_;
|
8581
8703
|
my $format;
|
8582
8704
|
if ($flags == 0x15 or $flags == 0x16) {
|
8583
|
-
$format = { 1=>'int8', 2=>'int16', 4=>'int32' }->{$len};
|
8705
|
+
$format = { 1=>'int8', 2=>'int16', 4=>'int32', 8=>'int64' }->{$len};
|
8584
8706
|
$format .= $flags == 0x15 ? 's' : 'u' if $format;
|
8585
8707
|
} elsif ($flags == 0x17) {
|
8586
8708
|
$format = 'float';
|
@@ -8801,20 +8923,28 @@ sub ProcessKeys($$$)
|
|
8801
8923
|
my $ns = substr($$dataPt, $pos + 4, 4);
|
8802
8924
|
my $tag = substr($$dataPt, $pos + 8, $len - 8);
|
8803
8925
|
$tag =~ s/\0.*//s; # truncate at null
|
8926
|
+
my $full = $tag;
|
8804
8927
|
$tag =~ s/^com\.(apple\.quicktime\.)?// if $ns eq 'mdta'; # remove apple quicktime domain
|
8805
8928
|
$tag = "Tag_$ns" unless $tag;
|
8806
|
-
|
8807
|
-
my $tagInfo
|
8808
|
-
|
8809
|
-
$tagInfo = $et->GetTagInfo($
|
8810
|
-
|
8929
|
+
my $short = $tag;
|
8930
|
+
my $tagInfo;
|
8931
|
+
for (;;) {
|
8932
|
+
$tagInfo = $et->GetTagInfo($tagTablePtr, $tag) and last;
|
8933
|
+
# also try ItemList and UserData tables
|
8934
|
+
$tagInfo = $et->GetTagInfo($itemList, $tag) and last;
|
8935
|
+
$tagInfo = $et->GetTagInfo($userData, $tag) and last;
|
8936
|
+
# (I have some samples where the tag is a reversed ItemList or UserData tag ID)
|
8937
|
+
if ($tag =~ /^\w{3}\xa9$/) {
|
8938
|
+
$tag = pack('N', unpack('V', $tag));
|
8939
|
+
$tagInfo = $et->GetTagInfo($itemList, $tag) and last;
|
8811
8940
|
$tagInfo = $et->GetTagInfo($userData, $tag);
|
8812
|
-
|
8813
|
-
|
8814
|
-
|
8815
|
-
|
8816
|
-
|
8941
|
+
last;
|
8942
|
+
}
|
8943
|
+
if ($tag eq $full) {
|
8944
|
+
$tag = $short;
|
8945
|
+
last;
|
8817
8946
|
}
|
8947
|
+
$tag = $full;
|
8818
8948
|
}
|
8819
8949
|
my ($newInfo, $msg);
|
8820
8950
|
if ($tagInfo) {
|
@@ -8855,6 +8985,7 @@ sub ProcessKeys($$$)
|
|
8855
8985
|
delete $$itemList{$id};
|
8856
8986
|
}
|
8857
8987
|
if ($newInfo) {
|
8988
|
+
$$newInfo{KeysID} = $tag; # save original ID for use in family 7 group name
|
8858
8989
|
AddTagToTable($itemList, $id, $newInfo);
|
8859
8990
|
$msg or $msg = '';
|
8860
8991
|
$out and print $out "$$et{INDENT}Added ItemList Tag $id = ($ns) $tag$msg\n";
|
@@ -8933,6 +9064,7 @@ sub ProcessMOV($$;$)
|
|
8933
9064
|
if ($raf->Read($buff, $size-8) == $size-8) {
|
8934
9065
|
$raf->Seek(-($size-8), 1);
|
8935
9066
|
my $type = substr($buff, 0, 4);
|
9067
|
+
$$et{save_ftyp} = $type;
|
8936
9068
|
# see if we know the extension for this file type
|
8937
9069
|
if ($ftypLookup{$type} and $ftypLookup{$type} =~ /\(\.(\w+)/) {
|
8938
9070
|
$fileType = $1;
|
@@ -8981,6 +9113,12 @@ sub ProcessMOV($$;$)
|
|
8981
9113
|
} else {
|
8982
9114
|
my $t = PrintableTagID($tag,2);
|
8983
9115
|
$et->VPrint(0,"$$et{INDENT}Tag '${t}' extends to end of file");
|
9116
|
+
if ($$tagTablePtr{"$tag-size"}) {
|
9117
|
+
my $pos = $raf->Tell();
|
9118
|
+
$raf->Seek(0, 2);
|
9119
|
+
$et->HandleTag($tagTablePtr, "$tag-size", $raf->Tell() - $pos);
|
9120
|
+
$et->HandleTag($tagTablePtr, "$tag-offset", $pos) if $$tagTablePtr{"$tag-offset"};
|
9121
|
+
}
|
8984
9122
|
}
|
8985
9123
|
last;
|
8986
9124
|
}
|
@@ -9207,6 +9345,7 @@ ItemID: foreach $id (keys %$items) {
|
|
9207
9345
|
Name => $name,
|
9208
9346
|
Description => $desc,
|
9209
9347
|
};
|
9348
|
+
$et->VPrint(0, $$et{INDENT}, "[adding QuickTime:$name]\n");
|
9210
9349
|
AddTagToTable($tagTablePtr, $tag, $tagInfo);
|
9211
9350
|
}
|
9212
9351
|
# ignore 8-byte header
|
@@ -9218,9 +9357,9 @@ ItemID: foreach $id (keys %$items) {
|
|
9218
9357
|
$val = \$buff;
|
9219
9358
|
}
|
9220
9359
|
}
|
9221
|
-
|
9360
|
+
$$tagInfo{List} = 1; # (allow any of these tags to have multiple data elements)
|
9361
|
+
$et->VerboseInfo($tag, $tagInfo, Value => $val) if $verbose;
|
9222
9362
|
} else {
|
9223
|
-
undef %triplet if $tag eq 'mean';
|
9224
9363
|
$triplet{$tag} = substr($val,4) if length($val) > 4;
|
9225
9364
|
undef $tagInfo; # don't store this tag
|
9226
9365
|
}
|
@@ -9304,7 +9443,13 @@ ItemID: foreach $id (keys %$items) {
|
|
9304
9443
|
# (shouldn't be null terminated, but some software writes it anyway)
|
9305
9444
|
$value =~ s/\0$// unless $$tagInfo{Binary};
|
9306
9445
|
} else {
|
9307
|
-
|
9446
|
+
if (not $format) {
|
9447
|
+
$format = QuickTimeFormat($flags, $len);
|
9448
|
+
} elsif ($format =~ /^int\d+([us])$/) {
|
9449
|
+
# adjust integer to available length (but not int64)
|
9450
|
+
my $fmt = { 1=>'int8', 2=>'int16', 4=>'int32' }->{$len};
|
9451
|
+
$format = $fmt . $1 if defined $fmt;
|
9452
|
+
}
|
9308
9453
|
if ($format) {
|
9309
9454
|
$value = ReadValue(\$value, 0, $format, $$tagInfo{Count}, $len);
|
9310
9455
|
} elsif (not $$tagInfo{ValueConv}) {
|
@@ -9356,9 +9501,9 @@ ItemID: foreach $id (keys %$items) {
|
|
9356
9501
|
}
|
9357
9502
|
for (;;) {
|
9358
9503
|
my ($len, $lang);
|
9359
|
-
if ($$tagInfo{IText} and $$tagInfo{IText}
|
9360
|
-
last if $pos +
|
9361
|
-
$pos +=
|
9504
|
+
if ($$tagInfo{IText} and $$tagInfo{IText} >= 6) {
|
9505
|
+
last if $pos + $$tagInfo{IText} > $size;
|
9506
|
+
$pos += $$tagInfo{IText} - 2;
|
9362
9507
|
$lang = unpack("x${pos}n", $val);
|
9363
9508
|
$pos += 2;
|
9364
9509
|
$len = $size - $pos;
|
@@ -9378,7 +9523,7 @@ ItemID: foreach $id (keys %$items) {
|
|
9378
9523
|
# ignore any empty entries (or null padding) after the first
|
9379
9524
|
next if not $len and $pos;
|
9380
9525
|
my $str = substr($val, $pos, $len);
|
9381
|
-
my $langInfo;
|
9526
|
+
my ($langInfo, $enc);
|
9382
9527
|
if (($lang < 0x400 or $lang == 0x7fff) and $str !~ /^\xfe\xff/) {
|
9383
9528
|
# this is a Macintosh language code
|
9384
9529
|
# a language code of 0 is Macintosh english, so treat as default
|
@@ -9395,15 +9540,22 @@ ItemID: foreach $id (keys %$items) {
|
|
9395
9540
|
}
|
9396
9541
|
# the spec says only "Macintosh text encoding", but
|
9397
9542
|
# allow this to be configured by the user
|
9398
|
-
$
|
9543
|
+
$enc = $charsetQuickTime;
|
9399
9544
|
} else {
|
9400
9545
|
# convert language code to ASCII (ignore read-only bit)
|
9401
9546
|
$lang = UnpackLang($lang);
|
9402
9547
|
# may be either UTF-8 or UTF-16BE
|
9403
|
-
|
9548
|
+
$enc = $str=~s/^\xfe\xff// ? 'UTF16' : 'UTF8';
|
9549
|
+
}
|
9550
|
+
unless ($$tagInfo{NoDecode}) {
|
9404
9551
|
$str = $et->Decode($str, $enc);
|
9552
|
+
$str =~ s/\0+$//; # remove any trailing nulls (eg. 3gp tags)
|
9553
|
+
}
|
9554
|
+
if ($$tagInfo{IText} and $$tagInfo{IText} > 6) {
|
9555
|
+
my $n = $$tagInfo{IText} - 6;
|
9556
|
+
# add back extra bytes (eg. 'rtng' box)
|
9557
|
+
$str = substr($val, $pos-$n-2, $n) . $str;
|
9405
9558
|
}
|
9406
|
-
$str =~ s/\0+$//; # remove any trailing nulls (eg. 3gp tags)
|
9407
9559
|
$langInfo = GetLangInfoQT($et, $tagInfo, $lang) if $lang;
|
9408
9560
|
$et->FoundTag($langInfo || $tagInfo, $str);
|
9409
9561
|
$pos += $len;
|
@@ -9453,6 +9605,13 @@ ItemID: foreach $id (keys %$items) {
|
|
9453
9605
|
($size, $tag) = unpack('Na4', $buff);
|
9454
9606
|
++$index if defined $index;
|
9455
9607
|
}
|
9608
|
+
# tweak file type based on track content ("iso*" and "dash" ftyp only)
|
9609
|
+
if ($topLevel and $$et{VALUE}{FileType} and $$et{VALUE}{FileType} eq 'MP4' and
|
9610
|
+
$$et{save_ftyp} and $$et{HasHandler} and $$et{save_ftyp} =~ /^(iso|dash)/ and
|
9611
|
+
$$et{HasHandler}{soun} and not $$et{HasHandler}{vide})
|
9612
|
+
{
|
9613
|
+
$et->OverrideFileType('M4A', 'audio/mp4');
|
9614
|
+
}
|
9456
9615
|
# fill in missing defaults for alternate language tags
|
9457
9616
|
# (the first language is taken as the default)
|
9458
9617
|
if ($doDefaultLang and $$et{QTLang}) {
|