exiftool_vendored 12.18.0 → 12.33.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 +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}) {