exiftool_vendored 12.25.0 → 12.32.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +114 -4
  3. data/bin/MANIFEST +11 -0
  4. data/bin/META.json +1 -1
  5. data/bin/META.yml +1 -1
  6. data/bin/README +44 -43
  7. data/bin/arg_files/xmp2exif.args +2 -1
  8. data/bin/config_files/convert_regions.config +25 -14
  9. data/bin/config_files/example.config +1 -1
  10. data/bin/exiftool +72 -56
  11. data/bin/fmt_files/gpx.fmt +1 -1
  12. data/bin/fmt_files/gpx_wpt.fmt +1 -1
  13. data/bin/lib/Image/ExifTool/BuildTagLookup.pm +10 -2
  14. data/bin/lib/Image/ExifTool/CBOR.pm +277 -0
  15. data/bin/lib/Image/ExifTool/Canon.pm +25 -18
  16. data/bin/lib/Image/ExifTool/DPX.pm +13 -2
  17. data/bin/lib/Image/ExifTool/Exif.pm +11 -6
  18. data/bin/lib/Image/ExifTool/FlashPix.pm +35 -10
  19. data/bin/lib/Image/ExifTool/FujiFilm.pm +1 -0
  20. data/bin/lib/Image/ExifTool/Geotag.pm +13 -2
  21. data/bin/lib/Image/ExifTool/GoPro.pm +16 -1
  22. data/bin/lib/Image/ExifTool/ID3.pm +15 -3
  23. data/bin/lib/Image/ExifTool/JPEG.pm +68 -2
  24. data/bin/lib/Image/ExifTool/JSON.pm +4 -2
  25. data/bin/lib/Image/ExifTool/Jpeg2000.pm +58 -26
  26. data/bin/lib/Image/ExifTool/LIF.pm +153 -0
  27. data/bin/lib/Image/ExifTool/Lang/nl.pm +60 -59
  28. data/bin/lib/Image/ExifTool/M2TS.pm +103 -7
  29. data/bin/lib/Image/ExifTool/MIE.pm +2 -1
  30. data/bin/lib/Image/ExifTool/MRC.pm +1 -1
  31. data/bin/lib/Image/ExifTool/Nikon.pm +15 -4
  32. data/bin/lib/Image/ExifTool/NikonSettings.pm +10 -2
  33. data/bin/lib/Image/ExifTool/Olympus.pm +5 -2
  34. data/bin/lib/Image/ExifTool/Other.pm +93 -0
  35. data/bin/lib/Image/ExifTool/PDF.pm +9 -12
  36. data/bin/lib/Image/ExifTool/PNG.pm +7 -6
  37. data/bin/lib/Image/ExifTool/Panasonic.pm +14 -2
  38. data/bin/lib/Image/ExifTool/Pentax.pm +28 -5
  39. data/bin/lib/Image/ExifTool/Photoshop.pm +6 -0
  40. data/bin/lib/Image/ExifTool/QuickTime.pm +103 -24
  41. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +203 -121
  42. data/bin/lib/Image/ExifTool/README +3 -0
  43. data/bin/lib/Image/ExifTool/RIFF.pm +7 -2
  44. data/bin/lib/Image/ExifTool/Samsung.pm +47 -10
  45. data/bin/lib/Image/ExifTool/Sony.pm +84 -33
  46. data/bin/lib/Image/ExifTool/TagLookup.pm +50 -3
  47. data/bin/lib/Image/ExifTool/TagNames.pod +135 -29
  48. data/bin/lib/Image/ExifTool/Torrent.pm +18 -11
  49. data/bin/lib/Image/ExifTool/WriteIPTC.pl +1 -1
  50. data/bin/lib/Image/ExifTool/WritePDF.pl +1 -0
  51. data/bin/lib/Image/ExifTool/WritePNG.pl +2 -0
  52. data/bin/lib/Image/ExifTool/WriteQuickTime.pl +11 -4
  53. data/bin/lib/Image/ExifTool/WriteXMP.pl +1 -1
  54. data/bin/lib/Image/ExifTool/Writer.pl +3 -0
  55. data/bin/lib/Image/ExifTool/XMP.pm +17 -5
  56. data/bin/lib/Image/ExifTool/XMP2.pl +2 -1
  57. data/bin/lib/Image/ExifTool/XMPStruct.pl +3 -1
  58. data/bin/lib/Image/ExifTool/ZISRAW.pm +121 -2
  59. data/bin/lib/Image/ExifTool.pm +79 -37
  60. data/bin/lib/Image/ExifTool.pod +62 -60
  61. data/bin/perl-Image-ExifTool.spec +43 -42
  62. data/lib/exiftool_vendored/version.rb +1 -1
  63. metadata +6 -3
@@ -25,6 +25,7 @@ sub Process_mebx($$$);
25
25
  sub ProcessFreeGPS($$$);
26
26
  sub ProcessFreeGPS2($$$);
27
27
  sub Process360Fly($$$);
28
+ sub ProcessFMAS($$$);
28
29
 
29
30
  # QuickTime data types that have ExifTool equivalents
30
31
  # (ref https://developer.apple.com/library/content/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW35)
@@ -95,18 +96,18 @@ my %insvLimit = (
95
96
  %Image::ExifTool::QuickTime::Stream = (
96
97
  GROUPS => { 2 => 'Location' },
97
98
  NOTES => q{
98
- Timed metadata extracted from QuickTime media data and some AVI videos when
99
- the ExtractEmbedded option is used. Although most of these tags are
100
- combined into the single table below, ExifTool currently reads 51 different
101
- formats of timed GPS metadata from video files.
99
+ The tags below are extracted from timed metadata in QuickTime and other
100
+ formats of video files when the ExtractEmbedded option is used. Although
101
+ most of these tags are combined into the single table below, ExifTool
102
+ currently reads 57 different formats of timed GPS metadata from video files.
102
103
  },
103
104
  VARS => { NO_ID => 1 },
104
105
  GPSLatitude => { PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', RawConv => '$$self{FoundGPSLatitude} = 1; $val' },
105
106
  GPSLongitude => { PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")' },
106
107
  GPSAltitude => { PrintConv => '(sprintf("%.4f", $val) + 0) . " m"' }, # round to 4 decimals
107
- GPSSpeed => { PrintConv => 'sprintf("%.4f", $val) + 0' }, # round to 4 decimals
108
+ GPSSpeed => { PrintConv => 'sprintf("%.4f", $val) + 0', Notes => 'in km/h unless GPSSpeedRef says otherwise' },
108
109
  GPSSpeedRef => { PrintConv => { K => 'km/h', M => 'mph', N => 'knots' } },
109
- GPSTrack => { PrintConv => 'sprintf("%.4f", $val) + 0' }, # round to 4 decimals
110
+ GPSTrack => { PrintConv => 'sprintf("%.4f", $val) + 0', Notes => 'true north unless GPSTrackRef says otherwise' },
110
111
  GPSTrackRef => { PrintConv => { M => 'Magnetic North', T => 'True North' } },
111
112
  GPSDateTime => {
112
113
  Groups => { 2 => 'Time' },
@@ -168,15 +169,29 @@ my %insvLimit = (
168
169
  },
169
170
  },
170
171
  gpmd => [{
171
- Name => 'gpmd_GoPro',
172
- Condition => '$$valPt !~ /^\0\0\xf2\xe1\xf0\xeeTT/',
173
- SubDirectory => { TagTable => 'Image::ExifTool::GoPro::GPMF' },
172
+ Name => 'gpmd_Kingslim', # Kingslim D4 dashcam
173
+ Condition => '$$valPt =~ /^.{21}\0\0\0A[NS][EW]/s',
174
+ SubDirectory => {
175
+ TagTable => 'Image::ExifTool::QuickTime::Stream',
176
+ ProcessProc => \&ProcessFreeGPS,
177
+ },
174
178
  },{
175
179
  Name => 'gpmd_Rove', # Rove Stealth 4K encrypted text
180
+ Condition => '$$valPt =~ /^\0\0\xf2\xe1\xf0\xeeTT/',
176
181
  SubDirectory => {
177
182
  TagTable => 'Image::ExifTool::QuickTime::Stream',
178
183
  ProcessProc => \&Process_text,
179
184
  },
185
+ },{
186
+ Name => 'gpmd_FMAS', # Vantrue N2S binary format
187
+ Condition => '$$valPt =~ /^FMAS\0\0\0\0/',
188
+ SubDirectory => {
189
+ TagTable => 'Image::ExifTool::QuickTime::Stream',
190
+ ProcessProc => \&ProcessFMAS,
191
+ },
192
+ },{
193
+ Name => 'gpmd_GoPro',
194
+ SubDirectory => { TagTable => 'Image::ExifTool::GoPro::GPMF' },
180
195
  }],
181
196
  fdsc => {
182
197
  Name => 'fdsc',
@@ -408,7 +423,14 @@ my %insvLimit = (
408
423
  Groups => { 2 => 'Time' },
409
424
  Format => 'double',
410
425
  RawConv => '$$self{FoundGPSDateTime} = 1; $val',
426
+ # by the specification, this should use the GPS epoch of Jan 6, 1980,
427
+ # but I have samples which use the Unix epoch of Jan 1, 1970, so convert
428
+ # to the Unix Epoch only if it doesn't match the CreateDate within 5 years
411
429
  ValueConv => q{
430
+ my $offset = 315964800;
431
+ if ($$self{CreateDate} and $$self{CreateDate} - $val > 24 * 3600 * 365 * 5) {
432
+ $val += $offset;
433
+ }
412
434
  my $str = ConvertUnixTime($val);
413
435
  my $frac = $val - int($val);
414
436
  if ($frac != 0) {
@@ -887,14 +909,8 @@ sub Process_text($$$)
887
909
  $tags{GPSDateTime} = $dateTime;
888
910
  $tags{GPSLatitude} = (($4 || 0) + $5/60) * ($6 eq 'N' ? 1 : -1);
889
911
  $tags{GPSLongitude} = (($7 || 0) + $8/60) * ($9 eq 'E' ? 1 : -1);
890
- if (length $10) {
891
- $tags{GPSSpeed} = $10 * $knotsToKph;
892
- $tags{GPSSpeedRef} = 'K';
893
- }
894
- if (length $11) {
895
- $tags{GPSTrack} = $11;
896
- $tags{GPSTrackRef} = 'T';
897
- }
912
+ $tags{GPSSpeed} = $10 * $knotsToKph if length $10;
913
+ $tags{GPSTrack} = $11 if length $11;
898
914
  } elsif ($tag =~ /^[A-Z]{2}GGA$/ and $dat =~ /^,(\d{2})(\d{2})(\d+(?:\.\d*)?),(\d*?)(\d{1,2}\.\d+),([NS]),(\d*?)(\d{1,2}\.\d+),([EW]),[1-6]?,(\d+)?,(\.\d+|\d+\.?\d*)?,(-?\d+\.?\d*)?,M?/s) {
899
915
  my $time = "$1:$2:$3";
900
916
  if ($$et{LastTime}) {
@@ -974,10 +990,7 @@ sub Process_text($$$)
974
990
  $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$dataPt, 0x39, 5)));
975
991
  $tags{GPSAltitude} = $val + 0 if $val =~ /^[-+]\d+$/;
976
992
  $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$dataPt, 0x3e, 3)));
977
- if ($val =~ /^\d+$/) {
978
- $tags{GPSSpeed} = $val + 0;
979
- $tags{GPSSpeedRef} = 'K';
980
- }
993
+ $tags{GPSSpeed} = $val + 0 if $val =~ /^\d+$/;
981
994
  if ($$dataPt =~ /^\0\0..\xaa\xaa/s) { # (BlueSkySea)
982
995
  $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$dataPt, 0xad, 12)));
983
996
  # the first X,Y,Z accelerometer readings from the AccelerometerData
@@ -1008,10 +1021,7 @@ sub Process_text($$$)
1008
1021
  $tags{GPSLatitude} = $2;
1009
1022
  $tags{GPSLongitude} = $1;
1010
1023
  $tags{GPSAltitude} = $1 if $$dataPt =~ /,\s*H\s+([-+]?\d+\.?\d*)m/;
1011
- if ($$dataPt =~ /,\s*H.S\s+([-+]?\d+\.?\d*)/) {
1012
- $tags{GPSSpeed} = $1 * $mpsToKph;
1013
- $tags{GPSSpeedRef} = 'K';
1014
- }
1024
+ $tags{GPSSpeed} = $1 * $mpsToKph if $$dataPt =~ /,\s*H.S\s+([-+]?\d+\.?\d*)/;
1015
1025
  $tags{Distance} = $1 * $mpsToKph if $$dataPt =~ /,\s*D\s+(\d+\.?\d*)m/;
1016
1026
  $tags{VerticalSpeed} = $1 if $$dataPt =~ /,\s*V.S\s+([-+]?\d+\.?\d*)/;
1017
1027
  $tags{FNumber} = $1 if $$dataPt =~ /\bF\/(\d+\.?\d*)/;
@@ -1072,14 +1082,8 @@ sub Process_text($$$)
1072
1082
  $tags{GPSDateTime} = sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%.2dZ', $year, $14, $13, $1, $2, $3);
1073
1083
  $tags{GPSLatitude} = (($5 || 0) + $6/60) * ($7 eq 'N' ? 1 : -1);
1074
1084
  $tags{GPSLongitude} = (($8 || 0) + $9/60) * ($10 eq 'E' ? 1 : -1);
1075
- if (length $11) {
1076
- $tags{GPSSpeed} = $11 * $knotsToKph;
1077
- $tags{GPSSpeedRef} = 'K';
1078
- }
1079
- if (length $12) {
1080
- $tags{GPSTrack} = $12;
1081
- $tags{GPSTrackRef} = 'T';
1082
- }
1085
+ $tags{GPSSpeed} = $11 * $knotsToKph if length $11;
1086
+ $tags{GPSTrack} = $12 if length $12;
1083
1087
  }
1084
1088
  $tags{GSensor} = $1 if $$dataPt =~ /\bgsensori,(.*?)(;|$)/;
1085
1089
  $tags{Car} = $1 if $$dataPt =~ /\bCAR,(.*?)(;|$)/;
@@ -1216,7 +1220,10 @@ sub ProcessSamples($)
1216
1220
  $et->VPrint(1, "${hdr}, Sample ".($i+1).' of '.scalar(@$start)." ($size bytes)\n");
1217
1221
  $et->VerboseDump(\$buff, Addr => $$start[$i]);
1218
1222
  }
1219
- if ($type eq 'text') {
1223
+ if ($type eq 'text' or
1224
+ # (PNDM is normally 'text', but was sbtl/tx3g in concatenated Garmin sample output_3videos.mp4)
1225
+ ($type eq 'sbtl' and $metaFormat eq 'tx3g' and $buff =~ /^..PNDM/s))
1226
+ {
1220
1227
 
1221
1228
  FoundSomething($et, $tagTbl, $time[$i], $dur[$i]);
1222
1229
  unless ($buff =~ /^\$BEGIN/) {
@@ -1251,8 +1258,7 @@ sub ProcessSamples($)
1251
1258
  next if length($buff) < 20 + $n;
1252
1259
  $et->HandleTag($tagTbl, GPSLatitude => Get32s(\$buff, 12+$n) * 180/0x80000000);
1253
1260
  $et->HandleTag($tagTbl, GPSLongitude => Get32s(\$buff, 16+$n) * 180/0x80000000);
1254
- $et->HandleTag($tagTbl, GPSSpeed => Get16u(\$buff, 8+$n) * $mphToKph);
1255
- $et->HandleTag($tagTbl, GPSSpeedRef => 'K');
1261
+ $et->HandleTag($tagTbl, GPSSpeed => Get16u(\$buff, 8+$n) * $mphToKph);
1256
1262
  SetGPSDateTime($et, $tagTbl, $time[$i]);
1257
1263
  next; # all done (don't store/process as text)
1258
1264
  }
@@ -1325,6 +1331,19 @@ sub ProcessSamples($)
1325
1331
  $$et{HandlerType} = $$et{HanderDesc} = '';
1326
1332
  }
1327
1333
 
1334
+ #------------------------------------------------------------------------------
1335
+ # Convert latitude/longitude from DDDMM.MMMM format to decimal degrees
1336
+ # Inputs: 0) latitude, 1) longitude
1337
+ # Returns: lat/lon are changed in place
1338
+ # (note: this method works fine for negative coordinates)
1339
+ sub ConvertLatLon($$)
1340
+ {
1341
+ my $deg = int($_[0] / 100); # latitude
1342
+ $_[0] = $deg + ($_[0] - $deg * 100) / 60;
1343
+ $deg = int($_[1] / 100); # longitude
1344
+ $_[1] = $deg + ($_[1] - $deg * 100) / 60;
1345
+ }
1346
+
1328
1347
  #------------------------------------------------------------------------------
1329
1348
  # Process "freeGPS " data blocks referenced by a 'gps ' (GPSDataList) atom
1330
1349
  # Inputs: 0) ExifTool ref, 1) dirInfo ref {DataPt,SampleTime,SampleDuration}, 2) tagTable ref
@@ -1336,7 +1355,7 @@ sub ProcessFreeGPS($$$)
1336
1355
  my ($et, $dirInfo, $tagTbl) = @_;
1337
1356
  my $dataPt = $$dirInfo{DataPt};
1338
1357
  my $dirLen = length $$dataPt;
1339
- my ($yr, $mon, $day, $hr, $min, $sec, $stat, $lbl);
1358
+ my ($yr, $mon, $day, $hr, $min, $sec, $stat, $lbl, $ddd);
1340
1359
  my ($lat, $latRef, $lon, $lonRef, $spd, $trk, $alt, @acc, @xtra);
1341
1360
 
1342
1361
  return 0 if $dirLen < 92;
@@ -1426,7 +1445,7 @@ sub ProcessFreeGPS($$$)
1426
1445
  map { $_ = $_ - 4294967296 if $_ >= 0x80000000; $_ /= 256 } @acc;
1427
1446
  }
1428
1447
 
1429
- } elsif ($$dataPt =~ /^.{40}A([NS])([EW])/s) {
1448
+ } elsif ($$dataPt =~ /^.{37}\0\0\0A([NS])([EW])/s) {
1430
1449
 
1431
1450
  # decode freeGPS from ViofoA119v3 dashcam (similar to Novatek GPS format)
1432
1451
  # 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 03 00 00 [..@.freeGPS ....]
@@ -1443,6 +1462,34 @@ sub ProcessFreeGPS($$$)
1443
1462
  $trk = GetFloat($dataPt, 0x38);
1444
1463
  SetByteOrder('MM');
1445
1464
 
1465
+ } elsif ($$dataPt =~ /^.{21}\0\0\0A([NS])([EW])/s) {
1466
+
1467
+ # also decode 'gpmd' chunk from Kingslim D4 dashcam videos
1468
+ # 0000: 0a 00 00 00 0b 00 00 00 07 00 00 00 e5 07 00 00 [................]
1469
+ # 0010: 06 00 00 00 03 00 00 00 41 4e 57 31 91 52 83 45 [........ANW1.R.E]
1470
+ # 0020: 15 70 fe c5 29 5c c3 41 ae c7 af 42 00 00 d1 be [.p..)\.A...B....]
1471
+ # 0030: 00 00 80 3b 00 00 2c 3e 00 00 00 00 00 00 00 00 [...;..,>........]
1472
+ # 0040: 00 00 00 00 00 00 00 00 00 00 00 00 26 26 26 26 [............&&&&]
1473
+ # 0050: 4c 49 47 4f 47 50 53 49 4e 46 4f 00 00 00 00 05 [LIGOGPSINFO.....]
1474
+ # 0060: 01 00 00 00 23 23 23 23 75 00 00 00 c0 22 20 20 [....####u...." ]
1475
+ # 0070: 20 f0 12 10 12 21 e5 0e 10 12 2f 90 10 13 01 f2 [ ....!..../.....]
1476
+ ($latRef, $lonRef) = ($1, $2);
1477
+ ($hr,$min,$sec,$yr,$mon,$day) = unpack("V6", $$dataPt);
1478
+ SetByteOrder('II');
1479
+ # lat/lon aren't decoded properly, but spd,trk,acc are
1480
+ $lat = GetFloat($dataPt, 0x1c);
1481
+ $lon = GetFloat($dataPt, 0x20);
1482
+ $et->VPrint(0, sprintf("Raw lat/lon = %.9f %.9f\n", $lat, $lon));
1483
+ $et->WarnOnce('GPSLatitude/Longitude encryption is not yet known, so these will be wrong');
1484
+ $lat = abs $lat;
1485
+ $lon = abs $lon;
1486
+ $spd = GetFloat($dataPt, 0x24) * $knotsToKph; # (convert knots to km/h)
1487
+ $trk = GetFloat($dataPt, 0x28);
1488
+ $acc[0] = GetFloat($dataPt, 0x2c);
1489
+ $acc[1] = GetFloat($dataPt, 0x30);
1490
+ $acc[2] = GetFloat($dataPt, 0x34);
1491
+ SetByteOrder('MM');
1492
+
1446
1493
  } elsif ($$dataPt =~ /^.{60}A\0{3}.{4}([NS])\0{3}.{4}([EW])\0{3}/s) {
1447
1494
 
1448
1495
  # decode freeGPS from Akaso dashcam
@@ -1463,6 +1510,23 @@ sub ProcessFreeGPS($$$)
1463
1510
  $trk -= 360 if $trk >= 360;
1464
1511
  SetByteOrder('MM');
1465
1512
 
1513
+ } elsif ($$dataPt =~ /^.{60}4W`b]S</s and length($$dataPt) >= 140) {
1514
+
1515
+ # 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 01 00 00 [..@.freeGPS ....]
1516
+ # 0010: 5a 58 53 42 4e 58 59 53 00 00 00 00 00 00 00 00 [ZXSBNXYS........]
1517
+ # 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
1518
+ # 0030: 00 00 00 00 00 00 00 00 00 00 00 00 34 57 60 62 [............4W`b]
1519
+ # 0040: 5d 53 3c 41 44 45 41 41 42 3e 40 40 3c 51 3c 45 []S<ADEAAB>@@<Q<E]
1520
+ # 0050: 41 40 43 3e 41 47 49 48 44 3c 5e 3c 40 41 46 43 [A@C>AGIHD<^<@AFC]
1521
+ # 0060: 42 3e 49 49 40 42 45 3c 55 3c 45 47 3e 45 43 41 [B>II@BE<U<EG>ECA]
1522
+ # decipher $GPRMC by subtracting 16 from each character value
1523
+ $_ = pack 'C*', map { $_>=16 and $_-=16 } unpack('x60C80', $$dataPt);
1524
+ return 0 unless /[A-Z]{2}RMC,(\d{2})(\d{2})(\d+(\.\d*)?),A?,(\d*?\d{1,2}\.\d+),([NS]),(\d*?\d{1,2}\.\d+),([EW]),(\d*\.?\d*),(\d*\.?\d*),(\d{2})(\d{2})(\d+)/;
1525
+ ($yr,$mon,$day,$hr,$min,$sec,$lat,$latRef,$lon,$lonRef) = ($13,$12,$11,$1,$2,$3,$5,$6,$7,$8);
1526
+ $yr += ($yr >= 70 ? 1900 : 2000);
1527
+ $spd = $9 * $knotsToKph if length $9;
1528
+ $trk = $10 if length $10;
1529
+
1466
1530
  } elsif ($$dataPt =~ /^.{16}YndAkasoCar/s) {
1467
1531
 
1468
1532
  # Akaso V1 dascham
@@ -1481,13 +1545,17 @@ sub ProcessFreeGPS($$$)
1481
1545
  return 0 unless $stat eq 'A' and ($latRef eq 'N' or $latRef eq 'S') and
1482
1546
  ($lonRef eq 'E' or $lonRef eq 'W');
1483
1547
 
1484
- $et->WarnOnce("Can't yet decrypt Akaso V1 timed GPS", 1);
1548
+ $et->WarnOnce('GPSLatitude/Longitude encryption is not yet known, so these will be wrong');
1485
1549
  # (see https://exiftool.org/forum/index.php?topic=11320.0)
1486
- return 1;
1487
1550
 
1488
1551
  SetByteOrder('II');
1552
+
1553
+ $spd = GetFloat($dataPt, 0x60);
1554
+ $trk = GetFloat($dataPt, 0x64) + 180; # (why is this off by 180?)
1489
1555
  $lat = GetDouble($dataPt, 0x50); # latitude is here, but encrypted somehow
1490
1556
  $lon = GetDouble($dataPt, 0x58); # longitude is here, but encrypted somehow
1557
+ $ddd = 1; # don't convert until we know what the format is
1558
+
1491
1559
  SetByteOrder('MM');
1492
1560
  #my $serialNum = substr($$dataPt, 0x68, 20);
1493
1561
 
@@ -1551,10 +1619,7 @@ sub ProcessFreeGPS($$$)
1551
1619
  #
1552
1620
  FoundSomething($et, $tagTbl, $$dirInfo{SampleTime}, $$dirInfo{SampleDuration});
1553
1621
  # lat/long are in DDDMM.MMMM format
1554
- my $deg = int($lat / 100);
1555
- $lat = $deg + ($lat - $deg * 100) / 60;
1556
- $deg = int($lon / 100);
1557
- $lon = $deg + ($lon - $deg * 100) / 60;
1622
+ ConvertLatLon($lat, $lon) unless $ddd;
1558
1623
  $sec = '0' . $sec unless $sec =~ /^\d{2}/; # pad integer part of seconds to 2 digits
1559
1624
  if (defined $yr) {
1560
1625
  my $time = sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%sZ',$yr,$mon,$day,$hr,$min,$sec);
@@ -1566,14 +1631,8 @@ sub ProcessFreeGPS($$$)
1566
1631
  $et->HandleTag($tagTbl, GPSLatitude => $lat * ($latRef eq 'S' ? -1 : 1));
1567
1632
  $et->HandleTag($tagTbl, GPSLongitude => $lon * ($lonRef eq 'W' ? -1 : 1));
1568
1633
  $et->HandleTag($tagTbl, GPSAltitude => $alt) if defined $alt;
1569
- if (defined $spd) {
1570
- $et->HandleTag($tagTbl, GPSSpeed => $spd);
1571
- $et->HandleTag($tagTbl, GPSSpeedRef => 'K');
1572
- }
1573
- if (defined $trk) {
1574
- $et->HandleTag($tagTbl, GPSTrack => $trk);
1575
- $et->HandleTag($tagTbl, GPSTrackRef => 'T');
1576
- }
1634
+ $et->HandleTag($tagTbl, GPSSpeed => $spd) if defined $spd;
1635
+ $et->HandleTag($tagTbl, GPSTrack => $trk) if defined $trk;
1577
1636
  while (@xtra) {
1578
1637
  my $tag = shift @xtra;
1579
1638
  $et->HandleTag($tagTbl, $tag => shift @xtra);
@@ -1692,9 +1751,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
1692
1751
  $et->HandleTag($tagTbl, GPSLatitude => Get32s(\$b, 0x10) / 1e7);
1693
1752
  $et->HandleTag($tagTbl, GPSLongitude => Get32s(\$b, 0x18) / 1e7);
1694
1753
  $et->HandleTag($tagTbl, GPSSpeed => Get32s(\$b, 0x20) / 100 * $mpsToKph);
1695
- $et->HandleTag($tagTbl, GPSSpeedRef => 'K');
1696
1754
  $et->HandleTag($tagTbl, GPSTrack => $trk);
1697
- $et->HandleTag($tagTbl, GPSTrackRef => 'T');
1698
1755
  $et->HandleTag($tagTbl, GPSAltitude => Get32s(\$b, 0x28) / 1000);
1699
1756
  $lastRecPos = $recPos;
1700
1757
  $foundNew = 1;
@@ -1804,6 +1861,27 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
1804
1861
  $spd = GetFloat($dataPt, 0x50);
1805
1862
  $trk = GetFloat($dataPt, 0x54);
1806
1863
 
1864
+ } elsif ($$dataPt =~ /^.{16}A([NS])([EW])\0/s) {
1865
+
1866
+ # INNOVV MP4 video (same format as INNOVV TS)
1867
+ while ($$dataPt =~ /(A[NS][EW]\0.{28})/g) {
1868
+ my $dat = $1;
1869
+ $lat = abs(GetFloat(\$dat, 4)); # (abs just to be safe)
1870
+ $lon = abs(GetFloat(\$dat, 8)); # (abs just to be safe)
1871
+ $spd = GetFloat(\$dat, 12) * $knotsToKph;
1872
+ $trk = GetFloat(\$dat, 16);
1873
+ @acc = unpack('x20V3', $dat);
1874
+ map { $_ = $_ - 4294967296 if $_ >= 0x80000000 } @acc;
1875
+ ConvertLatLon($lat, $lon);
1876
+ $$et{DOC_NUM} = ++$$et{DOC_COUNT};
1877
+ $et->HandleTag($tagTbl, GPSLatitude => $lat * (substr($dat,1,1) eq 'S' ? -1 : 1));
1878
+ $et->HandleTag($tagTbl, GPSLongitude => $lon * (substr($dat,2,1) eq 'W' ? -1 : 1));
1879
+ $et->HandleTag($tagTbl, GPSSpeed => $spd);
1880
+ $et->HandleTag($tagTbl, GPSTrack => $trk);
1881
+ $et->HandleTag($tagTbl, Accelerometer => "@acc");
1882
+ }
1883
+ return 1;
1884
+
1807
1885
  } else {
1808
1886
 
1809
1887
  # (look for binary GPS as stored by NextBase 512G, ref PH)
@@ -1845,9 +1923,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
1845
1923
  $et->HandleTag($tagTbl, GPSLatitude => $lat);
1846
1924
  $et->HandleTag($tagTbl, GPSLongitude => $lon);
1847
1925
  $et->HandleTag($tagTbl, GPSSpeed => $spd / 100 * $mpsToKph);
1848
- $et->HandleTag($tagTbl, GPSSpeedRef => 'K');
1849
1926
  $et->HandleTag($tagTbl, GPSTrack => $trk);
1850
- $et->HandleTag($tagTbl, GPSTrackRef => 'T');
1851
1927
  last if $pos += 0x20 > length($$dataPt) - 0x1e;
1852
1928
  }
1853
1929
  return $$et{DOC_NUM} ? 1 : 0; # return 0 if nothing extracted
@@ -1860,23 +1936,12 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
1860
1936
  $yr += 2000 if $yr < 2000;
1861
1937
  my $time = sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%.2dZ', $yr, $mon, $day, $hr, $min, $sec);
1862
1938
  # convert from DDMM.MMMMMM to DD.DDDDDD format if necessary
1863
- unless ($ddd) {
1864
- my $deg = int($lat / 100);
1865
- $lat = $deg + ($lat - $deg * 100) / 60;
1866
- $deg = int($lon / 100);
1867
- $lon = $deg + ($lon - $deg * 100) / 60;
1868
- }
1939
+ ConvertLatLon($lat, $lon) unless $ddd;
1869
1940
  $et->HandleTag($tagTbl, GPSDateTime => $time);
1870
1941
  $et->HandleTag($tagTbl, GPSLatitude => $lat * ($latRef eq 'S' ? -1 : 1));
1871
1942
  $et->HandleTag($tagTbl, GPSLongitude => $lon * ($lonRef eq 'W' ? -1 : 1));
1872
- if (defined $spd) {
1873
- $et->HandleTag($tagTbl, GPSSpeed => $spd); # (now in km/h)
1874
- $et->HandleTag($tagTbl, GPSSpeedRef => 'K');
1875
- }
1876
- if (defined $trk) {
1877
- $et->HandleTag($tagTbl, GPSTrack => $trk);
1878
- $et->HandleTag($tagTbl, GPSTrackRef => 'T');
1879
- }
1943
+ $et->HandleTag($tagTbl, GPSSpeed => $spd) if defined $spd; # (now in km/h)
1944
+ $et->HandleTag($tagTbl, GPSTrack => $trk) if defined $trk;
1880
1945
  if (defined $alt) {
1881
1946
  $et->HandleTag($tagTbl, GPSAltitude => $alt);
1882
1947
  }
@@ -1884,6 +1949,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
1884
1949
  return 1;
1885
1950
  }
1886
1951
 
1952
+
1887
1953
  #------------------------------------------------------------------------------
1888
1954
  # Extract embedded information referenced from a track
1889
1955
  # Inputs: 0) ExifTool ref, 1) tag name, 2) data ref
@@ -1962,22 +2028,18 @@ sub ParseTag($$$)
1962
2028
  while ($pos + 36 < $dataLen) {
1963
2029
  my $dat = substr($$dataPt, $pos, 36);
1964
2030
  last if $dat eq "\x0" x 36;
1965
- my @a = unpack 'VVVVCVCV', $dat;
2031
+ my @a = unpack 'VVVVaVaV', $dat;
1966
2032
  $$et{DOC_NUM} = ++$$et{DOC_COUNT};
1967
2033
  # 0=1, 1=1, 2=secs, 3=?
1968
2034
  SetGPSDateTime($et, $tagTbl, $a[2]);
1969
2035
  my $lat = $a[5] / 1e3;
1970
2036
  my $lon = $a[7] / 1e3;
1971
- my $deg = int($lat / 100);
1972
- $lat = $deg + ($lat - $deg * 100) / 60;
1973
- $deg = int($lon / 100);
1974
- $lon = $deg + ($lon - $deg * 100) / 60;
1975
- $lat = -$lat if $a[4] eq 'S';
1976
- $lon = -$lon if $a[6] eq 'W';
2037
+ ConvertLatLon($lat, $lon);
2038
+ $lat = -abs($lat) if $a[4] eq 'S';
2039
+ $lon = -abs($lon) if $a[6] eq 'W';
1977
2040
  $et->HandleTag($tagTbl, GPSLatitude => $lat);
1978
2041
  $et->HandleTag($tagTbl, GPSLongitude => $lon);
1979
- $et->HandleTag($tagTbl, GPSSpeed => $a[3] / 1e3);
1980
- $et->HandleTag($tagTbl, GPSSpeedRef => 'K');
2042
+ $et->HandleTag($tagTbl, GPSSpeed => $a[3] / 1e3);
1981
2043
  $pos += 36;
1982
2044
  }
1983
2045
  SetByteOrder('MM');
@@ -2039,9 +2101,9 @@ sub Process_mebx($$$)
2039
2101
 
2040
2102
  # parse using information from 'keys' table (eg. Apple iPhone7+ hevc 'Core Media Data Handler')
2041
2103
  $et->VerboseDir('mebx', undef, length $$dataPt);
2042
- my $pos = 0;
2043
- while ($pos + 8 < length $$dataPt) {
2044
- my $len = Get32u($dataPt, $pos);
2104
+ my ($pos, $len);
2105
+ for ($pos=0; $pos+8<length($$dataPt); $pos+=$len) {
2106
+ $len = Get32u($dataPt, $pos);
2045
2107
  last if $len < 8 or $pos + $len > length $$dataPt;
2046
2108
  my $id = substr($$dataPt, $pos+4, 4);
2047
2109
  my $info = $$ee{'keys'}{$id};
@@ -2064,7 +2126,6 @@ sub Process_mebx($$$)
2064
2126
  } else {
2065
2127
  $et->WarnOnce('No key information for mebx ID ' . PrintableTagID($id,1));
2066
2128
  }
2067
- $pos += $len;
2068
2129
  }
2069
2130
  return 1;
2070
2131
  }
@@ -2120,20 +2181,14 @@ sub Process_gps0($$$)
2120
2181
  my $lat = GetDouble($dataPt, $pos);
2121
2182
  my $lon = GetDouble($dataPt, $pos+8);
2122
2183
  next if abs($lat) > 9000 or abs($lon) > 18000;
2123
- # (note: this method works fine for negative coordinates)
2124
- my $deg = int($lat / 100);
2125
- $lat = $deg + ($lat - $deg * 100) / 60;
2126
- $deg = int($lon / 100);
2127
- $lon = $deg + ($lon - $deg * 100) / 60;
2184
+ ConvertLatLon($lat, $lon);
2128
2185
  my @a = unpack('C*', substr($$dataPt, $pos+22, 6)); # unpack date/time
2129
2186
  $a[0] += 2000;
2130
2187
  $et->HandleTag($tagTbl, GPSDateTime => sprintf("%.4d:%.2d:%.2d %.2d:%.2d:%.2dZ", @a));
2131
2188
  $et->HandleTag($tagTbl, GPSLatitude => $lat);
2132
2189
  $et->HandleTag($tagTbl, GPSLongitude => $lon);
2133
2190
  $et->HandleTag($tagTbl, GPSSpeed => Get16u($dataPt, $pos+0x14));
2134
- $et->HandleTag($tagTbl, GPSSpeedRef => 'K');
2135
2191
  $et->HandleTag($tagTbl, GPSTrack => Get8u($dataPt, $pos+0x1c) * 2); # (NC)
2136
- $et->HandleTag($tagTbl, GPSTrackRef => 'T');
2137
2192
  $et->HandleTag($tagTbl, GPSAltitude => Get32s($dataPt, $pos + 0x10));
2138
2193
  # yet to be decoded:
2139
2194
  # 0x1d - int8u[3] seen: "1 1 0"
@@ -2222,10 +2277,7 @@ sub ProcessRIFFTrailer($$$)
2222
2277
  my $lat = GetDouble(\$buff, $pos+4);
2223
2278
  my $lon = GetDouble(\$buff, $pos+12);
2224
2279
  $et->Warn('Bad gps0 record') and last if abs($lat) > 9000 or abs($lon) > 18000;
2225
- my $deg = int($lat / 100);
2226
- $lat = $deg + ($lat - $deg * 100) / 60;
2227
- $deg = int($lon / 100);
2228
- $lon = $deg + ($lon - $deg * 100) / 60;
2280
+ ConvertLatLon($lat, $lon);
2229
2281
  $lat = -$lat if Get8u(\$buff, $pos+0x21) == 2; # wild guess
2230
2282
  $lon = -$lon if Get8u(\$buff, $pos+0x22) == 2; # wild guess
2231
2283
  my @a = unpack('C*', substr($buff, $pos+26, 6)); # unpack date/time
@@ -2235,9 +2287,7 @@ sub ProcessRIFFTrailer($$$)
2235
2287
  $et->HandleTag($tagTbl, GPSLatitude => $lat);
2236
2288
  $et->HandleTag($tagTbl, GPSLongitude => $lon);
2237
2289
  $et->HandleTag($tagTbl, GPSSpeed => Get16u(\$buff, $pos+0x18) * $knotsToKph);
2238
- $et->HandleTag($tagTbl, GPSSpeedRef => 'K');
2239
2290
  $et->HandleTag($tagTbl, GPSTrack => Get8u(\$buff, $pos+0x20) * 2);
2240
- $et->HandleTag($tagTbl, GPSTrackRef => 'T');
2241
2291
  }
2242
2292
  } elsif ($tag eq 'gsen') {
2243
2293
  # (similar to record decoded in Process_gsen)
@@ -2291,17 +2341,11 @@ sub ProcessNMEA($$$)
2291
2341
  $et->HandleTag($tagTbl, GPSDateTime => $fix{dat});
2292
2342
  $et->HandleTag($tagTbl, GPSLatitude => $fix{lat});
2293
2343
  $et->HandleTag($tagTbl, GPSLongitude => $fix{lon});
2294
- if (defined $fix{spd}) {
2295
- $et->HandleTag($tagTbl, GPSSpeed => $fix{spd} * $knotsToKph);
2296
- $et->HandleTag($tagTbl, GPSSpeedRef => 'K');
2297
- }
2298
- if (defined $fix{trk}) {
2299
- $et->HandleTag($tagTbl, GPSTrack => $fix{trk});
2300
- $et->HandleTag($tagTbl, GPSTrackRef => 'T');
2301
- }
2302
- $et->HandleTag($tagTbl, GPSAltitude => $fix{alt}) if defined $fix{alt};
2303
- $et->HandleTag($tagTbl, GPSSatellites => $fix{nsats}+0) if defined $fix{nsats};
2304
- $et->HandleTag($tagTbl, GPSDOP => $fix{hdop}) if defined $fix{hdop};
2344
+ $et->HandleTag($tagTbl, GPSSpeed => $fix{spd} * $knotsToKph) if defined $fix{spd};
2345
+ $et->HandleTag($tagTbl, GPSTrack => $fix{trk}) if defined $fix{trk};
2346
+ $et->HandleTag($tagTbl, GPSAltitude => $fix{alt}) if defined $fix{alt};
2347
+ $et->HandleTag($tagTbl, GPSSatellites=> $fix{nsats}+0) if defined $fix{nsats};
2348
+ $et->HandleTag($tagTbl, GPSDOP => $fix{hdop}) if defined $fix{hdop};
2305
2349
  }
2306
2350
  undef %fix;
2307
2351
  }
@@ -2455,9 +2499,7 @@ sub ProcessTTAD($$$)
2455
2499
  $et->HandleTag($tagTbl, GPSLongitude => GetDouble($dataPt, $pos+0x24));
2456
2500
  $et->HandleTag($tagTbl, GPSAltitude => GetDouble($dataPt, $pos+0x14));
2457
2501
  $et->HandleTag($tagTbl, GPSSpeed => GetDouble($dataPt, $pos+0x0c) * $mpsToKph);
2458
- $et->HandleTag($tagTbl, GPSSpeedRef => 'K');
2459
2502
  $et->HandleTag($tagTbl, GPSTrack => GetDouble($dataPt, $pos+0x30));
2460
- $et->HandleTag($tagTbl, GPSTrackRef => 'T');
2461
2503
  if ($unknown) {
2462
2504
  my @a = map { GetDouble($dataPt, $pos+0x38+8*$_) } 0..2;
2463
2505
  $et->HandleTag($tagTbl, Unknown03 => "@a");
@@ -2577,21 +2619,26 @@ sub ProcessInsta360($;$)
2577
2619
  my $tmp = substr($buff, $p, $dlen);
2578
2620
  my @a = unpack('VVvaa8aa8aa8a8a8', $tmp);
2579
2621
  next unless $a[3] eq 'A'; # (ignore void fixes)
2580
- last unless ($a[5] eq 'N' or $a[5] eq 'S') and # (quick validation)
2581
- ($a[7] eq 'E' or $a[7] eq 'W');
2622
+ unless (($a[5] eq 'N' or $a[5] eq 'S') and # (quick validation)
2623
+ ($a[7] eq 'E' or $a[7] eq 'W' or
2624
+ # (odd, but I've seen "O" instead of "W". Perhaps
2625
+ # when the language is french? ie. "Ouest"?)
2626
+ $a[7] eq 'O'))
2627
+ {
2628
+ $et->Warn('Unrecognized INSV GPS format');
2629
+ last;
2630
+ }
2582
2631
  $$et{DOC_NUM} = ++$$et{DOC_COUNT};
2583
2632
  $a[$_] = GetDouble(\$a[$_], 0) foreach 4,6,8,9,10;
2584
2633
  $a[4] = -abs($a[4]) if $a[5] eq 'S'; # (abs just in case it was already signed)
2585
- $a[6] = -abs($a[6]) if $a[7] eq 'W';
2586
- $et->HandleTag($tagTbl, GPSDateTime => Image::ExifTool::ConvertUnixTime($a[0]) . 'Z');
2587
- $et->HandleTag($tagTbl, GPSLatitude => $a[4]);
2634
+ $a[6] = -abs($a[6]) if $a[7] ne 'E';
2635
+ $et->HandleTag($tagTbl, GPSDateTime => Image::ExifTool::ConvertUnixTime($a[0]) . 'Z');
2636
+ $et->HandleTag($tagTbl, GPSLatitude => $a[4]);
2588
2637
  $et->HandleTag($tagTbl, GPSLongitude => $a[6]);
2589
- $et->HandleTag($tagTbl, GPSSpeed => $a[8] * $mpsToKph);
2590
- $et->HandleTag($tagTbl, GPSSpeedRef => 'K');
2591
- $et->HandleTag($tagTbl, GPSTrack => $a[9]);
2592
- $et->HandleTag($tagTbl, GPSTrackRef => 'T');
2593
- $et->HandleTag($tagTbl, GPSAltitude => $a[10]);
2594
- $et->HandleTag($tagTbl, Unknown02 => "@a[1,2]") if $unknown; # millisecond counter (https://exiftool.org/forum/index.php?topic=9884.msg65143#msg65143)
2638
+ $et->HandleTag($tagTbl, GPSSpeed => $a[8] * $mpsToKph);
2639
+ $et->HandleTag($tagTbl, GPSTrack => $a[9]);
2640
+ $et->HandleTag($tagTbl, GPSAltitude => $a[10]);
2641
+ $et->HandleTag($tagTbl, Unknown02 => "@a[1,2]") if $unknown; # millisecond counter (https://exiftool.org/forum/index.php?topic=9884.msg65143#msg65143)
2595
2642
  }
2596
2643
  }
2597
2644
  } elsif ($id == 0x101) {
@@ -2647,6 +2694,41 @@ sub Process360Fly($$$)
2647
2694
  return 1;
2648
2695
  }
2649
2696
 
2697
+ #------------------------------------------------------------------------------
2698
+ # Process GPS from Vantrue N2S dashcam
2699
+ # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
2700
+ # Returns: 1 on success
2701
+ sub ProcessFMAS($$$)
2702
+ {
2703
+ my ($et, $dirInfo, $tagTbl) = @_;
2704
+ my $dataPt = $$dirInfo{DataPt};
2705
+ return 0 unless $$dataPt =~ /^FMAS\0\0\0\0.{72}SAMM.{36}A/s and length($$dataPt) >= 160;
2706
+ $et->VerboseDir('FMAS', undef, length($$dataPt));
2707
+ # 0000: 46 4d 41 53 00 00 00 00 00 00 00 00 00 00 00 00 [FMAS............]
2708
+ # 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
2709
+ # 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
2710
+ # 0030: 02 08 01 08 06 08 02 04 07 02 06 00 00 00 00 00 [................]
2711
+ # 0040: 00 00 00 00 00 00 00 00 4f 46 4e 49 4d 4d 41 53 [........OFNIMMAS]
2712
+ # 0050: 53 41 4d 4d 01 00 00 00 00 00 00 00 00 00 00 00 [SAMM............]
2713
+ # 0060: e5 07 09 18 08 00 22 00 02 00 00 00 a1 82 8a bf [......".........]
2714
+ # 0070: 89 23 8e bd 0b 2c 30 bc 41 57 4e 51 16 00 a1 01 [.#...,0.AWNQ....]
2715
+ # 0080: 29 26 27 0c 4b 00 49 00 00 00 00 00 00 00 00 00 [)&'.K.I.........]
2716
+ # 0090: 00 00 00 00 00 00 00 00 00 52 00 00 00 00 00 00 [.........R......]
2717
+ my @a = unpack('x96vCCCCCCx16AAACCCvCCvvv',$$dataPt);
2718
+ SetByteOrder('II');
2719
+ my $acc = ReadValue($dataPt, 0x6c, 'float', 3); # (looks like Z comes first in my sample)
2720
+ my $lon = $a[10] + ($a[11] + $a[13]/6000) / 60; # (why zero byte at $a[12]?)
2721
+ my $lat = $a[14] + ($a[15] + $a[16]/6000) / 60;
2722
+ $et->HandleTag($tagTbl, GPSDateTime => sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%.2d', @a[0..5]));
2723
+ $et->HandleTag($tagTbl, GPSLatitude => $lat * ($a[9] eq 'S' ? -1 : 1));
2724
+ $et->HandleTag($tagTbl, GPSLongitude => $lon * ($a[8] eq 'W' ? -1 : 1));
2725
+ $et->HandleTag($tagTbl, GPSSpeed => $a[17] * $mphToKph); # convert mph -> kph
2726
+ $et->HandleTag($tagTbl, GPSTrack => $a[18]);
2727
+ $et->HandleTag($tagTbl, Accelerometer=> $acc);
2728
+ SetByteOrder('MM');
2729
+ return 1;
2730
+ }
2731
+
2650
2732
  #------------------------------------------------------------------------------
2651
2733
  # Scan media data for "freeGPS" metadata if not found already (ref PH)
2652
2734
  # Inputs: 0) ExifTool ref
@@ -2720,7 +2802,7 @@ sub ScanMediaData($)
2720
2802
  $buf2 = substr($buff, $len);
2721
2803
  }
2722
2804
  if ($tagTbl) {
2723
- $$et{DOC_NUM} = 0;
2805
+ $$et{DOC_NUM} = 0; # reset DOC_NUM after extracting embedded metadata
2724
2806
  $et->VPrint(0, "--------------------------\n");
2725
2807
  SetByteOrder($oldByteOrder);
2726
2808
  $$et{INDENT} = substr $$et{INDENT}, 0, -2;
@@ -408,6 +408,9 @@ numerical, and generated automatically otherwise.
408
408
  to be evaluated. Expression may access $val and $et,
409
409
  and is evaluated only when reading.
410
410
 
411
+ 'iTXt' - [PNG TextualData tags only] flag to write tag as PNG
412
+ iTXt chunk even if it contains no special characters.
413
+
411
414
  'List' - flag indicating that duplicate entries of this tag
412
415
  are allowed, and will be accumulated in a list. Note that for
413
416
  XMP information, 3 different types of lists are supported and
@@ -30,7 +30,7 @@ use strict;
30
30
  use vars qw($VERSION);
31
31
  use Image::ExifTool qw(:DataAccess :Utils);
32
32
 
33
- $VERSION = '1.58';
33
+ $VERSION = '1.59';
34
34
 
35
35
  sub ConvertTimecode($);
36
36
  sub ProcessSGLT($$$);
@@ -527,6 +527,10 @@ my %code2charset = (
527
527
  Name => 'Text',
528
528
  Notes => 'streamed text, extracted when the ExtractEmbedded option is used',
529
529
  },
530
+ 'id3 ' => {
531
+ Name => 'ID3',
532
+ SubDirectory => { TagTable => 'Image::ExifTool::ID3::Main' },
533
+ },
530
534
  #
531
535
  # WebP-specific tags
532
536
  #
@@ -818,6 +822,7 @@ my %code2charset = (
818
822
  ILGT => 'Lightness',
819
823
  IMED => 'Medium',
820
824
  INAM => 'Title',
825
+ ITRK => 'TrackNumber',
821
826
  IPLT => 'NumColors',
822
827
  IPRD => 'Product',
823
828
  ISBJ => 'Subject',
@@ -1080,7 +1085,7 @@ my %code2charset = (
1080
1085
  Name => 'TextFormat',
1081
1086
  Condition => '$$self{RIFFStreamType} eq "txts"',
1082
1087
  Hidden => 1,
1083
- RawConv => '$self->Options("ExtractEmbedded") or $self->WarnOnce("Use ExtractEmbedded option to extract timed text"); undef',
1088
+ RawConv => '$self->Options("ExtractEmbedded") or $self->WarnOnce("Use ExtractEmbedded option to extract timed text",3); undef',
1084
1089
  },
1085
1090
  ],
1086
1091
  );