exiftool-vendored.exe 12.26.0 → 12.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/exiftool_files/Changes +119 -4
- package/bin/exiftool_files/README +44 -43
- package/bin/exiftool_files/arg_files/xmp2exif.args +2 -1
- package/bin/exiftool_files/config_files/convert_regions.config +25 -14
- package/bin/exiftool_files/config_files/example.config +1 -1
- package/bin/exiftool_files/exiftool.pl +79 -66
- package/bin/exiftool_files/fmt_files/gpx.fmt +1 -1
- package/bin/exiftool_files/fmt_files/gpx_wpt.fmt +1 -1
- package/bin/exiftool_files/lib/Image/ExifTool/BuildTagLookup.pm +11 -3
- package/bin/exiftool_files/lib/Image/ExifTool/CBOR.pm +331 -0
- package/bin/exiftool_files/lib/Image/ExifTool/Canon.pm +26 -7
- package/bin/exiftool_files/lib/Image/ExifTool/DPX.pm +13 -2
- package/bin/exiftool_files/lib/Image/ExifTool/Exif.pm +98 -4
- package/bin/exiftool_files/lib/Image/ExifTool/FlashPix.pm +35 -10
- package/bin/exiftool_files/lib/Image/ExifTool/FujiFilm.pm +1 -0
- package/bin/exiftool_files/lib/Image/ExifTool/Geotag.pm +13 -2
- package/bin/exiftool_files/lib/Image/ExifTool/GoPro.pm +16 -1
- package/bin/exiftool_files/lib/Image/ExifTool/ID3.pm +15 -3
- package/bin/exiftool_files/lib/Image/ExifTool/JSON.pm +7 -3
- package/bin/exiftool_files/lib/Image/ExifTool/Jpeg2000.pm +60 -26
- package/bin/exiftool_files/lib/Image/ExifTool/LIF.pm +153 -0
- package/bin/exiftool_files/lib/Image/ExifTool/Lang/nl.pm +60 -59
- package/bin/exiftool_files/lib/Image/ExifTool/M2TS.pm +103 -7
- package/bin/exiftool_files/lib/Image/ExifTool/MacOS.pm +2 -2
- package/bin/exiftool_files/lib/Image/ExifTool/Nikon.pm +14 -3
- package/bin/exiftool_files/lib/Image/ExifTool/NikonSettings.pm +10 -2
- package/bin/exiftool_files/lib/Image/ExifTool/Olympus.pm +9 -2
- package/bin/exiftool_files/lib/Image/ExifTool/Other.pm +93 -0
- package/bin/exiftool_files/lib/Image/ExifTool/PDF.pm +9 -12
- package/bin/exiftool_files/lib/Image/ExifTool/PNG.pm +7 -6
- package/bin/exiftool_files/lib/Image/ExifTool/Panasonic.pm +14 -3
- package/bin/exiftool_files/lib/Image/ExifTool/Pentax.pm +27 -5
- package/bin/exiftool_files/lib/Image/ExifTool/Photoshop.pm +6 -0
- package/bin/exiftool_files/lib/Image/ExifTool/QuickTime.pm +105 -24
- package/bin/exiftool_files/lib/Image/ExifTool/QuickTimeStream.pl +203 -121
- package/bin/exiftool_files/lib/Image/ExifTool/README +5 -2
- package/bin/exiftool_files/lib/Image/ExifTool/RIFF.pm +6 -1
- package/bin/exiftool_files/lib/Image/ExifTool/Samsung.pm +47 -10
- package/bin/exiftool_files/lib/Image/ExifTool/Sony.pm +85 -34
- package/bin/exiftool_files/lib/Image/ExifTool/TagLookup.pm +65 -5
- package/bin/exiftool_files/lib/Image/ExifTool/TagNames.pod +153 -32
- package/bin/exiftool_files/lib/Image/ExifTool/Torrent.pm +18 -11
- package/bin/exiftool_files/lib/Image/ExifTool/WritePDF.pl +1 -0
- package/bin/exiftool_files/lib/Image/ExifTool/WritePNG.pl +2 -0
- package/bin/exiftool_files/lib/Image/ExifTool/WriteQuickTime.pl +8 -4
- package/bin/exiftool_files/lib/Image/ExifTool/Writer.pl +3 -0
- package/bin/exiftool_files/lib/Image/ExifTool/XMP.pm +21 -4
- package/bin/exiftool_files/lib/Image/ExifTool/XMP2.pl +3 -1
- package/bin/exiftool_files/lib/Image/ExifTool/XMPStruct.pl +3 -1
- package/bin/exiftool_files/lib/Image/ExifTool/ZISRAW.pm +121 -2
- package/bin/exiftool_files/lib/Image/ExifTool.pm +8867 -8835
- package/bin/exiftool_files/lib/Image/ExifTool.pod +58 -56
- package/package.json +3 -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
|
-
|
|
99
|
-
the ExtractEmbedded option is used. Although
|
|
100
|
-
combined into the single table below, ExifTool
|
|
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'
|
|
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'
|
|
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 => '
|
|
172
|
-
Condition => '$$valPt
|
|
173
|
-
SubDirectory => {
|
|
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
|
|
891
|
-
|
|
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
|
|
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
|
|
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
|
|
1076
|
-
|
|
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
|
|
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 =~ /^.{
|
|
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(
|
|
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
|
-
|
|
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
|
|
1570
|
-
|
|
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
|
|
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
|
|
1873
|
-
|
|
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 '
|
|
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
|
-
|
|
1972
|
-
$lat =
|
|
1973
|
-
$
|
|
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
|
|
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
|
|
2043
|
-
|
|
2044
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
}
|
|
2298
|
-
|
|
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
|
-
|
|
2581
|
-
|
|
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]
|
|
2586
|
-
$et->HandleTag($tagTbl, GPSDateTime
|
|
2587
|
-
$et->HandleTag($tagTbl, GPSLatitude
|
|
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
|
|
2590
|
-
$et->HandleTag($tagTbl,
|
|
2591
|
-
$et->HandleTag($tagTbl,
|
|
2592
|
-
$et->HandleTag($tagTbl,
|
|
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
|
|
@@ -471,9 +474,9 @@ numerical, and generated automatically otherwise.
|
|
|
471
474
|
tags in IFD1 of JPEG images which default to priority 0.
|
|
472
475
|
|
|
473
476
|
'Protected' - bit mask to protect tags from writing:
|
|
474
|
-
Bit 0x01 indicates an '
|
|
477
|
+
Bit 0x01 indicates an 'Unsafe' tag, which is not set via
|
|
475
478
|
SetNewValuesFromFile() unless specified explicitly.
|
|
476
|
-
Bit 0x02 indicates a '
|
|
479
|
+
Bit 0x02 indicates a 'Protected' tag, which should not be set
|
|
477
480
|
directly by the user.
|
|
478
481
|
|
|
479
482
|
'PutFirst' - [EXIF only] flag to place this value before IFD0
|
|
@@ -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.
|
|
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',
|