exiftool_vendored 12.42.0 → 12.52.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +226 -6
  3. data/bin/MANIFEST +14 -0
  4. data/bin/META.json +1 -1
  5. data/bin/META.yml +1 -1
  6. data/bin/README +45 -44
  7. data/bin/config_files/acdsee.config +2 -1
  8. data/bin/config_files/frameCount.config +56 -0
  9. data/bin/config_files/tiff_version.config +1 -1
  10. data/bin/exiftool +116 -97
  11. data/bin/fmt_files/gpx.fmt +3 -0
  12. data/bin/fmt_files/gpx_wpt.fmt +3 -0
  13. data/bin/lib/Image/ExifTool/Apple.pm +16 -3
  14. data/bin/lib/Image/ExifTool/BuildTagLookup.pm +23 -12
  15. data/bin/lib/Image/ExifTool/Canon.pm +66 -37
  16. data/bin/lib/Image/ExifTool/CanonRaw.pm +8 -1
  17. data/bin/lib/Image/ExifTool/CanonVRD.pm +7 -8
  18. data/bin/lib/Image/ExifTool/Casio.pm +3 -3
  19. data/bin/lib/Image/ExifTool/DJI.pm +2 -1
  20. data/bin/lib/Image/ExifTool/DarwinCore.pm +13 -1
  21. data/bin/lib/Image/ExifTool/EXE.pm +9 -1
  22. data/bin/lib/Image/ExifTool/Exif.pm +17 -12
  23. data/bin/lib/Image/ExifTool/FLAC.pm +17 -3
  24. data/bin/lib/Image/ExifTool/FLIR.pm +9 -7
  25. data/bin/lib/Image/ExifTool/FlashPix.pm +26 -3
  26. data/bin/lib/Image/ExifTool/FujiFilm.pm +51 -4
  27. data/bin/lib/Image/ExifTool/GPS.pm +31 -5
  28. data/bin/lib/Image/ExifTool/Geotag.pm +36 -8
  29. data/bin/lib/Image/ExifTool/ICC_Profile.pm +3 -2
  30. data/bin/lib/Image/ExifTool/ICO.pm +143 -0
  31. data/bin/lib/Image/ExifTool/ID3.pm +6 -6
  32. data/bin/lib/Image/ExifTool/IPTC.pm +5 -1
  33. data/bin/lib/Image/ExifTool/JPEG.pm +1 -0
  34. data/bin/lib/Image/ExifTool/Jpeg2000.pm +24 -3
  35. data/bin/lib/Image/ExifTool/LNK.pm +5 -2
  36. data/bin/lib/Image/ExifTool/Lang/de.pm +1 -1
  37. data/bin/lib/Image/ExifTool/Lang/fr.pm +6015 -759
  38. data/bin/lib/Image/ExifTool/Lang/sk.pm +1927 -0
  39. data/bin/lib/Image/ExifTool/M2TS.pm +98 -8
  40. data/bin/lib/Image/ExifTool/MIE.pm +9 -3
  41. data/bin/lib/Image/ExifTool/MISB.pm +494 -0
  42. data/bin/lib/Image/ExifTool/MakerNotes.pm +3 -1
  43. data/bin/lib/Image/ExifTool/Matroska.pm +272 -48
  44. data/bin/lib/Image/ExifTool/Motorola.pm +8 -2
  45. data/bin/lib/Image/ExifTool/Nikon.pm +746 -382
  46. data/bin/lib/Image/ExifTool/NikonCustom.pm +139 -106
  47. data/bin/lib/Image/ExifTool/NikonSettings.pm +5 -3
  48. data/bin/lib/Image/ExifTool/Olympus.pm +6 -4
  49. data/bin/lib/Image/ExifTool/PNG.pm +8 -1
  50. data/bin/lib/Image/ExifTool/Panasonic.pm +21 -4
  51. data/bin/lib/Image/ExifTool/PanasonicRaw.pm +25 -5
  52. data/bin/lib/Image/ExifTool/Parrot.pm +96 -2
  53. data/bin/lib/Image/ExifTool/Pentax.pm +7 -2
  54. data/bin/lib/Image/ExifTool/Photoshop.pm +29 -3
  55. data/bin/lib/Image/ExifTool/QuickTime.pm +166 -13
  56. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +161 -22
  57. data/bin/lib/Image/ExifTool/README +15 -4
  58. data/bin/lib/Image/ExifTool/RIFF.pm +106 -9
  59. data/bin/lib/Image/ExifTool/Samsung.pm +2 -2
  60. data/bin/lib/Image/ExifTool/Sigma.pm +27 -1
  61. data/bin/lib/Image/ExifTool/SigmaRaw.pm +37 -13
  62. data/bin/lib/Image/ExifTool/Sony.pm +75 -47
  63. data/bin/lib/Image/ExifTool/TagInfoXML.pm +13 -6
  64. data/bin/lib/Image/ExifTool/TagLookup.pm +4791 -4519
  65. data/bin/lib/Image/ExifTool/TagNames.pod +2056 -1446
  66. data/bin/lib/Image/ExifTool/Text.pm +3 -4
  67. data/bin/lib/Image/ExifTool/Torrent.pm +2 -3
  68. data/bin/lib/Image/ExifTool/Validate.pm +3 -3
  69. data/bin/lib/Image/ExifTool/WriteCanonRaw.pl +7 -0
  70. data/bin/lib/Image/ExifTool/WriteExif.pl +100 -23
  71. data/bin/lib/Image/ExifTool/WriteIPTC.pl +2 -6
  72. data/bin/lib/Image/ExifTool/WritePhotoshop.pl +5 -5
  73. data/bin/lib/Image/ExifTool/WriteQuickTime.pl +12 -7
  74. data/bin/lib/Image/ExifTool/WriteRIFF.pl +359 -0
  75. data/bin/lib/Image/ExifTool/WriteXMP.pl +15 -1
  76. data/bin/lib/Image/ExifTool/Writer.pl +46 -18
  77. data/bin/lib/Image/ExifTool/XMP.pm +78 -59
  78. data/bin/lib/Image/ExifTool/XMP2.pl +19 -4
  79. data/bin/lib/Image/ExifTool/ZIP.pm +19 -7
  80. data/bin/lib/Image/ExifTool.pm +146 -38
  81. data/bin/lib/Image/ExifTool.pod +83 -69
  82. data/bin/perl-Image-ExifTool.spec +43 -43
  83. data/lib/exiftool_vendored/version.rb +1 -1
  84. metadata +10 -4
@@ -26,6 +26,9 @@ sub ProcessFreeGPS($$$);
26
26
  sub ProcessFreeGPS2($$$);
27
27
  sub Process360Fly($$$);
28
28
  sub ProcessFMAS($$$);
29
+ sub ProcessCAMM($$$);
30
+
31
+ my $debug; # set to 1 for extra debugging messages
29
32
 
30
33
  # QuickTime data types that have ExifTool equivalents
31
34
  # (ref https://developer.apple.com/library/content/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW35)
@@ -80,7 +83,7 @@ my %processByMetaFormat = (
80
83
 
81
84
  # data lengths for each INSV record type
82
85
  my %insvDataLen = (
83
- 0x300 => 56, # accelerometer
86
+ 0x300 => 0, # accelerometer (could be either 20 or 56 bytes)
84
87
  0x400 => 16, # exposure (ref 6)
85
88
  0x600 => 8, # timestamps (ref 6)
86
89
  0x700 => 53, # GPS
@@ -99,7 +102,7 @@ my %insvLimit = (
99
102
  The tags below are extracted from timed metadata in QuickTime and other
100
103
  formats of video files when the ExtractEmbedded option is used. Although
101
104
  most of these tags are combined into the single table below, ExifTool
102
- currently reads 59 different formats of timed GPS metadata from video files.
105
+ currently reads 62 different formats of timed GPS metadata from video files.
103
106
  },
104
107
  VARS => { NO_ID => 1 },
105
108
  GPSLatitude => { PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', RawConv => '$$self{FoundGPSLatitude} = 1; $val' },
@@ -234,7 +237,7 @@ my %insvLimit = (
234
237
  camm => [{
235
238
  Name => 'camm0',
236
239
  # (according to the spec. the first 2 bytes are reserved and should be zero,
237
- # but I have a sample where these bytes are non-zero, so allow anything here)
240
+ # but I have samples where these bytes are non-zero, so allow anything here)
238
241
  Condition => '$$valPt =~ /^..\0\0/s',
239
242
  SubDirectory => {
240
243
  TagTable => 'Image::ExifTool::QuickTime::camm0',
@@ -316,7 +319,7 @@ my %insvLimit = (
316
319
 
317
320
  # tags found in 'camm' type 0 timed metadata (ref 4)
318
321
  %Image::ExifTool::QuickTime::camm0 = (
319
- PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
322
+ PROCESS_PROC => \&ProcessCAMM,
320
323
  GROUPS => { 2 => 'Location' },
321
324
  FIRST_ENTRY => 0,
322
325
  NOTES => q{
@@ -334,7 +337,7 @@ my %insvLimit = (
334
337
 
335
338
  # tags found in 'camm' type 1 timed metadata (ref 4)
336
339
  %Image::ExifTool::QuickTime::camm1 = (
337
- PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
340
+ PROCESS_PROC => \&ProcessCAMM,
338
341
  GROUPS => { 2 => 'Camera' },
339
342
  FIRST_ENTRY => 0,
340
343
  4 => {
@@ -353,7 +356,7 @@ my %insvLimit = (
353
356
 
354
357
  # tags found in 'camm' type 2 timed metadata (ref PH, Insta360Pro)
355
358
  %Image::ExifTool::QuickTime::camm2 = (
356
- PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
359
+ PROCESS_PROC => \&ProcessCAMM,
357
360
  GROUPS => { 2 => 'Location' },
358
361
  FIRST_ENTRY => 0,
359
362
  4 => {
@@ -365,7 +368,7 @@ my %insvLimit = (
365
368
 
366
369
  # tags found in 'camm' type 3 timed metadata (ref PH, Insta360Pro)
367
370
  %Image::ExifTool::QuickTime::camm3 = (
368
- PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
371
+ PROCESS_PROC => \&ProcessCAMM,
369
372
  GROUPS => { 2 => 'Location' },
370
373
  FIRST_ENTRY => 0,
371
374
  4 => {
@@ -377,7 +380,7 @@ my %insvLimit = (
377
380
 
378
381
  # tags found in 'camm' type 4 timed metadata (ref 4)
379
382
  %Image::ExifTool::QuickTime::camm4 = (
380
- PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
383
+ PROCESS_PROC => \&ProcessCAMM,
381
384
  GROUPS => { 2 => 'Location' },
382
385
  FIRST_ENTRY => 0,
383
386
  4 => {
@@ -389,7 +392,7 @@ my %insvLimit = (
389
392
 
390
393
  # tags found in 'camm' type 5 timed metadata (ref 4)
391
394
  %Image::ExifTool::QuickTime::camm5 = (
392
- PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
395
+ PROCESS_PROC => \&ProcessCAMM,
393
396
  GROUPS => { 2 => 'Location' },
394
397
  FIRST_ENTRY => 0,
395
398
  4 => {
@@ -414,7 +417,7 @@ my %insvLimit = (
414
417
 
415
418
  # tags found in 'camm' type 6 timed metadata (ref PH/4, Insta360)
416
419
  %Image::ExifTool::QuickTime::camm6 = (
417
- PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
420
+ PROCESS_PROC => \&ProcessCAMM,
418
421
  GROUPS => { 2 => 'Location' },
419
422
  FIRST_ENTRY => 0,
420
423
  0x04 => {
@@ -480,7 +483,7 @@ my %insvLimit = (
480
483
 
481
484
  # tags found in 'camm' type 7 timed metadata (ref 4)
482
485
  %Image::ExifTool::QuickTime::camm7 = (
483
- PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
486
+ PROCESS_PROC => \&ProcessCAMM,
484
487
  GROUPS => { 2 => 'Location' },
485
488
  FIRST_ENTRY => 0,
486
489
  4 => {
@@ -896,10 +899,15 @@ sub Process_text($$$)
896
899
  my $time = "$1:$2:$3";
897
900
  if ($$et{LastTime}) {
898
901
  if ($$et{LastTime} eq $time) {
902
+ # combine with the previous NMEA sentence
899
903
  $$et{DOC_NUM} = $$et{LastDoc};
900
904
  } elsif (%tags) {
905
+ # handle existing tags and start a new document
906
+ # (see https://exiftool.org/forum/index.php?msg=75422)
901
907
  HandleTextTags($et, $tagTbl, \%tags);
902
- $$et{DOC_NUM} = ++$$et{DOC_COUNT};
908
+ undef %tags;
909
+ # increment document number and update document count if necessary
910
+ $$et{DOC_COUNT} < ++$$et{DOC_NUM} and $$et{DOC_COUNT} = $$et{DOC_NUM};
903
911
  }
904
912
  }
905
913
  $$et{LastTime} = $time;
@@ -918,7 +926,8 @@ sub Process_text($$$)
918
926
  $$et{DOC_NUM} = $$et{LastDoc};
919
927
  } elsif (%tags) {
920
928
  HandleTextTags($et, $tagTbl, \%tags);
921
- $$et{DOC_NUM} = ++$$et{DOC_COUNT};
929
+ undef %tags;
930
+ $$et{DOC_COUNT} < ++$$et{DOC_NUM} and $$et{DOC_COUNT} = $$et{DOC_NUM};
922
931
  }
923
932
  }
924
933
  $$et{LastTime} = $time;
@@ -1416,6 +1425,7 @@ sub ProcessFreeGPS($$$)
1416
1425
  } elsif ($buf2 =~ /^.{173}([-+]\d{3})([-+]\d{3})([-+]\d{3})/s) { # (Azdome)
1417
1426
  @acc = ($1/100, $2/100, $3/100);
1418
1427
  }
1428
+ $debug and $et->FoundTag(GPSType => '1A');
1419
1429
 
1420
1430
  } elsif ($$dataPt =~ /^.{52}(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/s) {
1421
1431
 
@@ -1444,6 +1454,7 @@ sub ProcessFreeGPS($$$)
1444
1454
  # change to signed integer and divide by 256
1445
1455
  map { $_ = $_ - 4294967296 if $_ >= 0x80000000; $_ /= 256 } @acc;
1446
1456
  }
1457
+ $debug and $et->FoundTag(GPSType => '1B');
1447
1458
 
1448
1459
  } elsif ($$dataPt =~ /^.{37}\0\0\0A([NS])([EW])/s) {
1449
1460
 
@@ -1454,13 +1465,31 @@ sub ProcessFreeGPS($$$)
1454
1465
  # 0030: f1 47 40 46 66 66 d2 41 85 eb 83 41 00 00 00 00 [.G@Fff.A...A....]
1455
1466
  ($latRef, $lonRef) = ($1, $2);
1456
1467
  ($hr,$min,$sec,$yr,$mon,$day) = unpack('x16V6', $$dataPt);
1457
- $yr += 2000;
1468
+ if ($yr < 2000) {
1469
+ $yr += 2000;
1470
+ } else {
1471
+ # Kenwood dashcam sometimes stores absolute year and local time
1472
+ # (but sometimes year since 2000 and UTC time in same video!)
1473
+ require Time::Local;
1474
+ my $time = Image::ExifTool::TimeLocal($sec,$min,$hr,$day,$mon-1,$yr-1900);
1475
+ ($sec,$min,$hr,$day,$mon,$yr) = gmtime($time);
1476
+ $yr += 1900;
1477
+ ++$mon;
1478
+ $et->WarnOnce('Converting GPSDateTime to UTC based on local time zone',1);
1479
+ }
1458
1480
  SetByteOrder('II');
1459
1481
  $lat = GetFloat($dataPt, 0x2c);
1460
1482
  $lon = GetFloat($dataPt, 0x30);
1461
1483
  $spd = GetFloat($dataPt, 0x34) * $knotsToKph; # (convert knots to km/h)
1462
1484
  $trk = GetFloat($dataPt, 0x38);
1485
+ # (may be all zeros or int16u counting from 1 to 6 if not valid)
1486
+ my $tmp = substr($$dataPt, 60, 12);
1487
+ if ($tmp ne "\0\0\0\0\0\0\0\0\0\0\0\0" and $tmp ne "\x01\0\x02\0\x03\0\x04\0\x05\0\x06\0") {
1488
+ @acc = unpack('V3', $tmp);
1489
+ map { $_ = $_ - 4294967296 if $_ >= 0x80000000; $_ /= 256 } @acc;
1490
+ }
1463
1491
  SetByteOrder('MM');
1492
+ $debug and $et->FoundTag(GPSType => '1C');
1464
1493
 
1465
1494
  } elsif ($$dataPt =~ /^.{21}\0\0\0A([NS])([EW])/s) {
1466
1495
 
@@ -1489,6 +1518,7 @@ sub ProcessFreeGPS($$$)
1489
1518
  $acc[1] = GetFloat($dataPt, 0x30);
1490
1519
  $acc[2] = GetFloat($dataPt, 0x34);
1491
1520
  SetByteOrder('MM');
1521
+ $debug and $et->FoundTag(GPSType => '1D');
1492
1522
 
1493
1523
  } elsif ($$dataPt =~ /^.{60}A\0{3}.{4}([NS])\0{3}.{4}([EW])\0{3}/s) {
1494
1524
 
@@ -1509,6 +1539,7 @@ sub ProcessFreeGPS($$$)
1509
1539
  $trk = GetFloat($dataPt, 0x54) + 180; # (why is this off by 180?)
1510
1540
  $trk -= 360 if $trk >= 360;
1511
1541
  SetByteOrder('MM');
1542
+ $debug and $et->FoundTag(GPSType => '1E');
1512
1543
 
1513
1544
  } elsif ($$dataPt =~ /^.{60}4W`b]S</s and length($$dataPt) >= 140) {
1514
1545
 
@@ -1526,8 +1557,9 @@ sub ProcessFreeGPS($$$)
1526
1557
  $yr += ($yr >= 70 ? 1900 : 2000);
1527
1558
  $spd = $9 * $knotsToKph if length $9;
1528
1559
  $trk = $10 if length $10;
1560
+ $debug and $et->FoundTag(GPSType => '1F');
1529
1561
 
1530
- } elsif ($$dataPt =~ /^.{64}[\x01-\x0c]\0{3}[\x01-\x1f]\0{3}A[NS][EW]\0/s) {
1562
+ } elsif ($$dataPt =~ /^.{64}[\x01-\x0c]\0{3}[\x01-\x1f]\0{3}A[NS][EW]\0{5}/s) {
1531
1563
 
1532
1564
  # Akaso V1 dascham
1533
1565
  # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 78 00 00 00 [....freeGPS x...]
@@ -1569,6 +1601,7 @@ sub ProcessFreeGPS($$$)
1569
1601
 
1570
1602
  SetByteOrder('MM');
1571
1603
  #my $serialNum = substr($$dataPt, 0x68, 20);
1604
+ $debug and $et->FoundTag(GPSType => '1G');
1572
1605
 
1573
1606
  } elsif ($$dataPt =~ /^.{12}\xac\0\0\0.{44}(.{72})/s) {
1574
1607
 
@@ -1591,6 +1624,7 @@ sub ProcessFreeGPS($$$)
1591
1624
  # bytes 7-12 are the timestamp in ASCII HHMMSS after xor-ing with 0x70
1592
1625
  substr($time,7,6) = pack 'C*', map { $_ ^= 0x70 } unpack 'C*', substr($time,7,6);
1593
1626
  # (other values are currently unknown)
1627
+ $debug and $et->FoundTag(GPSType => '1H');
1594
1628
 
1595
1629
  } elsif ($$dataPt =~ /^.{64}A([NS])([EW])\0/s) {
1596
1630
 
@@ -1616,6 +1650,7 @@ sub ProcessFreeGPS($$$)
1616
1650
  $trk = GetFloat($dataPt, 0x68);
1617
1651
  $alt = GetFloat($dataPt, 0x6c);
1618
1652
  SetByteOrder('MM');
1653
+ $debug and $et->FoundTag(GPSType => '1I');
1619
1654
 
1620
1655
  } else {
1621
1656
 
@@ -1624,6 +1659,9 @@ sub ProcessFreeGPS($$$)
1624
1659
  # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 4c 00 00 00 [....freeGPS L...]
1625
1660
  # 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
1626
1661
  # 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
1662
+ # 0030: 10 00 00 00 2d 00 00 00 14 00 00 00 11 00 00 00 [....-...........]
1663
+ # 0040: 0c 00 00 00 1f 00 00 00 41 4e 45 00 5d 9a a9 45 [........ANE.]..E]
1664
+ # 0050: ab 1e e5 44 ec 51 f0 40 b8 5e a5 43 00 00 00 00 [...D.Q.@.^.C....]
1627
1665
  # (records are same structure as Type 3 Novatek GPS in ProcessFreeGPS2() below)
1628
1666
  ($hr,$min,$sec,$yr,$mon,$day,$stat,$latRef,$lonRef,$lat,$lon,$spd,$trk) =
1629
1667
  unpack('x48V6a1a1a1x1V4', $$dataPt);
@@ -1649,6 +1687,7 @@ sub ProcessFreeGPS($$$)
1649
1687
  $yr += 2000 if $yr < 2000;
1650
1688
  $spd *= $knotsToKph; # convert speed to km/h
1651
1689
  # ($trk is not confirmed; may be GPSImageDirection, ref PH)
1690
+ $debug and $et->FoundTag(GPSType => '1J');
1652
1691
  }
1653
1692
  #
1654
1693
  # save tag values extracted by above code
@@ -1802,6 +1841,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
1802
1841
  }
1803
1842
  # save position of most recent record (needed when parsing the next freeGPS block)
1804
1843
  $$et{FreeGPS2}{RecentRecPos} = $lastRecPos;
1844
+ $debug and $et->FoundTag(GPSType => '2A');
1805
1845
  return 1;
1806
1846
 
1807
1847
  } elsif ($$dataPt =~ /^.{60}A\0.{10}([NS])\0.{14}([EW])\0/s) {
@@ -1833,6 +1873,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
1833
1873
  $lon = GetDouble($dataPt, 0x50);
1834
1874
  $spd = GetDouble($dataPt, 0x60) * $knotsToKph;
1835
1875
  $trk = GetDouble($dataPt, 0x68);
1876
+ $debug and $et->FoundTag(GPSType => '2B');
1836
1877
 
1837
1878
  } elsif ($$dataPt =~ /^.{72}A([NS])([EW])/s) {
1838
1879
 
@@ -1869,6 +1910,8 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
1869
1910
  $lon = abs Get32s($dataPt, 0x50) / 1e7;
1870
1911
  $spd = Get32s($dataPt, 0x54) / 100 * $mpsToKph;
1871
1912
  $alt = GetFloat($dataPt, 0x58) / 1000; # (NC)
1913
+ $debug and $et->FoundTag(GPSType => '2C');
1914
+
1872
1915
  } else {
1873
1916
  # Type 3 (ref 2)
1874
1917
  # (no sample with this format)
@@ -1876,6 +1919,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
1876
1919
  $lon = GetFloat($dataPt, 0x50);
1877
1920
  $spd = GetFloat($dataPt, 0x54) * $knotsToKph;
1878
1921
  $trk = GetFloat($dataPt, 0x58);
1922
+ $debug and $et->FoundTag(GPSType => '2D');
1879
1923
  }
1880
1924
 
1881
1925
  } elsif ($$dataPt =~ /^.{60}A\0.{6}([NS])\0.{6}([EW])\0/s and $dirLen >= 112) {
@@ -1896,6 +1940,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
1896
1940
  $lon = GetFloat($dataPt, 0x48);
1897
1941
  $spd = GetFloat($dataPt, 0x50);
1898
1942
  $trk = GetFloat($dataPt, 0x54);
1943
+ $debug and $et->FoundTag(GPSType => '2E');
1899
1944
 
1900
1945
  } elsif ($$dataPt =~ /^.{16}A([NS])([EW])\0/s) {
1901
1946
 
@@ -1916,6 +1961,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
1916
1961
  $et->HandleTag($tagTbl, GPSTrack => $trk);
1917
1962
  $et->HandleTag($tagTbl, Accelerometer => "@acc");
1918
1963
  }
1964
+ $debug and $et->FoundTag(GPSType => '2F');
1919
1965
  return 1;
1920
1966
 
1921
1967
  } else {
@@ -1962,6 +2008,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
1962
2008
  $et->HandleTag($tagTbl, GPSTrack => $trk);
1963
2009
  last if $pos += 0x20 > length($$dataPt) - 0x1e;
1964
2010
  }
2011
+ $debug and $et->FoundTag(GPSType => '2G');
1965
2012
  return $$et{DOC_NUM} ? 1 : 0; # return 0 if nothing extracted
1966
2013
  }
1967
2014
  #
@@ -2530,7 +2577,7 @@ sub ProcessTTAD($$$)
2530
2577
  # (I think "5" may be the number of satellites. seen: 5,6,7 - PH)
2531
2578
  FoundSomething($et, $tagTbl, $sampleTime / 1000);
2532
2579
  my $t = GetDouble($dataPt, $pos);
2533
- $et->HandleTag($tagTbl, GPSDateTime => Image::ExifTool::ConvertUnixTime($t,undef,3).'Z');
2580
+ $et->HandleTag($tagTbl, GPSDateTime => Image::ExifTool::ConvertUnixTime($t,undef,3) . 'Z');
2534
2581
  $et->HandleTag($tagTbl, GPSLatitude => GetDouble($dataPt, $pos+0x1c));
2535
2582
  $et->HandleTag($tagTbl, GPSLongitude => GetDouble($dataPt, $pos+0x24));
2536
2583
  $et->HandleTag($tagTbl, GPSAltitude => GetDouble($dataPt, $pos+0x14));
@@ -2621,8 +2668,33 @@ sub ProcessInsta360($;$)
2621
2668
  if ($verbose) {
2622
2669
  $et->VPrint(0, sprintf("Insta360 Record 0x%x (offset 0x%x, %d bytes):\n", $id, $fileEnd + $epos, $len));
2623
2670
  }
2671
+ # there are 2 types of record 0x300:
2672
+ # 1. 56 byte records
2673
+ # 0000: 4a f7 02 00 00 00 00 00 00 00 00 00 00 1e e7 3f [J..............?]
2674
+ # 0010: 00 00 00 00 00 b2 ef bf 00 00 00 00 00 70 c1 bf [.............p..]
2675
+ # 0020: 00 00 00 e0 91 5c 8c bf 00 00 00 20 8f ff 87 bf [.....\..... ....]
2676
+ # 0030: 00 00 00 00 88 7f c9 bf
2677
+ # 2. 20 byte records
2678
+ # 0000: c1 d8 d9 0b 00 00 00 00 f5 83 14 80 df 7f fe 7f [................]
2679
+ # 0010: fe 7f 01 80
2680
+ if ($id == 0x300) {
2681
+ if ($len % 20 and not $len % 56) {
2682
+ $dlen = 56;
2683
+ } elsif ($len % 56 and not $len % 20) {
2684
+ $dlen = 20;
2685
+ } else {
2686
+ if ($raf->Read($buff, 20) == 20) {
2687
+ if (substr($buff, 16, 3) eq "\0\0\0") {
2688
+ $dlen = 56;
2689
+ } else {
2690
+ $dlen = 20;
2691
+ }
2692
+ }
2693
+ $raf->Seek($epos, 2) or last;
2694
+ }
2695
+ }
2624
2696
  # limit the number of records we read if necessary
2625
- if ($insvLimit{$id} and $len > $insvLimit{$id}[1] * $dlen and
2697
+ if ($dlen and $insvLimit{$id} and $len > $insvLimit{$id}[1] * $dlen and
2626
2698
  $et->Warn("Insta360 $insvLimit{$id}[0] data is huge. Processing only the first $insvLimit{$id}[1] records",2))
2627
2699
  {
2628
2700
  $len = $insvLimit{$id}[1] * $dlen;
@@ -2630,11 +2702,18 @@ sub ProcessInsta360($;$)
2630
2702
  $raf->Read($buff, $len) == $len or last;
2631
2703
  $et->VerboseDump(\$buff) if $verbose > 2;
2632
2704
  if ($dlen) {
2633
- $len % $dlen and $et->Warn(sprintf('Unexpected Insta360 record 0x%x length',$id)), last;
2634
- if ($id == 0x300) {
2705
+ if ($len % $dlen) {
2706
+ $et->Warn(sprintf('Unexpected Insta360 record 0x%x length',$id));
2707
+ } elsif ($id == 0x300) {
2635
2708
  for ($p=0; $p<$len; $p+=$dlen) {
2636
2709
  $$et{DOC_NUM} = ++$$et{DOC_COUNT};
2637
- my @a = map { GetDouble(\$buff, $p + 8 * $_) } 1..6;
2710
+ my @a;
2711
+ if ($dlen == 56) {
2712
+ @a = map { GetDouble(\$buff, $p + 8 * $_) } 1..6;
2713
+ } else {
2714
+ @a = unpack("x${p}x8v6", $buff);
2715
+ map { $_ = ($_ - 0x8000) / 1000 } @a;
2716
+ }
2638
2717
  $et->HandleTag($tagTbl, TimeCode => sprintf('%.3f', Get64u(\$buff, $p) / 1000));
2639
2718
  $et->HandleTag($tagTbl, Accelerometer => "@a[0..2]"); # (NC)
2640
2719
  $et->HandleTag($tagTbl, AngularVelocity => "@a[3..5]"); # (NC)
@@ -2699,6 +2778,66 @@ sub ProcessInsta360($;$)
2699
2778
  return 1;
2700
2779
  }
2701
2780
 
2781
+ #------------------------------------------------------------------------------
2782
+ # Process CAMM metadata (ref PH)
2783
+ # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
2784
+ # Returns: 1 on success
2785
+ sub ProcessCAMM($$$)
2786
+ {
2787
+ my ($et, $dirInfo, $tagTbl) = @_;
2788
+ my $dataPt = $$dirInfo{DataPt};
2789
+ my $pos = $$dirInfo{DirStart} || 0;
2790
+ my $end = $pos + ($$dirInfo{DirLen} || length($$dataPt) - $pos);
2791
+ # camm record size for each type, including 4-byte header
2792
+ my %size = ( 1 => 12, 2 => 16, 3 => 16, 4 => 16, 5 => 28, 6 => 60, 7 => 16 );
2793
+ my $rtnVal = 0;
2794
+ while ($pos + 4 < $end) {
2795
+ my $type = Get16u($dataPt, $pos + 2);
2796
+ my $size = $size{$type} or $et->WarnOnce("Unknown camm record type $type"), last;
2797
+ $pos + $size > $end and $et->WarnOnce("Truncated camm record $type"), last;
2798
+ my $tagTbl = GetTagTable("Image::ExifTool::QuickTime::camm$type");
2799
+ $$dirInfo{DirStart} = $pos;
2800
+ $$dirInfo{DirLen} = $size;
2801
+ $et->ProcessBinaryData($dirInfo, $tagTbl) and $rtnVal = 1;
2802
+ # not sure if this is according to specification, but I have seen multiple
2803
+ # camm records all in a single sample, so step forward to process the next one
2804
+ $pos += $size;
2805
+ }
2806
+ return $rtnVal;
2807
+ }
2808
+
2809
+ #------------------------------------------------------------------------------
2810
+ # Process Garmin GPS 'uuid' atom (ref PH)
2811
+ # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
2812
+ # Returns: 1 on success
2813
+ # Note: This format is used by the Garmin DriveAssist 51, but the DriveAssist 50
2814
+ # uses a completely different format. :(
2815
+ sub ProcessGarminGPS($$$)
2816
+ {
2817
+ my ($et, $dirInfo, $tagTbl) = @_;
2818
+ my $dataPt = $$dirInfo{DataPt};
2819
+ my $dataLen = length $$dataPt;
2820
+ my $pos = 33;
2821
+ my $epoch = (66 * 365 + 17) * 24 * 3600; # time is relative to Jan 1, 1904
2822
+ my $scl = 180 / (32768 * 65536); # scaling factor for lat/lon
2823
+ $et->VerboseDir('GarminGPS');
2824
+ while ($pos + 20 <= $dataLen) {
2825
+ $$et{DOC_NUM} = ++$$et{DOC_COUNT};
2826
+ my $time = Image::ExifTool::ConvertUnixTime(Get32u($dataPt, $pos) - $epoch) . 'Z';
2827
+ my $lat = Get32s($dataPt, $pos + 12) * $scl;
2828
+ my $lon = Get32s($dataPt, $pos + 16) * $scl;
2829
+ my $spd = Get16u($dataPt, $pos + 4); # (in mph)
2830
+ $et->HandleTag($tagTbl, 'GPSDateTime', $time);
2831
+ $et->HandleTag($tagTbl, 'GPSLatitude', $lat);
2832
+ $et->HandleTag($tagTbl, 'GPSLongitude', $lon);
2833
+ $et->HandleTag($tagTbl, 'GPSSpeed', $spd);
2834
+ $et->HandleTag($tagTbl, 'GPSSpeedRef', 'M');
2835
+ $pos += 20;
2836
+ }
2837
+ delete $$et{DOC_NUM};
2838
+ return 1;
2839
+ }
2840
+
2702
2841
  #------------------------------------------------------------------------------
2703
2842
  # Process 360Fly 'uuid' atom containing sensor data
2704
2843
  # (ref https://github.com/JamesHeinrich/getID3/blob/master/getid3/module.audio-video.quicktime.php)
@@ -2776,9 +2915,9 @@ sub ScanMediaData($)
2776
2915
  my ($pos, $buf2) = (0, '');
2777
2916
 
2778
2917
  # don't rescan for freeGPS if we already found embedded metadata
2779
- my $dataPos = $$et{VALUE}{MediaDataOffset};
2918
+ my $dataPos = $$et{MediaDataOffset};
2780
2919
  if ($dataPos and not $$et{DOC_COUNT}) {
2781
- $dataLen = $$et{VALUE}{MediaDataSize};
2920
+ $dataLen = $$et{MediaDataSize};
2782
2921
  if ($dataLen) {
2783
2922
  if ($raf->Seek($dataPos, 0)) {
2784
2923
  $$et{FreeGPS2} = { }; # initialize variable space for FreeGPS2()
@@ -395,7 +395,9 @@ numerical, and generated automatically otherwise.
395
395
  be accessible.
396
396
 
397
397
  'Hidden' - set to hide tag from the TagName documentation.
398
- Also suppresses verbose output of a BinaryData tag.
398
+ Also suppresses verbose output of a BinaryData tag. The
399
+ RawConv of a Hidden tag should return undef so the tag value
400
+ is not seen by the user.
399
401
 
400
402
  'IsComposite' - flag set for Composite tags
401
403
 
@@ -531,7 +533,8 @@ numerical, and generated automatically otherwise.
531
533
  SubIFD's where the PutFirst flag is valid.
532
534
 
533
535
  'Unknown' - this is an unknown tag (only extracted when the
534
- Unknown option is set).
536
+ Unknown option is set). This is set to 2 for Unknown tags in
537
+ binary tables (extracted when Unknown is 2).
535
538
 
536
539
  'WriteNothing' - flag indicating that nothing is actually
537
540
  written when this tag is set. It is a fake writable tag that
@@ -638,7 +641,8 @@ numerical, and generated automatically otherwise.
638
641
  expression, a code reference or a list reference. In this
639
642
  expression, $self, $val and $tag may be used as with
640
643
  ValueConv, but if ValueConv was defined then $val is the
641
- ValueConv value instead of the Raw value. The returned value
644
+ ValueConv value instead of the Raw value. Composite tags
645
+ may also use the @val, @prt and @raw lists. The returned value
642
646
  should always be defined. Note that the print conversion is
643
647
  only done if the PrintConv option is enabled (which it is by
644
648
  default), and if the result of the ValueConv is not a scalar
@@ -717,7 +721,7 @@ numerical, and generated automatically otherwise.
717
721
  condition exists, then a 'true' condition is assumed. The
718
722
  expression may use $self to access the ExifTool object. The
719
723
  first 128 bytes of the raw data value are accessible through
720
- the reference $valPt for EXIF, Jpeg2000, QuickTime and
724
+ the reference $valPt for EXIF, Jpeg2000, QuickTime, FLAC and
721
725
  BinaryData tags only (note that for BinaryData tags, the raw
722
726
  data of $$valPt is always 'undef' type, and may not be used
723
727
  when writing except for SubDirectory tags). EXIF tags (and
@@ -964,6 +968,10 @@ numerical, and generated automatically otherwise.
964
968
  OtherLang : [reserved] Used internally by QuickTime module to store a list
965
969
  of tag ID's for alternate-language tags based on this one.
966
970
 
971
+ ParentTagInfo : [reserved] Used internally to store a reference to the tag
972
+ information hash of the parent structure for flattened
973
+ structure tags.
974
+
967
975
  RootTagInfo : [reserved] Used internally to store a reference to the tag
968
976
  information hash of the top-level structure for flattened
969
977
  structure tags.
@@ -975,6 +983,9 @@ numerical, and generated automatically otherwise.
975
983
  alternate language tags (eg. 'fr'). Only used with formats
976
984
  which support alternate languages (eg. XMP, MIE, etc).
977
985
 
986
+ AddedUnknown : [reserved] Used internally to mark Unknown tags that were
987
+ added to the table at run time.
988
+
978
989
  SubDirectory { If it exists, this specifies the start of a new subdirectory.
979
990
  It contains a collection of variables which specify the type
980
991
  and location of the subdirectory. Note that ValueConv and