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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +236 -4
  3. data/bin/MANIFEST +23 -0
  4. data/bin/META.json +1 -1
  5. data/bin/META.yml +1 -1
  6. data/bin/README +45 -43
  7. data/bin/arg_files/xmp2exif.args +2 -1
  8. data/bin/config_files/acdsee.config +193 -6
  9. data/bin/config_files/convert_regions.config +25 -14
  10. data/bin/config_files/cuepointlist.config +70 -0
  11. data/bin/config_files/example.config +2 -9
  12. data/bin/exiftool +152 -97
  13. data/bin/fmt_files/gpx.fmt +2 -2
  14. data/bin/fmt_files/gpx_wpt.fmt +2 -2
  15. data/bin/fmt_files/kml.fmt +1 -1
  16. data/bin/fmt_files/kml_track.fmt +1 -1
  17. data/bin/lib/Image/ExifTool/Apple.pm +3 -2
  18. data/bin/lib/Image/ExifTool/BuildTagLookup.pm +31 -13
  19. data/bin/lib/Image/ExifTool/CBOR.pm +331 -0
  20. data/bin/lib/Image/ExifTool/Canon.pm +44 -19
  21. data/bin/lib/Image/ExifTool/DJI.pm +6 -6
  22. data/bin/lib/Image/ExifTool/DPX.pm +13 -2
  23. data/bin/lib/Image/ExifTool/DjVu.pm +6 -5
  24. data/bin/lib/Image/ExifTool/Exif.pm +124 -13
  25. data/bin/lib/Image/ExifTool/FITS.pm +13 -2
  26. data/bin/lib/Image/ExifTool/FlashPix.pm +35 -10
  27. data/bin/lib/Image/ExifTool/FujiFilm.pm +19 -8
  28. data/bin/lib/Image/ExifTool/GPS.pm +22 -11
  29. data/bin/lib/Image/ExifTool/Geotag.pm +13 -2
  30. data/bin/lib/Image/ExifTool/GoPro.pm +16 -1
  31. data/bin/lib/Image/ExifTool/ICC_Profile.pm +2 -2
  32. data/bin/lib/Image/ExifTool/ID3.pm +15 -3
  33. data/bin/lib/Image/ExifTool/JPEG.pm +74 -4
  34. data/bin/lib/Image/ExifTool/JSON.pm +30 -5
  35. data/bin/lib/Image/ExifTool/Jpeg2000.pm +395 -16
  36. data/bin/lib/Image/ExifTool/LIF.pm +153 -0
  37. data/bin/lib/Image/ExifTool/Lang/nl.pm +60 -59
  38. data/bin/lib/Image/ExifTool/M2TS.pm +137 -5
  39. data/bin/lib/Image/ExifTool/MIE.pm +4 -3
  40. data/bin/lib/Image/ExifTool/MRC.pm +341 -0
  41. data/bin/lib/Image/ExifTool/MWG.pm +3 -3
  42. data/bin/lib/Image/ExifTool/MXF.pm +1 -1
  43. data/bin/lib/Image/ExifTool/MacOS.pm +3 -3
  44. data/bin/lib/Image/ExifTool/Microsoft.pm +298 -82
  45. data/bin/lib/Image/ExifTool/Nikon.pm +18 -5
  46. data/bin/lib/Image/ExifTool/NikonSettings.pm +19 -2
  47. data/bin/lib/Image/ExifTool/Olympus.pm +10 -3
  48. data/bin/lib/Image/ExifTool/Other.pm +93 -0
  49. data/bin/lib/Image/ExifTool/PDF.pm +9 -12
  50. data/bin/lib/Image/ExifTool/PNG.pm +8 -7
  51. data/bin/lib/Image/ExifTool/Panasonic.pm +28 -3
  52. data/bin/lib/Image/ExifTool/Pentax.pm +28 -5
  53. data/bin/lib/Image/ExifTool/PhaseOne.pm +4 -3
  54. data/bin/lib/Image/ExifTool/Photoshop.pm +6 -0
  55. data/bin/lib/Image/ExifTool/QuickTime.pm +234 -75
  56. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +283 -141
  57. data/bin/lib/Image/ExifTool/README +5 -2
  58. data/bin/lib/Image/ExifTool/RIFF.pm +89 -12
  59. data/bin/lib/Image/ExifTool/Samsung.pm +48 -10
  60. data/bin/lib/Image/ExifTool/Shortcuts.pm +9 -0
  61. data/bin/lib/Image/ExifTool/Sony.pm +230 -69
  62. data/bin/lib/Image/ExifTool/TagInfoXML.pm +1 -0
  63. data/bin/lib/Image/ExifTool/TagLookup.pm +4145 -4029
  64. data/bin/lib/Image/ExifTool/TagNames.pod +671 -287
  65. data/bin/lib/Image/ExifTool/Torrent.pm +18 -11
  66. data/bin/lib/Image/ExifTool/WriteExif.pl +1 -1
  67. data/bin/lib/Image/ExifTool/WriteIPTC.pl +1 -1
  68. data/bin/lib/Image/ExifTool/WritePDF.pl +1 -0
  69. data/bin/lib/Image/ExifTool/WritePNG.pl +2 -0
  70. data/bin/lib/Image/ExifTool/WritePostScript.pl +1 -0
  71. data/bin/lib/Image/ExifTool/WriteQuickTime.pl +55 -21
  72. data/bin/lib/Image/ExifTool/WriteXMP.pl +7 -3
  73. data/bin/lib/Image/ExifTool/Writer.pl +47 -10
  74. data/bin/lib/Image/ExifTool/XMP.pm +45 -15
  75. data/bin/lib/Image/ExifTool/XMP2.pl +3 -1
  76. data/bin/lib/Image/ExifTool/XMPStruct.pl +3 -1
  77. data/bin/lib/Image/ExifTool/ZISRAW.pm +121 -2
  78. data/bin/lib/Image/ExifTool.pm +233 -81
  79. data/bin/lib/Image/ExifTool.pod +114 -93
  80. data/bin/perl-Image-ExifTool.spec +43 -42
  81. data/lib/exiftool_vendored/version.rb +1 -1
  82. 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.58';
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
- 'isom' => 'MP4 Base Media v1 [IS0 14496-12:2003]', # video/mp4
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 => 'GetUnixTime($val, $self->Options("QuickTimeUTC")) + (66 * 365 + 17) * 24 * 3600',
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
- RawConv => q{
1565
- return '<err>' unless length $val >= 14;
1566
- my $str = 'Entity=' . substr($val,4,4) . ' Criteria=' . substr($val,8,4);
1567
- $str =~ tr/\0-\x1f\x7f-\xff//d; # remove unprintable characters
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
- RawConv => q{
1579
- return '<err>' unless length $val >= 12;
1580
- my $str = 'Entity=' . substr($val,4,4) . ' Index=' . Get16u(\$val,8);
1581
- $str =~ tr/\0-\x1f\x7f-\xff//d; # remove unprintable characters
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 .= " Body=$1";
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 .= " Notes=$1";
1683
+ $str .= ' Notes=' . $self->Decode($1, 'UTF8');
1651
1684
  }
1652
- return $lang . $str;
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
- RawConv => 'length($val) >= 6 ? Get16u(\$val,4) : "<err>"',
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
- RawConv => q{
1716
+ Writable => 'undef',
1717
+ Notes => 'used in 3gp videos',
1718
+ Avoid => 1,
1719
+ ValueConv => q{
1663
1720
  return '<err>' unless length $val >= 8;
1664
- return Get8u(\$val, 7);
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
- SubDirectory => { TagTable => 'Image::ExifTool::Microsoft::Xtra' },
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 does not specify a
3004
- L<Handler|Image::ExifTool::TagNames/QuickTime Handler Tags>, but the
3005
- API L<QuickTimeHandler|../ExifTool.html#QuickTimeHandler> option may be used to include an 'mdir' Handler box.
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 => 3 },
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
- # via SaveMetaKeys(). NOTE: these tags are not writable!
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' => { Name => 'VideoOrientation', Writable => 0 },
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
- DISCNUMBER => 'DiscNumber', #PH
6438
- TRACKNUMBER => 'TrackNumber', #PH
6439
- popularimeter => 'Popularimeter', #PH
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 => '$$self{HandlerType} = $val unless $val eq "alis" or $val eq "url "; $val',
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::ProcessNMEA($self, { DataPt => \$val }, $tagTbl);
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
- # (I have some samples where the tag is a reversed ItemList or UserData tag ID)
8807
- my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
8808
- unless ($tagInfo) {
8809
- $tagInfo = $et->GetTagInfo($itemList, $tag);
8810
- unless ($tagInfo) {
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
- if (not $tagInfo and $tag =~ /^\w{3}\xa9$/) {
8813
- $tag = pack('N', unpack('V', $tag));
8814
- $tagInfo = $et->GetTagInfo($itemList, $tag);
8815
- $tagInfo or $tagInfo = $et->GetTagInfo($userData, $tag);
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
- undef %triplet;
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
- $format = QuickTimeFormat($flags, $len) unless $format;
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} == 6) {
9360
- last if $pos + 6 > $size;
9361
- $pos += 4;
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
- $str = $et->Decode($str, $charsetQuickTime);
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
- my $enc = $str=~s/^\xfe\xff// ? 'UTF16' : 'UTF8';
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}) {