exiftool_vendored 12.22.0 → 12.34.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 +201 -5
- data/bin/MANIFEST +22 -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 +1 -1
- data/bin/exiftool +89 -70
- data/bin/fmt_files/gpx.fmt +1 -1
- data/bin/fmt_files/gpx_wpt.fmt +1 -1
- data/bin/lib/Image/ExifTool/BuildTagLookup.pm +17 -4
- data/bin/lib/Image/ExifTool/CBOR.pm +331 -0
- data/bin/lib/Image/ExifTool/Canon.pm +53 -21
- data/bin/lib/Image/ExifTool/Charset.pm +2 -0
- 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 +120 -12
- data/bin/lib/Image/ExifTool/FlashPix.pm +35 -10
- data/bin/lib/Image/ExifTool/FujiFilm.pm +19 -8
- 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 +96 -4
- 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 +103 -7
- data/bin/lib/Image/ExifTool/MIE.pm +2 -1
- 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 +5 -3
- data/bin/lib/Image/ExifTool/Nikon.pm +17 -5
- data/bin/lib/Image/ExifTool/NikonSettings.pm +19 -2
- data/bin/lib/Image/ExifTool/Olympus.pm +9 -2
- data/bin/lib/Image/ExifTool/Other.pm +93 -0
- data/bin/lib/Image/ExifTool/PDF.pm +11 -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 +210 -65
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +280 -139
- data/bin/lib/Image/ExifTool/README +9 -2
- data/bin/lib/Image/ExifTool/RIFF.pm +89 -12
- data/bin/lib/Image/ExifTool/Samsung.pm +48 -10
- data/bin/lib/Image/ExifTool/Sony.pm +204 -61
- data/bin/lib/Image/ExifTool/TagLookup.pm +206 -19
- data/bin/lib/Image/ExifTool/TagNames.pod +634 -195
- data/bin/lib/Image/ExifTool/Torrent.pm +18 -11
- 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 +58 -16
- data/bin/lib/Image/ExifTool/WriteXMP.pl +7 -3
- data/bin/lib/Image/ExifTool/Writer.pl +44 -0
- data/bin/lib/Image/ExifTool/XMP.pm +51 -18
- data/bin/lib/Image/ExifTool/XMP2.pl +4 -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 +188 -61
- data/bin/lib/Image/ExifTool.pod +89 -68
- data/bin/perl-Image-ExifTool.spec +43 -42
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +10 -9
@@ -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.71';
|
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};
|
@@ -549,6 +558,7 @@ my %eeBox2 = (
|
|
549
558
|
# *** this is where ExifTool writes XMP in MP4 videos (as per XMP spec) ***
|
550
559
|
Condition => '$$valPt=~/^\xbe\x7a\xcf\xcb\x97\xa9\x42\xe8\x9c\x71\x99\x94\x91\xe3\xaf\xac/',
|
551
560
|
WriteGroup => 'XMP', # (write main XMP tags here)
|
561
|
+
PreservePadding => 1,
|
552
562
|
SubDirectory => {
|
553
563
|
TagTable => 'Image::ExifTool::XMP::Main',
|
554
564
|
Start => 16,
|
@@ -598,6 +608,7 @@ my %eeBox2 = (
|
|
598
608
|
Name => 'PreviewImage',
|
599
609
|
Condition => '$$valPt=~/^\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16/',
|
600
610
|
Groups => { 2 => 'Preview' },
|
611
|
+
PreservePadding => 1,
|
601
612
|
# 0x00 - undef[16]: UUID
|
602
613
|
# 0x10 - int32u[2]: "0 1" (version and/or item count?)
|
603
614
|
# 0x18 - int32u: PRVW atom size
|
@@ -678,6 +689,15 @@ my %eeBox2 = (
|
|
678
689
|
udat => { #PH (GPS NMEA-format log written by Datakam Player software)
|
679
690
|
Name => 'GPSLog',
|
680
691
|
Binary => 1, # (actually ASCII, but very lengthy)
|
692
|
+
Notes => 'parsed to extract GPS separately when ExtractEmbedded is used',
|
693
|
+
RawConv => q{
|
694
|
+
$val =~ s/\0+$//; # remove trailing nulls
|
695
|
+
if (length $val and $$self{OPTIONS}{ExtractEmbedded}) {
|
696
|
+
my $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream');
|
697
|
+
Image::ExifTool::QuickTime::ProcessGPSLog($self, { DataPt => \$val }, $tagTbl);
|
698
|
+
}
|
699
|
+
return $val;
|
700
|
+
},
|
681
701
|
},
|
682
702
|
# meta - proprietary XML information written by some Flip cameras - PH
|
683
703
|
# beam - 16 bytes found in an iPhone video
|
@@ -716,6 +736,11 @@ my %eeBox2 = (
|
|
716
736
|
Unknown => 1,
|
717
737
|
Binary => 1,
|
718
738
|
},
|
739
|
+
sefd => {
|
740
|
+
Name => 'SamsungTrailer',
|
741
|
+
SubDirectory => { TagTable => 'Image::ExifTool::Samsung::Trailer' },
|
742
|
+
},
|
743
|
+
# 'samn'? - seen in Vantrue N2S sample video
|
719
744
|
);
|
720
745
|
|
721
746
|
# MPEG-4 'ftyp' atom
|
@@ -1177,6 +1202,15 @@ my %eeBox2 = (
|
|
1177
1202
|
Name => 'CreateDate',
|
1178
1203
|
Groups => { 2 => 'Time' },
|
1179
1204
|
%timeInfo,
|
1205
|
+
RawConv => q{
|
1206
|
+
my $offset = (66 * 365 + 17) * 24 * 3600;
|
1207
|
+
if ($val >= $offset or $$self{OPTIONS}{QuickTimeUTC}) {
|
1208
|
+
$val -= $offset;
|
1209
|
+
} elsif ($val and not $$self{IsWriting}) {
|
1210
|
+
$self->WarnOnce('Patched incorrect time zero for QuickTime date/time tag',1);
|
1211
|
+
}
|
1212
|
+
return $$self{CreateDate} = $val;
|
1213
|
+
},
|
1180
1214
|
# this is int64u if MovieHeaderVersion == 1 (ref 13)
|
1181
1215
|
Hook => '$$self{MovieHeaderVersion} and $format = "int64u", $varSize += 4',
|
1182
1216
|
},
|
@@ -1564,36 +1598,29 @@ my %eeBox2 = (
|
|
1564
1598
|
coll => { Name => 'CollectionName', %langText3gp }, #17
|
1565
1599
|
rtng => {
|
1566
1600
|
Name => 'Rating',
|
1601
|
+
Writable => 'undef',
|
1602
|
+
Avoid => 1,
|
1567
1603
|
# (4-byte flags, 4-char entity, 4-char criteria, 2-byte lang, string)
|
1568
|
-
|
1569
|
-
|
1570
|
-
|
1571
|
-
|
1572
|
-
my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 12));
|
1573
|
-
$lang = $lang ? "($lang) " : '';
|
1574
|
-
$val = substr($val, 14);
|
1575
|
-
$val = $self->Decode($val, 'UCS2') if $val =~ /^\xfe\xff/;
|
1576
|
-
return $lang . $str . ' ' . $val;
|
1577
|
-
},
|
1604
|
+
IText => 14, # (14 bytes before string)
|
1605
|
+
Notes => 'string in the form "Entity=XXXX Criteria=XXXX XXXXX", used in 3gp videos',
|
1606
|
+
ValueConv => '$val=~s/^(.{4})(.{4})/Entity=$1 Criteria=$2 /i; $val',
|
1607
|
+
ValueConvInv => '$val=~s/Entity=(.{4}) Criteria=(.{4}) ?/$1$2/i; $val',
|
1578
1608
|
},
|
1579
1609
|
clsf => {
|
1580
1610
|
Name => 'Classification',
|
1611
|
+
Writable => 'undef',
|
1612
|
+
Avoid => 1,
|
1581
1613
|
# (4-byte flags, 4-char entity, 2-byte index, 2-byte lang, string)
|
1582
|
-
|
1583
|
-
|
1584
|
-
|
1585
|
-
|
1586
|
-
my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 10));
|
1587
|
-
$lang = $lang ? "($lang) " : '';
|
1588
|
-
$val = substr($val, 12);
|
1589
|
-
$val = $self->Decode($val, 'UCS2') if $val =~ /^\xfe\xff/;
|
1590
|
-
return $lang . $str . ' ' . $val;
|
1591
|
-
},
|
1614
|
+
IText => 12,
|
1615
|
+
Notes => 'string in the form "Entity=XXXX Index=### XXXXX", used in 3gp videos',
|
1616
|
+
ValueConv => '$val=~s/^(.{4})(.{2})/"Entity=$1 Index=".unpack("n",$2)." "/ie; $val',
|
1617
|
+
ValueConvInv => '$val=~s/Entity=(.{4}) Index=(\d+) ?/$1.pack("n",$2)/ie; $val',
|
1592
1618
|
},
|
1593
1619
|
kywd => {
|
1594
1620
|
Name => 'Keywords',
|
1595
1621
|
# (4 byte flags, 2-byte lang, 1-byte count, count x pascal strings, ref 17)
|
1596
|
-
# (but I have also seen a simple string written by iPhone)
|
1622
|
+
# (but I have also seen a simple string written by iPhone, so don't make writable yet)
|
1623
|
+
Notes => "not writable because Apple doesn't follow the 3gp specification",
|
1597
1624
|
RawConv => q{
|
1598
1625
|
my $sep = $self->Options('ListSep');
|
1599
1626
|
return join($sep, split /\0+/, $val) unless $val =~ /^\0/; # (iPhone)
|
@@ -1618,20 +1645,24 @@ my %eeBox2 = (
|
|
1618
1645
|
loci => {
|
1619
1646
|
Name => 'LocationInformation',
|
1620
1647
|
Groups => { 2 => 'Location' },
|
1648
|
+
Writable => 'undef',
|
1649
|
+
IText => 6,
|
1650
|
+
Avoid => 1,
|
1651
|
+
NoDecode => 1, # (we'll decode the data ourself)
|
1652
|
+
Notes => q{
|
1653
|
+
string in the form "XXXXX Role=XXX Lat=XXX Lon=XXX Alt=XXX Body=XXX
|
1654
|
+
Notes=XXX", used in 3gp videos
|
1655
|
+
},
|
1621
1656
|
# (4-byte flags, 2-byte lang, location string, 1-byte role, 4-byte fixed longitude,
|
1622
1657
|
# 4-byte fixed latitude, 4-byte fixed altitude, body string, notes string)
|
1623
1658
|
RawConv => q{
|
1624
|
-
return '<err>' unless length $val >= 6;
|
1625
|
-
my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 4));
|
1626
|
-
$lang = $lang ? "($lang) " : '';
|
1627
|
-
$val = substr($val, 6);
|
1628
1659
|
my $str;
|
1629
1660
|
if ($val =~ /^\xfe\xff/) {
|
1630
1661
|
$val =~ s/^(\xfe\xff(.{2})*?)\0\0//s or return '<err>';
|
1631
1662
|
$str = $self->Decode($1, 'UCS2');
|
1632
1663
|
} else {
|
1633
1664
|
$val =~ s/^(.*?)\0//s or return '<err>';
|
1634
|
-
$str = $1;
|
1665
|
+
$str = $self->Decode($1, 'UTF8');
|
1635
1666
|
}
|
1636
1667
|
$str = '(none)' unless length $str;
|
1637
1668
|
return '<err>' if length $val < 13;
|
@@ -1646,27 +1677,52 @@ my %eeBox2 = (
|
|
1646
1677
|
if ($val =~ s/^(\xfe\xff(.{2})*?)\0\0//s) {
|
1647
1678
|
$str .= ' Body=' . $self->Decode($1, 'UCS2');
|
1648
1679
|
} elsif ($val =~ s/^(.*?)\0//s) {
|
1649
|
-
$str .=
|
1680
|
+
$str .= ' Body=' . $self->Decode($1, 'UTF8');
|
1650
1681
|
}
|
1651
1682
|
if ($val =~ s/^(\xfe\xff(.{2})*?)\0\0//s) {
|
1652
1683
|
$str .= ' Notes=' . $self->Decode($1, 'UCS2');
|
1653
1684
|
} elsif ($val =~ s/^(.*?)\0//s) {
|
1654
|
-
$str .=
|
1685
|
+
$str .= ' Notes=' . $self->Decode($1, 'UTF8');
|
1655
1686
|
}
|
1656
|
-
return $
|
1687
|
+
return $str;
|
1688
|
+
},
|
1689
|
+
RawConvInv => q{
|
1690
|
+
my ($role, $lat, $lon, $alt, $body, $note);
|
1691
|
+
$lat = $1 if $val =~ s/ Lat=([-+]?[.\d]+)//i;
|
1692
|
+
$lon = $1 if $val =~ s/ Lon=([-+]?[.\d]+)//i;
|
1693
|
+
$alt = $1 if $val =~ s/ Alt=([-+]?[.\d]+)//i;
|
1694
|
+
$note = $val =~ s/ Notes=(.*)//i ? $1 : '';
|
1695
|
+
$body = $val =~ s/ Body=(.*)//i ? $1 : '';
|
1696
|
+
$role = $val =~ s/ Role=(.*)//i ? $1 : '';
|
1697
|
+
$val = '' if $val eq '(none)';
|
1698
|
+
$role = {shooting=>0,real=>1,fictional=>2}->{lc $role} || 0;
|
1699
|
+
return $self->Encode($val, 'UTF8') . "\0" . Set8u($role) .
|
1700
|
+
SetFixed32s(defined $lon ? $lon : 999) .
|
1701
|
+
SetFixed32s(defined $lat ? $lat : 999) .
|
1702
|
+
SetFixed32s(defined $alt ? $alt : 0) .
|
1703
|
+
$self->Encode($body) . "\0" .
|
1704
|
+
$self->Encode($note) . "\0";
|
1657
1705
|
},
|
1658
1706
|
},
|
1659
1707
|
yrrc => {
|
1660
1708
|
Name => 'Year',
|
1709
|
+
Writable => 'undef',
|
1661
1710
|
Groups => { 2 => 'Time' },
|
1662
|
-
|
1711
|
+
Avoid => 1,
|
1712
|
+
Notes => 'used in 3gp videos',
|
1713
|
+
ValueConv => 'length($val) >= 6 ? unpack("x4n",$val) : "<err>"',
|
1714
|
+
ValueConvInv => 'pack("Nn",0,$val)',
|
1663
1715
|
},
|
1664
1716
|
urat => { #17
|
1665
1717
|
Name => 'UserRating',
|
1666
|
-
|
1718
|
+
Writable => 'undef',
|
1719
|
+
Notes => 'used in 3gp videos',
|
1720
|
+
Avoid => 1,
|
1721
|
+
ValueConv => q{
|
1667
1722
|
return '<err>' unless length $val >= 8;
|
1668
|
-
|
1723
|
+
unpack('x7C', $val);
|
1669
1724
|
},
|
1725
|
+
ValueConvInv => 'pack("N2",0,$val)',
|
1670
1726
|
},
|
1671
1727
|
# tsel - TrackSelection (ref 17)
|
1672
1728
|
# Apple tags (ref 16[dead] -- see ref 25 instead)
|
@@ -2215,6 +2271,12 @@ my %eeBox2 = (
|
|
2215
2271
|
# opax - 164 bytes unknown (center and affine arrays? ref 26)
|
2216
2272
|
# opai - 32 bytes (maybe contains a serial number starting at byte 16? - PH) (rgb gains, degamma, gamma? ref 26)
|
2217
2273
|
# intv - 16 bytes all zero
|
2274
|
+
# ---- Xaiomi ----
|
2275
|
+
mcvr => {
|
2276
|
+
Name => 'PreviewImage',
|
2277
|
+
Groups => { 2 => 'Preview' },
|
2278
|
+
Binary => 1,
|
2279
|
+
},
|
2218
2280
|
# ---- Unknown ----
|
2219
2281
|
# CDET - 128 bytes (unknown origin)
|
2220
2282
|
# mtyp - 4 bytes all zero (some drone video)
|
@@ -2652,6 +2714,7 @@ my %eeBox2 = (
|
|
2652
2714
|
colr => [{
|
2653
2715
|
Name => 'ICC_Profile',
|
2654
2716
|
Condition => '$$valPt =~ /^(prof|rICC)/',
|
2717
|
+
Permanent => 0, # (in QuickTime, this writes a zero-length box instead of deleting)
|
2655
2718
|
SubDirectory => {
|
2656
2719
|
TagTable => 'Image::ExifTool::ICC_Profile::Main',
|
2657
2720
|
Start => 4,
|
@@ -6242,6 +6305,10 @@ my %eeBox2 = (
|
|
6242
6305
|
'location.ISO6709' => {
|
6243
6306
|
Name => 'GPSCoordinates',
|
6244
6307
|
Groups => { 2 => 'Location' },
|
6308
|
+
Notes => q{
|
6309
|
+
Google Photos may ignore this if the coorinates have more than 5 digits
|
6310
|
+
after the decimal
|
6311
|
+
},
|
6245
6312
|
ValueConv => \&ConvertISO6709,
|
6246
6313
|
ValueConvInv => \&ConvInvISO6709,
|
6247
6314
|
PrintConv => \&PrintGPSCoordinates,
|
@@ -6386,10 +6453,11 @@ my %eeBox2 = (
|
|
6386
6453
|
# iTunes info ('----') atoms
|
6387
6454
|
%Image::ExifTool::QuickTime::iTunesInfo = (
|
6388
6455
|
PROCESS_PROC => \&ProcessMOV,
|
6389
|
-
GROUPS => { 2 => 'Audio' },
|
6456
|
+
GROUPS => { 1 => 'iTunes', 2 => 'Audio' },
|
6390
6457
|
NOTES => q{
|
6391
6458
|
ExifTool will extract any iTunesInfo tags that exist, even if they are not
|
6392
|
-
defined in this table.
|
6459
|
+
defined in this table. These tags belong to the family 1 "iTunes" group,
|
6460
|
+
and are not currently writable.
|
6393
6461
|
},
|
6394
6462
|
# 'mean'/'name'/'data' atoms form a triplet, but unfortunately
|
6395
6463
|
# I haven't been able to find any documentation on this.
|
@@ -6450,9 +6518,45 @@ my %eeBox2 = (
|
|
6450
6518
|
SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::EncodingParams' },
|
6451
6519
|
},
|
6452
6520
|
# also heard about 'iTunPGAP', but I haven't seen a sample
|
6453
|
-
|
6454
|
-
|
6455
|
-
|
6521
|
+
# all tags below were added based on samples I have seen - PH
|
6522
|
+
DISCNUMBER => 'DiscNumber',
|
6523
|
+
TRACKNUMBER => 'TrackNumber',
|
6524
|
+
ARTISTS => 'Artists',
|
6525
|
+
CATALOGNUMBER => 'CatalogNumber',
|
6526
|
+
RATING => 'Rating',
|
6527
|
+
MEDIA => 'Media',
|
6528
|
+
SCRIPT => 'Script', # character set? (seen 'Latn')
|
6529
|
+
BARCODE => 'Barcode',
|
6530
|
+
LABEL => 'Label',
|
6531
|
+
MOOD => 'Mood',
|
6532
|
+
popularimeter => 'Popularimeter',
|
6533
|
+
'Dynamic Range (DR)'=> 'DynamicRange',
|
6534
|
+
initialkey => 'InitialKey',
|
6535
|
+
originalyear => 'OriginalYear',
|
6536
|
+
originaldate => 'OriginalDate',
|
6537
|
+
'~length' => 'Length', # play length? (ie. duration?)
|
6538
|
+
replaygain_track_gain=>'ReplayTrackGain',
|
6539
|
+
replaygain_track_peak=>'ReplayTrackPeak',
|
6540
|
+
'Volume Level (ReplayGain)'=> 'ReplayVolumeLevel',
|
6541
|
+
'Dynamic Range (R128)'=> 'DynamicRangeR128',
|
6542
|
+
'Volume Level (R128)' => 'VolumeLevelR128',
|
6543
|
+
'Peak Level (Sample)' => 'PeakLevelSample',
|
6544
|
+
'Peak Level (R128)' => 'PeakLevelR128',
|
6545
|
+
# also seen (many from forum12777):
|
6546
|
+
# 'MusicBrainz Album Release Country'
|
6547
|
+
# 'MusicBrainz Album Type'
|
6548
|
+
# 'MusicBrainz Album Status'
|
6549
|
+
# 'MusicBrainz Track Id'
|
6550
|
+
# 'MusicBrainz Release Track Id'
|
6551
|
+
# 'MusicBrainz Album Id'
|
6552
|
+
# 'MusicBrainz Album Artist Id'
|
6553
|
+
# 'MusicBrainz Artist Id'
|
6554
|
+
# 'Acoustid Id' (sic)
|
6555
|
+
# 'Tool Version'
|
6556
|
+
# 'Tool Name'
|
6557
|
+
# 'ISRC'
|
6558
|
+
# 'HDCD'
|
6559
|
+
# 'Waveform'
|
6456
6560
|
);
|
6457
6561
|
|
6458
6562
|
# iTunes audio encoding parameters
|
@@ -7611,7 +7715,11 @@ my %eeBox2 = (
|
|
7611
7715
|
8 => {
|
7612
7716
|
Name => 'HandlerType',
|
7613
7717
|
Format => 'undef[4]',
|
7614
|
-
RawConv =>
|
7718
|
+
RawConv => q{
|
7719
|
+
$$self{HandlerType} = $val unless $val eq 'alis' or $val eq 'url ';
|
7720
|
+
$$self{HasHandler}{$val} = 1; # remember all our handlers
|
7721
|
+
return $val;
|
7722
|
+
},
|
7615
7723
|
PrintConvColumns => 2,
|
7616
7724
|
PrintConv => {
|
7617
7725
|
alis => 'Alias Data', #PH
|
@@ -7716,7 +7824,7 @@ my %eeBox2 = (
|
|
7716
7824
|
$val =~ s/\0+$//; # remove trailing nulls
|
7717
7825
|
if (length $val and $$self{OPTIONS}{ExtractEmbedded}) {
|
7718
7826
|
my $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream');
|
7719
|
-
Image::ExifTool::QuickTime::
|
7827
|
+
Image::ExifTool::QuickTime::ProcessGPSLog($self, { DataPt => \$val }, $tagTbl);
|
7720
7828
|
}
|
7721
7829
|
return $val;
|
7722
7830
|
},
|
@@ -8817,20 +8925,28 @@ sub ProcessKeys($$$)
|
|
8817
8925
|
my $ns = substr($$dataPt, $pos + 4, 4);
|
8818
8926
|
my $tag = substr($$dataPt, $pos + 8, $len - 8);
|
8819
8927
|
$tag =~ s/\0.*//s; # truncate at null
|
8928
|
+
my $full = $tag;
|
8820
8929
|
$tag =~ s/^com\.(apple\.quicktime\.)?// if $ns eq 'mdta'; # remove apple quicktime domain
|
8821
8930
|
$tag = "Tag_$ns" unless $tag;
|
8822
|
-
|
8823
|
-
my $tagInfo
|
8824
|
-
|
8825
|
-
$tagInfo = $et->GetTagInfo($
|
8826
|
-
|
8931
|
+
my $short = $tag;
|
8932
|
+
my $tagInfo;
|
8933
|
+
for (;;) {
|
8934
|
+
$tagInfo = $et->GetTagInfo($tagTablePtr, $tag) and last;
|
8935
|
+
# also try ItemList and UserData tables
|
8936
|
+
$tagInfo = $et->GetTagInfo($itemList, $tag) and last;
|
8937
|
+
$tagInfo = $et->GetTagInfo($userData, $tag) and last;
|
8938
|
+
# (I have some samples where the tag is a reversed ItemList or UserData tag ID)
|
8939
|
+
if ($tag =~ /^\w{3}\xa9$/) {
|
8940
|
+
$tag = pack('N', unpack('V', $tag));
|
8941
|
+
$tagInfo = $et->GetTagInfo($itemList, $tag) and last;
|
8827
8942
|
$tagInfo = $et->GetTagInfo($userData, $tag);
|
8828
|
-
|
8829
|
-
|
8830
|
-
|
8831
|
-
|
8832
|
-
|
8943
|
+
last;
|
8944
|
+
}
|
8945
|
+
if ($tag eq $full) {
|
8946
|
+
$tag = $short;
|
8947
|
+
last;
|
8833
8948
|
}
|
8949
|
+
$tag = $full;
|
8834
8950
|
}
|
8835
8951
|
my ($newInfo, $msg);
|
8836
8952
|
if ($tagInfo) {
|
@@ -8871,6 +8987,7 @@ sub ProcessKeys($$$)
|
|
8871
8987
|
delete $$itemList{$id};
|
8872
8988
|
}
|
8873
8989
|
if ($newInfo) {
|
8990
|
+
$$newInfo{KeysID} = $tag; # save original ID for use in family 7 group name
|
8874
8991
|
AddTagToTable($itemList, $id, $newInfo);
|
8875
8992
|
$msg or $msg = '';
|
8876
8993
|
$out and print $out "$$et{INDENT}Added ItemList Tag $id = ($ns) $tag$msg\n";
|
@@ -8949,6 +9066,7 @@ sub ProcessMOV($$;$)
|
|
8949
9066
|
if ($raf->Read($buff, $size-8) == $size-8) {
|
8950
9067
|
$raf->Seek(-($size-8), 1);
|
8951
9068
|
my $type = substr($buff, 0, 4);
|
9069
|
+
$$et{save_ftyp} = $type;
|
8952
9070
|
# see if we know the extension for this file type
|
8953
9071
|
if ($ftypLookup{$type} and $ftypLookup{$type} =~ /\(\.(\w+)/) {
|
8954
9072
|
$fileType = $1;
|
@@ -8997,6 +9115,12 @@ sub ProcessMOV($$;$)
|
|
8997
9115
|
} else {
|
8998
9116
|
my $t = PrintableTagID($tag,2);
|
8999
9117
|
$et->VPrint(0,"$$et{INDENT}Tag '${t}' extends to end of file");
|
9118
|
+
if ($$tagTablePtr{"$tag-size"}) {
|
9119
|
+
my $pos = $raf->Tell();
|
9120
|
+
$raf->Seek(0, 2);
|
9121
|
+
$et->HandleTag($tagTablePtr, "$tag-size", $raf->Tell() - $pos);
|
9122
|
+
$et->HandleTag($tagTablePtr, "$tag-offset", $pos) if $$tagTablePtr{"$tag-offset"};
|
9123
|
+
}
|
9000
9124
|
}
|
9001
9125
|
last;
|
9002
9126
|
}
|
@@ -9223,6 +9347,7 @@ ItemID: foreach $id (keys %$items) {
|
|
9223
9347
|
Name => $name,
|
9224
9348
|
Description => $desc,
|
9225
9349
|
};
|
9350
|
+
$et->VPrint(0, $$et{INDENT}, "[adding QuickTime:$name]\n");
|
9226
9351
|
AddTagToTable($tagTablePtr, $tag, $tagInfo);
|
9227
9352
|
}
|
9228
9353
|
# ignore 8-byte header
|
@@ -9234,9 +9359,9 @@ ItemID: foreach $id (keys %$items) {
|
|
9234
9359
|
$val = \$buff;
|
9235
9360
|
}
|
9236
9361
|
}
|
9237
|
-
|
9362
|
+
$$tagInfo{List} = 1; # (allow any of these tags to have multiple data elements)
|
9363
|
+
$et->VerboseInfo($tag, $tagInfo, Value => $val) if $verbose;
|
9238
9364
|
} else {
|
9239
|
-
undef %triplet if $tag eq 'mean';
|
9240
9365
|
$triplet{$tag} = substr($val,4) if length($val) > 4;
|
9241
9366
|
undef $tagInfo; # don't store this tag
|
9242
9367
|
}
|
@@ -9302,7 +9427,7 @@ ItemID: foreach $id (keys %$items) {
|
|
9302
9427
|
for (;;) {
|
9303
9428
|
last if $pos + 16 > $size;
|
9304
9429
|
my ($len, $type, $flags, $ctry, $lang) = unpack("x${pos}Na4Nnn", $val);
|
9305
|
-
last if $pos + $len > $size;
|
9430
|
+
last if $pos + $len > $size or not $len;
|
9306
9431
|
my ($value, $langInfo, $oldDir);
|
9307
9432
|
my $format = $$tagInfo{Format};
|
9308
9433
|
if ($type eq 'data' and $len >= 16) {
|
@@ -9320,7 +9445,13 @@ ItemID: foreach $id (keys %$items) {
|
|
9320
9445
|
# (shouldn't be null terminated, but some software writes it anyway)
|
9321
9446
|
$value =~ s/\0$// unless $$tagInfo{Binary};
|
9322
9447
|
} else {
|
9323
|
-
|
9448
|
+
if (not $format) {
|
9449
|
+
$format = QuickTimeFormat($flags, $len);
|
9450
|
+
} elsif ($format =~ /^int\d+([us])$/) {
|
9451
|
+
# adjust integer to available length (but not int64)
|
9452
|
+
my $fmt = { 1=>'int8', 2=>'int16', 4=>'int32' }->{$len};
|
9453
|
+
$format = $fmt . $1 if defined $fmt;
|
9454
|
+
}
|
9324
9455
|
if ($format) {
|
9325
9456
|
$value = ReadValue(\$value, 0, $format, $$tagInfo{Count}, $len);
|
9326
9457
|
} elsif (not $$tagInfo{ValueConv}) {
|
@@ -9372,9 +9503,9 @@ ItemID: foreach $id (keys %$items) {
|
|
9372
9503
|
}
|
9373
9504
|
for (;;) {
|
9374
9505
|
my ($len, $lang);
|
9375
|
-
if ($$tagInfo{IText} and $$tagInfo{IText}
|
9376
|
-
last if $pos +
|
9377
|
-
$pos +=
|
9506
|
+
if ($$tagInfo{IText} and $$tagInfo{IText} >= 6) {
|
9507
|
+
last if $pos + $$tagInfo{IText} > $size;
|
9508
|
+
$pos += $$tagInfo{IText} - 2;
|
9378
9509
|
$lang = unpack("x${pos}n", $val);
|
9379
9510
|
$pos += 2;
|
9380
9511
|
$len = $size - $pos;
|
@@ -9394,7 +9525,7 @@ ItemID: foreach $id (keys %$items) {
|
|
9394
9525
|
# ignore any empty entries (or null padding) after the first
|
9395
9526
|
next if not $len and $pos;
|
9396
9527
|
my $str = substr($val, $pos, $len);
|
9397
|
-
my $langInfo;
|
9528
|
+
my ($langInfo, $enc);
|
9398
9529
|
if (($lang < 0x400 or $lang == 0x7fff) and $str !~ /^\xfe\xff/) {
|
9399
9530
|
# this is a Macintosh language code
|
9400
9531
|
# a language code of 0 is Macintosh english, so treat as default
|
@@ -9411,15 +9542,22 @@ ItemID: foreach $id (keys %$items) {
|
|
9411
9542
|
}
|
9412
9543
|
# the spec says only "Macintosh text encoding", but
|
9413
9544
|
# allow this to be configured by the user
|
9414
|
-
$
|
9545
|
+
$enc = $charsetQuickTime;
|
9415
9546
|
} else {
|
9416
9547
|
# convert language code to ASCII (ignore read-only bit)
|
9417
9548
|
$lang = UnpackLang($lang);
|
9418
9549
|
# may be either UTF-8 or UTF-16BE
|
9419
|
-
|
9550
|
+
$enc = $str=~s/^\xfe\xff// ? 'UTF16' : 'UTF8';
|
9551
|
+
}
|
9552
|
+
unless ($$tagInfo{NoDecode}) {
|
9420
9553
|
$str = $et->Decode($str, $enc);
|
9554
|
+
$str =~ s/\0+$//; # remove any trailing nulls (eg. 3gp tags)
|
9555
|
+
}
|
9556
|
+
if ($$tagInfo{IText} and $$tagInfo{IText} > 6) {
|
9557
|
+
my $n = $$tagInfo{IText} - 6;
|
9558
|
+
# add back extra bytes (eg. 'rtng' box)
|
9559
|
+
$str = substr($val, $pos-$n-2, $n) . $str;
|
9421
9560
|
}
|
9422
|
-
$str =~ s/\0+$//; # remove any trailing nulls (eg. 3gp tags)
|
9423
9561
|
$langInfo = GetLangInfoQT($et, $tagInfo, $lang) if $lang;
|
9424
9562
|
$et->FoundTag($langInfo || $tagInfo, $str);
|
9425
9563
|
$pos += $len;
|
@@ -9469,6 +9607,13 @@ ItemID: foreach $id (keys %$items) {
|
|
9469
9607
|
($size, $tag) = unpack('Na4', $buff);
|
9470
9608
|
++$index if defined $index;
|
9471
9609
|
}
|
9610
|
+
# tweak file type based on track content ("iso*" and "dash" ftyp only)
|
9611
|
+
if ($topLevel and $$et{VALUE}{FileType} and $$et{VALUE}{FileType} eq 'MP4' and
|
9612
|
+
$$et{save_ftyp} and $$et{HasHandler} and $$et{save_ftyp} =~ /^(iso|dash)/ and
|
9613
|
+
$$et{HasHandler}{soun} and not $$et{HasHandler}{vide})
|
9614
|
+
{
|
9615
|
+
$et->OverrideFileType('M4A', 'audio/mp4');
|
9616
|
+
}
|
9472
9617
|
# fill in missing defaults for alternate language tags
|
9473
9618
|
# (the first language is taken as the default)
|
9474
9619
|
if ($doDefaultLang and $$et{QTLang}) {
|