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.
- checksums.yaml +4 -4
- data/bin/Changes +114 -4
- data/bin/MANIFEST +11 -0
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +44 -43
- data/bin/arg_files/xmp2exif.args +2 -1
- data/bin/config_files/convert_regions.config +25 -14
- data/bin/config_files/example.config +1 -1
- data/bin/exiftool +72 -56
- data/bin/fmt_files/gpx.fmt +1 -1
- data/bin/fmt_files/gpx_wpt.fmt +1 -1
- data/bin/lib/Image/ExifTool/BuildTagLookup.pm +10 -2
- data/bin/lib/Image/ExifTool/CBOR.pm +277 -0
- data/bin/lib/Image/ExifTool/Canon.pm +25 -18
- data/bin/lib/Image/ExifTool/DPX.pm +13 -2
- data/bin/lib/Image/ExifTool/Exif.pm +11 -6
- data/bin/lib/Image/ExifTool/FlashPix.pm +35 -10
- data/bin/lib/Image/ExifTool/FujiFilm.pm +1 -0
- data/bin/lib/Image/ExifTool/Geotag.pm +13 -2
- data/bin/lib/Image/ExifTool/GoPro.pm +16 -1
- data/bin/lib/Image/ExifTool/ID3.pm +15 -3
- data/bin/lib/Image/ExifTool/JPEG.pm +68 -2
- data/bin/lib/Image/ExifTool/JSON.pm +4 -2
- data/bin/lib/Image/ExifTool/Jpeg2000.pm +58 -26
- data/bin/lib/Image/ExifTool/LIF.pm +153 -0
- data/bin/lib/Image/ExifTool/Lang/nl.pm +60 -59
- data/bin/lib/Image/ExifTool/M2TS.pm +103 -7
- data/bin/lib/Image/ExifTool/MIE.pm +2 -1
- data/bin/lib/Image/ExifTool/MRC.pm +1 -1
- data/bin/lib/Image/ExifTool/Nikon.pm +15 -4
- data/bin/lib/Image/ExifTool/NikonSettings.pm +10 -2
- data/bin/lib/Image/ExifTool/Olympus.pm +5 -2
- data/bin/lib/Image/ExifTool/Other.pm +93 -0
- data/bin/lib/Image/ExifTool/PDF.pm +9 -12
- data/bin/lib/Image/ExifTool/PNG.pm +7 -6
- data/bin/lib/Image/ExifTool/Panasonic.pm +14 -2
- data/bin/lib/Image/ExifTool/Pentax.pm +28 -5
- data/bin/lib/Image/ExifTool/Photoshop.pm +6 -0
- data/bin/lib/Image/ExifTool/QuickTime.pm +103 -24
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +203 -121
- data/bin/lib/Image/ExifTool/README +3 -0
- data/bin/lib/Image/ExifTool/RIFF.pm +7 -2
- data/bin/lib/Image/ExifTool/Samsung.pm +47 -10
- data/bin/lib/Image/ExifTool/Sony.pm +84 -33
- data/bin/lib/Image/ExifTool/TagLookup.pm +50 -3
- data/bin/lib/Image/ExifTool/TagNames.pod +135 -29
- data/bin/lib/Image/ExifTool/Torrent.pm +18 -11
- data/bin/lib/Image/ExifTool/WriteIPTC.pl +1 -1
- data/bin/lib/Image/ExifTool/WritePDF.pl +1 -0
- data/bin/lib/Image/ExifTool/WritePNG.pl +2 -0
- data/bin/lib/Image/ExifTool/WriteQuickTime.pl +11 -4
- data/bin/lib/Image/ExifTool/WriteXMP.pl +1 -1
- data/bin/lib/Image/ExifTool/Writer.pl +3 -0
- data/bin/lib/Image/ExifTool/XMP.pm +17 -5
- data/bin/lib/Image/ExifTool/XMP2.pl +2 -1
- data/bin/lib/Image/ExifTool/XMPStruct.pl +3 -1
- data/bin/lib/Image/ExifTool/ZISRAW.pm +121 -2
- data/bin/lib/Image/ExifTool.pm +79 -37
- data/bin/lib/Image/ExifTool.pod +62 -60
- data/bin/perl-Image-ExifTool.spec +43 -42
- data/lib/exiftool_vendored/version.rb +1 -1
- 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
|
-
|
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 => '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
|
@@ -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',
|
@@ -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
|
);
|