exiftool_vendored 12.17.1 → 12.32.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 +225 -1
- 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 +142 -87
- 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 +30 -12
- data/bin/lib/Image/ExifTool/CBOR.pm +277 -0
- data/bin/lib/Image/ExifTool/Canon.pm +49 -18
- 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 +28 -11
- 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 +27 -4
- data/bin/lib/Image/ExifTool/Jpeg2000.pm +393 -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 +1 -1
- data/bin/lib/Image/ExifTool/Microsoft.pm +298 -82
- data/bin/lib/Image/ExifTool/Nikon.pm +19 -8
- data/bin/lib/Image/ExifTool/NikonSettings.pm +28 -11
- data/bin/lib/Image/ExifTool/Olympus.pm +6 -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 +247 -88
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +283 -141
- data/bin/lib/Image/ExifTool/README +3 -0
- 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 +237 -78
- data/bin/lib/Image/ExifTool/TagInfoXML.pm +1 -0
- data/bin/lib/Image/ExifTool/TagLookup.pm +4125 -4028
- data/bin/lib/Image/ExifTool/TagNames.pod +644 -286
- 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 +39 -14
- data/bin/lib/Image/ExifTool/XMP2.pl +2 -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 +223 -72
- 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.69';
|
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!)
|
@@ -258,11 +271,15 @@ my %unknownInfo = (
|
|
258
271
|
Unknown => 1,
|
259
272
|
ValueConv => '$val =~ /^([\x20-\x7e]*)\0*$/ ? $1 : \$val',
|
260
273
|
);
|
274
|
+
|
275
|
+
# multi-language text with 6-byte header
|
276
|
+
my %langText = ( IText => 6 );
|
277
|
+
|
261
278
|
# parsing for most of the 3gp udta language text boxes
|
262
|
-
my %
|
279
|
+
my %langText3gp = (
|
263
280
|
Notes => 'used in 3gp videos',
|
264
|
-
IText => 6,
|
265
281
|
Avoid => 1,
|
282
|
+
IText => 6,
|
266
283
|
);
|
267
284
|
|
268
285
|
# 4-character Vendor ID codes (ref PH)
|
@@ -670,6 +687,15 @@ my %eeBox2 = (
|
|
670
687
|
udat => { #PH (GPS NMEA-format log written by Datakam Player software)
|
671
688
|
Name => 'GPSLog',
|
672
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
|
+
},
|
673
699
|
},
|
674
700
|
# meta - proprietary XML information written by some Flip cameras - PH
|
675
701
|
# beam - 16 bytes found in an iPhone video
|
@@ -708,6 +734,11 @@ my %eeBox2 = (
|
|
708
734
|
Unknown => 1,
|
709
735
|
Binary => 1,
|
710
736
|
},
|
737
|
+
sefd => {
|
738
|
+
Name => 'SamsungTrailer',
|
739
|
+
SubDirectory => { TagTable => 'Image::ExifTool::Samsung::Trailer' },
|
740
|
+
},
|
741
|
+
# 'samn'? - seen in Vantrue N2S sample video
|
711
742
|
);
|
712
743
|
|
713
744
|
# MPEG-4 'ftyp' atom
|
@@ -1169,6 +1200,15 @@ my %eeBox2 = (
|
|
1169
1200
|
Name => 'CreateDate',
|
1170
1201
|
Groups => { 2 => 'Time' },
|
1171
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
|
+
},
|
1172
1212
|
# this is int64u if MovieHeaderVersion == 1 (ref 13)
|
1173
1213
|
Hook => '$$self{MovieHeaderVersion} and $format = "int64u", $varSize += 4',
|
1174
1214
|
},
|
@@ -1545,47 +1585,43 @@ my %eeBox2 = (
|
|
1545
1585
|
# the following are 3gp tags, references:
|
1546
1586
|
# http://atomicparsley.sourceforge.net
|
1547
1587
|
# http://www.3gpp.org/ftp/tsg_sa/WG4_CODEC/TSGS4_25/Docs/
|
1548
|
-
# (note that all %
|
1549
|
-
cprt => { Name => 'Copyright', %
|
1550
|
-
auth => { Name => 'Author', %
|
1551
|
-
titl => { Name => 'Title', %
|
1552
|
-
dscp => { Name => 'Description',%
|
1553
|
-
perf => { Name => 'Performer', %
|
1554
|
-
gnre => { Name => 'Genre', %
|
1555
|
-
albm => { Name => 'Album', %
|
1556
|
-
coll => { Name => 'CollectionName', %
|
1588
|
+
# (note that all %langText3gp tags are Avoid => 1)
|
1589
|
+
cprt => { Name => 'Copyright', %langText3gp, Groups => { 2 => 'Author' } },
|
1590
|
+
auth => { Name => 'Author', %langText3gp, Groups => { 2 => 'Author' } },
|
1591
|
+
titl => { Name => 'Title', %langText3gp },
|
1592
|
+
dscp => { Name => 'Description',%langText3gp },
|
1593
|
+
perf => { Name => 'Performer', %langText3gp },
|
1594
|
+
gnre => { Name => 'Genre', %langText3gp },
|
1595
|
+
albm => { Name => 'Album', %langText3gp },
|
1596
|
+
coll => { Name => 'CollectionName', %langText3gp }, #17
|
1557
1597
|
rtng => {
|
1558
1598
|
Name => 'Rating',
|
1599
|
+
Writable => 'undef',
|
1600
|
+
Avoid => 1,
|
1559
1601
|
# (4-byte flags, 4-char entity, 4-char criteria, 2-byte lang, string)
|
1560
|
-
|
1561
|
-
|
1562
|
-
|
1563
|
-
|
1564
|
-
my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 12));
|
1565
|
-
$lang = $lang ? "($lang) " : '';
|
1566
|
-
$val = substr($val, 14);
|
1567
|
-
$val = $self->Decode($val, 'UCS2') if $val =~ /^\xfe\xff/;
|
1568
|
-
return $lang . $str . ' ' . $val;
|
1569
|
-
},
|
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',
|
1570
1606
|
},
|
1571
1607
|
clsf => {
|
1572
1608
|
Name => 'Classification',
|
1609
|
+
Writable => 'undef',
|
1610
|
+
Avoid => 1,
|
1573
1611
|
# (4-byte flags, 4-char entity, 2-byte index, 2-byte lang, string)
|
1574
|
-
|
1575
|
-
|
1576
|
-
|
1577
|
-
|
1578
|
-
my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 10));
|
1579
|
-
$lang = $lang ? "($lang) " : '';
|
1580
|
-
$val = substr($val, 12);
|
1581
|
-
$val = $self->Decode($val, 'UCS2') if $val =~ /^\xfe\xff/;
|
1582
|
-
return $lang . $str . ' ' . $val;
|
1583
|
-
},
|
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',
|
1584
1616
|
},
|
1585
1617
|
kywd => {
|
1586
1618
|
Name => 'Keywords',
|
1587
|
-
# (4 byte flags, 2-byte lang, 1-byte count, count x pascal strings)
|
1619
|
+
# (4 byte flags, 2-byte lang, 1-byte count, count x pascal strings, ref 17)
|
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",
|
1588
1622
|
RawConv => q{
|
1623
|
+
my $sep = $self->Options('ListSep');
|
1624
|
+
return join($sep, split /\0+/, $val) unless $val =~ /^\0/; # (iPhone)
|
1589
1625
|
return '<err>' unless length $val >= 7;
|
1590
1626
|
my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 4));
|
1591
1627
|
$lang = $lang ? "($lang) " : '';
|
@@ -1601,27 +1637,30 @@ my %eeBox2 = (
|
|
1601
1637
|
push @vals, $v;
|
1602
1638
|
$pos += $len;
|
1603
1639
|
}
|
1604
|
-
my $sep = $self->Options('ListSep');
|
1605
1640
|
return $lang . join($sep, @vals);
|
1606
1641
|
},
|
1607
1642
|
},
|
1608
1643
|
loci => {
|
1609
1644
|
Name => 'LocationInformation',
|
1610
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
|
+
},
|
1611
1654
|
# (4-byte flags, 2-byte lang, location string, 1-byte role, 4-byte fixed longitude,
|
1612
1655
|
# 4-byte fixed latitude, 4-byte fixed altitude, body string, notes string)
|
1613
1656
|
RawConv => q{
|
1614
|
-
return '<err>' unless length $val >= 6;
|
1615
|
-
my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 4));
|
1616
|
-
$lang = $lang ? "($lang) " : '';
|
1617
|
-
$val = substr($val, 6);
|
1618
1657
|
my $str;
|
1619
1658
|
if ($val =~ /^\xfe\xff/) {
|
1620
1659
|
$val =~ s/^(\xfe\xff(.{2})*?)\0\0//s or return '<err>';
|
1621
1660
|
$str = $self->Decode($1, 'UCS2');
|
1622
1661
|
} else {
|
1623
1662
|
$val =~ s/^(.*?)\0//s or return '<err>';
|
1624
|
-
$str = $1;
|
1663
|
+
$str = $self->Decode($1, 'UTF8');
|
1625
1664
|
}
|
1626
1665
|
$str = '(none)' unless length $str;
|
1627
1666
|
return '<err>' if length $val < 13;
|
@@ -1636,27 +1675,52 @@ my %eeBox2 = (
|
|
1636
1675
|
if ($val =~ s/^(\xfe\xff(.{2})*?)\0\0//s) {
|
1637
1676
|
$str .= ' Body=' . $self->Decode($1, 'UCS2');
|
1638
1677
|
} elsif ($val =~ s/^(.*?)\0//s) {
|
1639
|
-
$str .=
|
1678
|
+
$str .= ' Body=' . $self->Decode($1, 'UTF8');
|
1640
1679
|
}
|
1641
1680
|
if ($val =~ s/^(\xfe\xff(.{2})*?)\0\0//s) {
|
1642
1681
|
$str .= ' Notes=' . $self->Decode($1, 'UCS2');
|
1643
1682
|
} elsif ($val =~ s/^(.*?)\0//s) {
|
1644
|
-
$str .=
|
1683
|
+
$str .= ' Notes=' . $self->Decode($1, 'UTF8');
|
1645
1684
|
}
|
1646
|
-
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";
|
1647
1703
|
},
|
1648
1704
|
},
|
1649
1705
|
yrrc => {
|
1650
1706
|
Name => 'Year',
|
1707
|
+
Writable => 'undef',
|
1651
1708
|
Groups => { 2 => 'Time' },
|
1652
|
-
|
1709
|
+
Avoid => 1,
|
1710
|
+
Notes => 'used in 3gp videos',
|
1711
|
+
ValueConv => 'length($val) >= 6 ? unpack("x4n",$val) : "<err>"',
|
1712
|
+
ValueConvInv => 'pack("Nn",0,$val)',
|
1653
1713
|
},
|
1654
1714
|
urat => { #17
|
1655
1715
|
Name => 'UserRating',
|
1656
|
-
|
1716
|
+
Writable => 'undef',
|
1717
|
+
Notes => 'used in 3gp videos',
|
1718
|
+
Avoid => 1,
|
1719
|
+
ValueConv => q{
|
1657
1720
|
return '<err>' unless length $val >= 8;
|
1658
|
-
|
1721
|
+
unpack('x7C', $val);
|
1659
1722
|
},
|
1723
|
+
ValueConvInv => 'pack("N2",0,$val)',
|
1660
1724
|
},
|
1661
1725
|
# tsel - TrackSelection (ref 17)
|
1662
1726
|
# Apple tags (ref 16[dead] -- see ref 25 instead)
|
@@ -1988,7 +2052,11 @@ my %eeBox2 = (
|
|
1988
2052
|
# ---- Microsoft ----
|
1989
2053
|
Xtra => { #PH (microsoft)
|
1990
2054
|
Name => 'MicrosoftXtra',
|
1991
|
-
|
2055
|
+
WriteGroup => 'Microsoft',
|
2056
|
+
SubDirectory => {
|
2057
|
+
DirName => 'Microsoft',
|
2058
|
+
TagTable => 'Image::ExifTool::Microsoft::Xtra',
|
2059
|
+
},
|
1992
2060
|
},
|
1993
2061
|
# ---- Minolta ----
|
1994
2062
|
MMA0 => { #PH (DiMage 7Hi)
|
@@ -2037,7 +2105,7 @@ my %eeBox2 = (
|
|
2037
2105
|
SubDirectory => { TagTable => 'Image::ExifTool::Olympus::thmb' },
|
2038
2106
|
},{ #17 (format is in bytes 3-7)
|
2039
2107
|
Name => 'ThumbnailImage',
|
2040
|
-
Condition => '$$valPt =~ /^.{8}\xff\xd8\xff\xdb/s',
|
2108
|
+
Condition => '$$valPt =~ /^.{8}\xff\xd8\xff[\xdb\xe0]/s',
|
2041
2109
|
Groups => { 2 => 'Preview' },
|
2042
2110
|
RawConv => 'substr($val, 8)',
|
2043
2111
|
Binary => 1,
|
@@ -2201,6 +2269,12 @@ my %eeBox2 = (
|
|
2201
2269
|
# opax - 164 bytes unknown (center and affine arrays? ref 26)
|
2202
2270
|
# opai - 32 bytes (maybe contains a serial number starting at byte 16? - PH) (rgb gains, degamma, gamma? ref 26)
|
2203
2271
|
# intv - 16 bytes all zero
|
2272
|
+
# ---- Xaiomi ----
|
2273
|
+
mcvr => {
|
2274
|
+
Name => 'PreviewImage',
|
2275
|
+
Groups => { 2 => 'Preview' },
|
2276
|
+
Binary => 1,
|
2277
|
+
},
|
2204
2278
|
# ---- Unknown ----
|
2205
2279
|
# CDET - 128 bytes (unknown origin)
|
2206
2280
|
# mtyp - 4 bytes all zero (some drone video)
|
@@ -2638,6 +2712,7 @@ my %eeBox2 = (
|
|
2638
2712
|
colr => [{
|
2639
2713
|
Name => 'ICC_Profile',
|
2640
2714
|
Condition => '$$valPt =~ /^(prof|rICC)/',
|
2715
|
+
Permanent => 0, # (in QuickTime, this writes a zero-length box instead of deleting)
|
2641
2716
|
SubDirectory => {
|
2642
2717
|
TagTable => 'Image::ExifTool::ICC_Profile::Main',
|
2643
2718
|
Start => 4,
|
@@ -2994,9 +3069,9 @@ my %eeBox2 = (
|
|
2994
3069
|
3-character ISO 639-2 language code and an optional ISO 3166-1 alpha 2
|
2995
3070
|
country code to the tag name (eg. "ItemList:Title-fra" or
|
2996
3071
|
"ItemList::Title-fra-FR"). When creating a new Meta box to contain the
|
2997
|
-
ItemList directory, by default ExifTool
|
2998
|
-
|
2999
|
-
|
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.
|
3000
3075
|
},
|
3001
3076
|
# in this table, binary 1 and 2-byte "data"-type tags are interpreted as
|
3002
3077
|
# int8u and int16u. Multi-byte binary "data" tags are extracted as binary data.
|
@@ -6157,13 +6232,12 @@ my %eeBox2 = (
|
|
6157
6232
|
PROCESS_PROC => \&ProcessKeys,
|
6158
6233
|
WRITE_PROC => \&WriteKeys,
|
6159
6234
|
CHECK_PROC => \&CheckQTValue,
|
6160
|
-
VARS => { LONG_TAGS =>
|
6235
|
+
VARS => { LONG_TAGS => 7 },
|
6161
6236
|
WRITABLE => 1,
|
6162
6237
|
# (not PREFERRED when writing)
|
6163
6238
|
GROUPS => { 1 => 'Keys' },
|
6164
6239
|
WRITE_GROUP => 'Keys',
|
6165
6240
|
LANG_INFO => \&GetLangInfo,
|
6166
|
-
FORMAT => 'string',
|
6167
6241
|
NOTES => q{
|
6168
6242
|
This directory contains a list of key names which are used to decode tags
|
6169
6243
|
written by the "mdta" handler. Also in this table are a few tags found in
|
@@ -6229,6 +6303,10 @@ my %eeBox2 = (
|
|
6229
6303
|
'location.ISO6709' => {
|
6230
6304
|
Name => 'GPSCoordinates',
|
6231
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
|
+
},
|
6232
6310
|
ValueConv => \&ConvertISO6709,
|
6233
6311
|
ValueConvInv => \&ConvInvISO6709,
|
6234
6312
|
PrintConv => \&PrintGPSCoordinates,
|
@@ -6265,6 +6343,11 @@ my %eeBox2 = (
|
|
6265
6343
|
PrintConv => '$self->ConvertDateTime($val)',
|
6266
6344
|
PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist)
|
6267
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' },
|
6268
6351
|
'direction.facing' => { Name => 'CameraDirection', Groups => { 2 => 'Location' } },
|
6269
6352
|
'direction.motion' => { Name => 'CameraMotion', Groups => { 2 => 'Location' } },
|
6270
6353
|
'location.body' => { Name => 'LocationBody', Groups => { 2 => 'Location' } },
|
@@ -6300,11 +6383,15 @@ my %eeBox2 = (
|
|
6300
6383
|
# com.divergentmedia.clipwrap.manufacturer ('Sony')
|
6301
6384
|
# com.divergentmedia.clipwrap.originalDateTime ('2013/2/6 10:30:40+0200')
|
6302
6385
|
#
|
6303
|
-
# seen in timed metadata (mebx), and added dynamically to the table
|
6304
|
-
#
|
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)
|
6305
6388
|
#
|
6306
6389
|
# (mdta)com.apple.quicktime.video-orientation (dtyp=66, int16s)
|
6307
|
-
'video-orientation' => {
|
6390
|
+
'video-orientation' => {
|
6391
|
+
Name => 'VideoOrientation',
|
6392
|
+
Writable => 0,
|
6393
|
+
PrintConv => \%Image::ExifTool::Exif::orientation, #PH (NC)
|
6394
|
+
},
|
6308
6395
|
# (mdta)com.apple.quicktime.live-photo-info (dtyp=com.apple.quicktime.com.apple.quicktime.live-photo-info)
|
6309
6396
|
'live-photo-info' => {
|
6310
6397
|
Name => 'LivePhotoInfo',
|
@@ -6364,10 +6451,11 @@ my %eeBox2 = (
|
|
6364
6451
|
# iTunes info ('----') atoms
|
6365
6452
|
%Image::ExifTool::QuickTime::iTunesInfo = (
|
6366
6453
|
PROCESS_PROC => \&ProcessMOV,
|
6367
|
-
GROUPS => { 2 => 'Audio' },
|
6454
|
+
GROUPS => { 1 => 'iTunes', 2 => 'Audio' },
|
6368
6455
|
NOTES => q{
|
6369
6456
|
ExifTool will extract any iTunesInfo tags that exist, even if they are not
|
6370
|
-
defined in this table.
|
6457
|
+
defined in this table. These tags belong to the family 1 "iTunes" group,
|
6458
|
+
and are not currently writable.
|
6371
6459
|
},
|
6372
6460
|
# 'mean'/'name'/'data' atoms form a triplet, but unfortunately
|
6373
6461
|
# I haven't been able to find any documentation on this.
|
@@ -6428,9 +6516,45 @@ my %eeBox2 = (
|
|
6428
6516
|
SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::EncodingParams' },
|
6429
6517
|
},
|
6430
6518
|
# also heard about 'iTunPGAP', but I haven't seen a sample
|
6431
|
-
|
6432
|
-
|
6433
|
-
|
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'
|
6434
6558
|
);
|
6435
6559
|
|
6436
6560
|
# iTunes audio encoding parameters
|
@@ -7589,7 +7713,11 @@ my %eeBox2 = (
|
|
7589
7713
|
8 => {
|
7590
7714
|
Name => 'HandlerType',
|
7591
7715
|
Format => 'undef[4]',
|
7592
|
-
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
|
+
},
|
7593
7721
|
PrintConvColumns => 2,
|
7594
7722
|
PrintConv => {
|
7595
7723
|
alis => 'Alias Data', #PH
|
@@ -7694,7 +7822,7 @@ my %eeBox2 = (
|
|
7694
7822
|
$val =~ s/\0+$//; # remove trailing nulls
|
7695
7823
|
if (length $val and $$self{OPTIONS}{ExtractEmbedded}) {
|
7696
7824
|
my $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream');
|
7697
|
-
Image::ExifTool::QuickTime::
|
7825
|
+
Image::ExifTool::QuickTime::ProcessGPSLog($self, { DataPt => \$val }, $tagTbl);
|
7698
7826
|
}
|
7699
7827
|
return $val;
|
7700
7828
|
},
|
@@ -8574,7 +8702,7 @@ sub QuickTimeFormat($$)
|
|
8574
8702
|
my ($flags, $len) = @_;
|
8575
8703
|
my $format;
|
8576
8704
|
if ($flags == 0x15 or $flags == 0x16) {
|
8577
|
-
$format = { 1=>'int8', 2=>'int16', 4=>'int32' }->{$len};
|
8705
|
+
$format = { 1=>'int8', 2=>'int16', 4=>'int32', 8=>'int64' }->{$len};
|
8578
8706
|
$format .= $flags == 0x15 ? 's' : 'u' if $format;
|
8579
8707
|
} elsif ($flags == 0x17) {
|
8580
8708
|
$format = 'float';
|
@@ -8795,20 +8923,28 @@ sub ProcessKeys($$$)
|
|
8795
8923
|
my $ns = substr($$dataPt, $pos + 4, 4);
|
8796
8924
|
my $tag = substr($$dataPt, $pos + 8, $len - 8);
|
8797
8925
|
$tag =~ s/\0.*//s; # truncate at null
|
8926
|
+
my $full = $tag;
|
8798
8927
|
$tag =~ s/^com\.(apple\.quicktime\.)?// if $ns eq 'mdta'; # remove apple quicktime domain
|
8799
8928
|
$tag = "Tag_$ns" unless $tag;
|
8800
|
-
|
8801
|
-
my $tagInfo
|
8802
|
-
|
8803
|
-
$tagInfo = $et->GetTagInfo($
|
8804
|
-
|
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;
|
8805
8940
|
$tagInfo = $et->GetTagInfo($userData, $tag);
|
8806
|
-
|
8807
|
-
$tag = pack('N', unpack('V', $tag));
|
8808
|
-
$tagInfo = $et->GetTagInfo($itemList, $tag);
|
8809
|
-
$tagInfo or $tagInfo = $et->GetTagInfo($userData, $tag);
|
8810
|
-
}
|
8941
|
+
last;
|
8811
8942
|
}
|
8943
|
+
if ($tag eq $full) {
|
8944
|
+
$tag = $short;
|
8945
|
+
last;
|
8946
|
+
}
|
8947
|
+
$tag = $full;
|
8812
8948
|
}
|
8813
8949
|
my ($newInfo, $msg);
|
8814
8950
|
if ($tagInfo) {
|
@@ -8849,6 +8985,7 @@ sub ProcessKeys($$$)
|
|
8849
8985
|
delete $$itemList{$id};
|
8850
8986
|
}
|
8851
8987
|
if ($newInfo) {
|
8988
|
+
$$newInfo{KeysID} = $tag; # save original ID for use in family 7 group name
|
8852
8989
|
AddTagToTable($itemList, $id, $newInfo);
|
8853
8990
|
$msg or $msg = '';
|
8854
8991
|
$out and print $out "$$et{INDENT}Added ItemList Tag $id = ($ns) $tag$msg\n";
|
@@ -8927,6 +9064,7 @@ sub ProcessMOV($$;$)
|
|
8927
9064
|
if ($raf->Read($buff, $size-8) == $size-8) {
|
8928
9065
|
$raf->Seek(-($size-8), 1);
|
8929
9066
|
my $type = substr($buff, 0, 4);
|
9067
|
+
$$et{save_ftyp} = $type;
|
8930
9068
|
# see if we know the extension for this file type
|
8931
9069
|
if ($ftypLookup{$type} and $ftypLookup{$type} =~ /\(\.(\w+)/) {
|
8932
9070
|
$fileType = $1;
|
@@ -9201,6 +9339,7 @@ ItemID: foreach $id (keys %$items) {
|
|
9201
9339
|
Name => $name,
|
9202
9340
|
Description => $desc,
|
9203
9341
|
};
|
9342
|
+
$et->VPrint(0, $$et{INDENT}, "[adding QuickTime:$name]\n");
|
9204
9343
|
AddTagToTable($tagTablePtr, $tag, $tagInfo);
|
9205
9344
|
}
|
9206
9345
|
# ignore 8-byte header
|
@@ -9212,9 +9351,9 @@ ItemID: foreach $id (keys %$items) {
|
|
9212
9351
|
$val = \$buff;
|
9213
9352
|
}
|
9214
9353
|
}
|
9215
|
-
|
9354
|
+
$$tagInfo{List} = 1; # (allow any of these tags to have multiple data elements)
|
9355
|
+
$et->VerboseInfo($tag, $tagInfo, Value => $val) if $verbose;
|
9216
9356
|
} else {
|
9217
|
-
undef %triplet if $tag eq 'mean';
|
9218
9357
|
$triplet{$tag} = substr($val,4) if length($val) > 4;
|
9219
9358
|
undef $tagInfo; # don't store this tag
|
9220
9359
|
}
|
@@ -9298,7 +9437,13 @@ ItemID: foreach $id (keys %$items) {
|
|
9298
9437
|
# (shouldn't be null terminated, but some software writes it anyway)
|
9299
9438
|
$value =~ s/\0$// unless $$tagInfo{Binary};
|
9300
9439
|
} else {
|
9301
|
-
|
9440
|
+
if (not $format) {
|
9441
|
+
$format = QuickTimeFormat($flags, $len);
|
9442
|
+
} elsif ($format =~ /^int\d+([us])$/) {
|
9443
|
+
# adjust integer to available length (but not int64)
|
9444
|
+
my $fmt = { 1=>'int8', 2=>'int16', 4=>'int32' }->{$len};
|
9445
|
+
$format = $fmt . $1 if defined $fmt;
|
9446
|
+
}
|
9302
9447
|
if ($format) {
|
9303
9448
|
$value = ReadValue(\$value, 0, $format, $$tagInfo{Count}, $len);
|
9304
9449
|
} elsif (not $$tagInfo{ValueConv}) {
|
@@ -9350,9 +9495,9 @@ ItemID: foreach $id (keys %$items) {
|
|
9350
9495
|
}
|
9351
9496
|
for (;;) {
|
9352
9497
|
my ($len, $lang);
|
9353
|
-
if ($$tagInfo{IText} and $$tagInfo{IText}
|
9354
|
-
last if $pos +
|
9355
|
-
$pos +=
|
9498
|
+
if ($$tagInfo{IText} and $$tagInfo{IText} >= 6) {
|
9499
|
+
last if $pos + $$tagInfo{IText} > $size;
|
9500
|
+
$pos += $$tagInfo{IText} - 2;
|
9356
9501
|
$lang = unpack("x${pos}n", $val);
|
9357
9502
|
$pos += 2;
|
9358
9503
|
$len = $size - $pos;
|
@@ -9372,7 +9517,7 @@ ItemID: foreach $id (keys %$items) {
|
|
9372
9517
|
# ignore any empty entries (or null padding) after the first
|
9373
9518
|
next if not $len and $pos;
|
9374
9519
|
my $str = substr($val, $pos, $len);
|
9375
|
-
my $langInfo;
|
9520
|
+
my ($langInfo, $enc);
|
9376
9521
|
if (($lang < 0x400 or $lang == 0x7fff) and $str !~ /^\xfe\xff/) {
|
9377
9522
|
# this is a Macintosh language code
|
9378
9523
|
# a language code of 0 is Macintosh english, so treat as default
|
@@ -9389,15 +9534,22 @@ ItemID: foreach $id (keys %$items) {
|
|
9389
9534
|
}
|
9390
9535
|
# the spec says only "Macintosh text encoding", but
|
9391
9536
|
# allow this to be configured by the user
|
9392
|
-
$
|
9537
|
+
$enc = $charsetQuickTime;
|
9393
9538
|
} else {
|
9394
9539
|
# convert language code to ASCII (ignore read-only bit)
|
9395
9540
|
$lang = UnpackLang($lang);
|
9396
9541
|
# may be either UTF-8 or UTF-16BE
|
9397
|
-
|
9542
|
+
$enc = $str=~s/^\xfe\xff// ? 'UTF16' : 'UTF8';
|
9543
|
+
}
|
9544
|
+
unless ($$tagInfo{NoDecode}) {
|
9398
9545
|
$str = $et->Decode($str, $enc);
|
9546
|
+
$str =~ s/\0+$//; # remove any trailing nulls (eg. 3gp tags)
|
9547
|
+
}
|
9548
|
+
if ($$tagInfo{IText} and $$tagInfo{IText} > 6) {
|
9549
|
+
my $n = $$tagInfo{IText} - 6;
|
9550
|
+
# add back extra bytes (eg. 'rtng' box)
|
9551
|
+
$str = substr($val, $pos-$n-2, $n) . $str;
|
9399
9552
|
}
|
9400
|
-
$str =~ s/\0+$//; # remove any trailing nulls (eg. 3gp tags)
|
9401
9553
|
$langInfo = GetLangInfoQT($et, $tagInfo, $lang) if $lang;
|
9402
9554
|
$et->FoundTag($langInfo || $tagInfo, $str);
|
9403
9555
|
$pos += $len;
|
@@ -9447,6 +9599,13 @@ ItemID: foreach $id (keys %$items) {
|
|
9447
9599
|
($size, $tag) = unpack('Na4', $buff);
|
9448
9600
|
++$index if defined $index;
|
9449
9601
|
}
|
9602
|
+
# tweak file type based on track content ("iso*" and "dash" ftyp only)
|
9603
|
+
if ($topLevel and $$et{VALUE}{FileType} and $$et{VALUE}{FileType} eq 'MP4' and
|
9604
|
+
$$et{save_ftyp} and $$et{HasHandler} and $$et{save_ftyp} =~ /^(iso|dash)/ and
|
9605
|
+
$$et{HasHandler}{soun} and not $$et{HasHandler}{vide})
|
9606
|
+
{
|
9607
|
+
$et->OverrideFileType('M4A', 'audio/mp4');
|
9608
|
+
}
|
9450
9609
|
# fill in missing defaults for alternate language tags
|
9451
9610
|
# (the first language is taken as the default)
|
9452
9611
|
if ($doDefaultLang and $$et{QTLang}) {
|