exiftool_vendored 12.17.1 → 12.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +225 -1
  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 +142 -87
  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 +30 -12
  19. data/bin/lib/Image/ExifTool/CBOR.pm +277 -0
  20. data/bin/lib/Image/ExifTool/Canon.pm +49 -18
  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 +28 -11
  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 +27 -4
  35. data/bin/lib/Image/ExifTool/Jpeg2000.pm +393 -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 +1 -1
  44. data/bin/lib/Image/ExifTool/Microsoft.pm +298 -82
  45. data/bin/lib/Image/ExifTool/Nikon.pm +19 -8
  46. data/bin/lib/Image/ExifTool/NikonSettings.pm +28 -11
  47. data/bin/lib/Image/ExifTool/Olympus.pm +6 -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 +247 -88
  56. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +283 -141
  57. data/bin/lib/Image/ExifTool/README +3 -0
  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 +237 -78
  62. data/bin/lib/Image/ExifTool/TagInfoXML.pm +1 -0
  63. data/bin/lib/Image/ExifTool/TagLookup.pm +4125 -4028
  64. data/bin/lib/Image/ExifTool/TagNames.pod +644 -286
  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 +39 -14
  75. data/bin/lib/Image/ExifTool/XMP2.pl +2 -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 +223 -72
  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.57';
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
- '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!)
@@ -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 %langText = (
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 %langText tags are Avoid => 1)
1549
- cprt => { Name => 'Copyright', %langText, Groups => { 2 => 'Author' } },
1550
- auth => { Name => 'Author', %langText, Groups => { 2 => 'Author' } },
1551
- titl => { Name => 'Title', %langText },
1552
- dscp => { Name => 'Description',%langText },
1553
- perf => { Name => 'Performer', %langText },
1554
- gnre => { Name => 'Genre', %langText },
1555
- albm => { Name => 'Album', %langText },
1556
- coll => { Name => 'CollectionName', %langText }, #17
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
- RawConv => q{
1561
- return '<err>' unless length $val >= 14;
1562
- my $str = 'Entity=' . substr($val,4,4) . ' Criteria=' . substr($val,8,4);
1563
- $str =~ tr/\0-\x1f\x7f-\xff//d; # remove unprintable characters
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
- RawConv => q{
1575
- return '<err>' unless length $val >= 12;
1576
- my $str = 'Entity=' . substr($val,4,4) . ' Index=' . Get16u(\$val,8);
1577
- $str =~ tr/\0-\x1f\x7f-\xff//d; # remove unprintable characters
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 .= " Body=$1";
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 .= " Notes=$1";
1683
+ $str .= ' Notes=' . $self->Decode($1, 'UTF8');
1645
1684
  }
1646
- 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";
1647
1703
  },
1648
1704
  },
1649
1705
  yrrc => {
1650
1706
  Name => 'Year',
1707
+ Writable => 'undef',
1651
1708
  Groups => { 2 => 'Time' },
1652
- 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)',
1653
1713
  },
1654
1714
  urat => { #17
1655
1715
  Name => 'UserRating',
1656
- RawConv => q{
1716
+ Writable => 'undef',
1717
+ Notes => 'used in 3gp videos',
1718
+ Avoid => 1,
1719
+ ValueConv => q{
1657
1720
  return '<err>' unless length $val >= 8;
1658
- return Get8u(\$val, 7);
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
- SubDirectory => { TagTable => 'Image::ExifTool::Microsoft::Xtra' },
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 does not specify a
2998
- L<Handler|Image::ExifTool::TagNames/QuickTime Handler Tags>, but the
2999
- 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.
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 => 3 },
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
- # 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)
6305
6388
  #
6306
6389
  # (mdta)com.apple.quicktime.video-orientation (dtyp=66, int16s)
6307
- 'video-orientation' => { Name => 'VideoOrientation', Writable => 0 },
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
- DISCNUMBER => 'DiscNumber', #PH
6432
- TRACKNUMBER => 'TrackNumber', #PH
6433
- 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'
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 => '$$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
+ },
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::ProcessNMEA($self, { DataPt => \$val }, $tagTbl);
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
- # (I have some samples where the tag is a reversed ItemList or UserData tag ID)
8801
- my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
8802
- unless ($tagInfo) {
8803
- $tagInfo = $et->GetTagInfo($itemList, $tag);
8804
- 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;
8805
8940
  $tagInfo = $et->GetTagInfo($userData, $tag);
8806
- if (not $tagInfo and $tag =~ /^\w{3}\xa9$/) {
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
- undef %triplet;
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
- $format = QuickTimeFormat($flags, $len) unless $format;
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} == 6) {
9354
- last if $pos + 6 > $size;
9355
- $pos += 4;
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
- $str = $et->Decode($str, $charsetQuickTime);
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
- my $enc = $str=~s/^\xfe\xff// ? 'UTF16' : 'UTF8';
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}) {