exiftool_vendored 12.22.0 → 12.34.0

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