exiftool_vendored 12.25.0 → 12.35.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +174 -7
  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 +118 -92
  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 +16 -3
  14. data/bin/lib/Image/ExifTool/CBOR.pm +331 -0
  15. data/bin/lib/Image/ExifTool/Canon.pm +52 -20
  16. data/bin/lib/Image/ExifTool/Charset.pm +2 -0
  17. data/bin/lib/Image/ExifTool/DPX.pm +13 -2
  18. data/bin/lib/Image/ExifTool/Exif.pm +107 -8
  19. data/bin/lib/Image/ExifTool/FLIR.pm +33 -8
  20. data/bin/lib/Image/ExifTool/FlashPix.pm +35 -10
  21. data/bin/lib/Image/ExifTool/FujiFilm.pm +1 -0
  22. data/bin/lib/Image/ExifTool/Geotag.pm +13 -2
  23. data/bin/lib/Image/ExifTool/GoPro.pm +16 -1
  24. data/bin/lib/Image/ExifTool/ICC_Profile.pm +96 -4
  25. data/bin/lib/Image/ExifTool/ID3.pm +15 -3
  26. data/bin/lib/Image/ExifTool/JPEG.pm +68 -2
  27. data/bin/lib/Image/ExifTool/JSON.pm +7 -3
  28. data/bin/lib/Image/ExifTool/Jpeg2000.pm +164 -36
  29. data/bin/lib/Image/ExifTool/LIF.pm +153 -0
  30. data/bin/lib/Image/ExifTool/Lang/nl.pm +60 -59
  31. data/bin/lib/Image/ExifTool/M2TS.pm +103 -7
  32. data/bin/lib/Image/ExifTool/MIE.pm +2 -1
  33. data/bin/lib/Image/ExifTool/MRC.pm +1 -1
  34. data/bin/lib/Image/ExifTool/MacOS.pm +2 -2
  35. data/bin/lib/Image/ExifTool/Nikon.pm +50 -6
  36. data/bin/lib/Image/ExifTool/NikonSettings.pm +10 -2
  37. data/bin/lib/Image/ExifTool/Olympus.pm +9 -2
  38. data/bin/lib/Image/ExifTool/Other.pm +93 -0
  39. data/bin/lib/Image/ExifTool/PDF.pm +11 -12
  40. data/bin/lib/Image/ExifTool/PNG.pm +7 -6
  41. data/bin/lib/Image/ExifTool/Panasonic.pm +14 -2
  42. data/bin/lib/Image/ExifTool/Pentax.pm +28 -5
  43. data/bin/lib/Image/ExifTool/Photoshop.pm +6 -0
  44. data/bin/lib/Image/ExifTool/QuickTime.pm +123 -25
  45. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +203 -121
  46. data/bin/lib/Image/ExifTool/README +9 -2
  47. data/bin/lib/Image/ExifTool/RIFF.pm +7 -2
  48. data/bin/lib/Image/ExifTool/Samsung.pm +47 -10
  49. data/bin/lib/Image/ExifTool/Sony.pm +113 -42
  50. data/bin/lib/Image/ExifTool/TagLookup.pm +4599 -4451
  51. data/bin/lib/Image/ExifTool/TagNames.pod +276 -41
  52. data/bin/lib/Image/ExifTool/Torrent.pm +18 -11
  53. data/bin/lib/Image/ExifTool/WriteIPTC.pl +1 -1
  54. data/bin/lib/Image/ExifTool/WritePDF.pl +1 -0
  55. data/bin/lib/Image/ExifTool/WritePNG.pl +2 -0
  56. data/bin/lib/Image/ExifTool/WriteQuickTime.pl +21 -4
  57. data/bin/lib/Image/ExifTool/WriteXMP.pl +1 -1
  58. data/bin/lib/Image/ExifTool/Writer.pl +47 -2
  59. data/bin/lib/Image/ExifTool/XMP.pm +32 -12
  60. data/bin/lib/Image/ExifTool/XMP2.pl +5 -2
  61. data/bin/lib/Image/ExifTool/XMPStruct.pl +3 -1
  62. data/bin/lib/Image/ExifTool/ZISRAW.pm +121 -2
  63. data/bin/lib/Image/ExifTool.pm +153 -52
  64. data/bin/lib/Image/ExifTool.pod +70 -60
  65. data/bin/perl-Image-ExifTool.spec +43 -42
  66. data/lib/exiftool_vendored/version.rb +1 -1
  67. 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 58 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 => 'relative to 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
@@ -447,6 +450,10 @@ numerical, and generated automatically otherwise.
447
450
  may be written if the tag already exists. By default, all
448
451
  MakerNotes tags are permanent unless otherwise specified.
449
452
 
453
+ 'PreservePadding' - [QuickTime only] flag to preserve the
454
+ original size of the QuickTime atom by padding with nulls when
455
+ writing with the QuickTimePad option.
456
+
450
457
  'PrintHex' - specifies that unknown PrintConv values should
451
458
  be printed in hex (eg. 'Unknown (0x1)'). Also causes
452
459
  numerical tag values to be printed in hex in the HTML tag name
@@ -471,9 +478,9 @@ numerical, and generated automatically otherwise.
471
478
  tags in IFD1 of JPEG images which default to priority 0.
472
479
 
473
480
  'Protected' - bit mask to protect tags from writing:
474
- Bit 0x01 indicates an 'unsafe' tag, which is not set via
481
+ Bit 0x01 indicates an 'Unsafe' tag, which is not set via
475
482
  SetNewValuesFromFile() unless specified explicitly.
476
- Bit 0x02 indicates a 'protected' tag, which should not be set
483
+ Bit 0x02 indicates a 'Protected' tag, which should not be set
477
484
  directly by the user.
478
485
 
479
486
  'PutFirst' - [EXIF only] flag to place this value before IFD0