exiftool-vendored.exe 12.30.0 → 12.38.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 +129 -3
- package/bin/exiftool_files/README +2 -2
- package/bin/exiftool_files/arg_files/xmp2exif.args +2 -1
- package/bin/exiftool_files/config_files/example.config +1 -1
- package/bin/exiftool_files/exiftool.pl +100 -58
- 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 +13 -3
- package/bin/exiftool_files/lib/Image/ExifTool/CBOR.pm +331 -0
- package/bin/exiftool_files/lib/Image/ExifTool/Canon.pm +175 -12
- package/bin/exiftool_files/lib/Image/ExifTool/CanonCustom.pm +12 -2
- package/bin/exiftool_files/lib/Image/ExifTool/Charset.pm +2 -0
- package/bin/exiftool_files/lib/Image/ExifTool/DPX.pm +13 -2
- package/bin/exiftool_files/lib/Image/ExifTool/DarwinCore.pm +2 -2
- package/bin/exiftool_files/lib/Image/ExifTool/Exif.pm +109 -3
- package/bin/exiftool_files/lib/Image/ExifTool/FLIR.pm +33 -8
- package/bin/exiftool_files/lib/Image/ExifTool/GIF.pm +5 -1
- package/bin/exiftool_files/lib/Image/ExifTool/GPS.pm +14 -10
- 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/ICC_Profile.pm +96 -4
- package/bin/exiftool_files/lib/Image/ExifTool/JSON.pm +7 -3
- package/bin/exiftool_files/lib/Image/ExifTool/Jpeg2000.pm +154 -24
- package/bin/exiftool_files/lib/Image/ExifTool/M2TS.pm +27 -12
- package/bin/exiftool_files/lib/Image/ExifTool/MacOS.pm +2 -2
- package/bin/exiftool_files/lib/Image/ExifTool/Nikon.pm +1204 -96
- package/bin/exiftool_files/lib/Image/ExifTool/NikonCustom.pm +5 -1
- package/bin/exiftool_files/lib/Image/ExifTool/NikonSettings.pm +135 -71
- package/bin/exiftool_files/lib/Image/ExifTool/Olympus.pm +5 -1
- package/bin/exiftool_files/lib/Image/ExifTool/OpenEXR.pm +4 -2
- package/bin/exiftool_files/lib/Image/ExifTool/PDF.pm +11 -12
- package/bin/exiftool_files/lib/Image/ExifTool/PNG.pm +4 -1
- package/bin/exiftool_files/lib/Image/ExifTool/Panasonic.pm +2 -2
- package/bin/exiftool_files/lib/Image/ExifTool/Pentax.pm +2 -1
- package/bin/exiftool_files/lib/Image/ExifTool/QuickTime.pm +69 -10
- package/bin/exiftool_files/lib/Image/ExifTool/QuickTimeStream.pl +141 -111
- package/bin/exiftool_files/lib/Image/ExifTool/README +9 -2
- package/bin/exiftool_files/lib/Image/ExifTool/Sony.pm +56 -13
- package/bin/exiftool_files/lib/Image/ExifTool/TagInfoXML.pm +9 -4
- package/bin/exiftool_files/lib/Image/ExifTool/TagLookup.pm +6473 -5827
- package/bin/exiftool_files/lib/Image/ExifTool/TagNames.pod +1401 -54
- 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 +10 -0
- package/bin/exiftool_files/lib/Image/ExifTool/WriteXMP.pl +10 -11
- package/bin/exiftool_files/lib/Image/ExifTool/Writer.pl +50 -5
- package/bin/exiftool_files/lib/Image/ExifTool/XMP.pm +125 -31
- 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.pm +8931 -8864
- package/bin/exiftool_files/lib/Image/ExifTool.pod +21 -13
- package/package.json +3 -3
|
@@ -47,7 +47,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
|
|
|
47
47
|
use Image::ExifTool::Exif;
|
|
48
48
|
use Image::ExifTool::GPS;
|
|
49
49
|
|
|
50
|
-
$VERSION = '2.
|
|
50
|
+
$VERSION = '2.73';
|
|
51
51
|
|
|
52
52
|
sub ProcessMOV($$;$);
|
|
53
53
|
sub ProcessKeys($$$);
|
|
@@ -482,6 +482,17 @@ my %eeBox2 = (
|
|
|
482
482
|
# (Pittasoft Blackview dashcam MP4 videos)
|
|
483
483
|
Condition => '$$valPt =~ /^\0\0..(cprt|sttm|ptnm|ptrh|thum|gps |3gf )/s',
|
|
484
484
|
SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Pittasoft' },
|
|
485
|
+
},{
|
|
486
|
+
Name => 'ThumbnailImage',
|
|
487
|
+
# (DJI Zenmuse XT2 thermal camera)
|
|
488
|
+
Groups => { 2 => 'Preview' },
|
|
489
|
+
Condition => '$$valPt =~ /^.{4}mdat\xff\xd8\xff/s',
|
|
490
|
+
RawConv => q{
|
|
491
|
+
my $len = unpack('N', $val);
|
|
492
|
+
return undef if $len <= 8 or $len > length($val);
|
|
493
|
+
return substr($val, 8, $len-8);
|
|
494
|
+
},
|
|
495
|
+
Binary => 1,
|
|
485
496
|
},{
|
|
486
497
|
Unknown => 1,
|
|
487
498
|
Binary => 1,
|
|
@@ -558,6 +569,7 @@ my %eeBox2 = (
|
|
|
558
569
|
# *** this is where ExifTool writes XMP in MP4 videos (as per XMP spec) ***
|
|
559
570
|
Condition => '$$valPt=~/^\xbe\x7a\xcf\xcb\x97\xa9\x42\xe8\x9c\x71\x99\x94\x91\xe3\xaf\xac/',
|
|
560
571
|
WriteGroup => 'XMP', # (write main XMP tags here)
|
|
572
|
+
PreservePadding => 1,
|
|
561
573
|
SubDirectory => {
|
|
562
574
|
TagTable => 'Image::ExifTool::XMP::Main',
|
|
563
575
|
Start => 16,
|
|
@@ -607,6 +619,7 @@ my %eeBox2 = (
|
|
|
607
619
|
Name => 'PreviewImage',
|
|
608
620
|
Condition => '$$valPt=~/^\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16/',
|
|
609
621
|
Groups => { 2 => 'Preview' },
|
|
622
|
+
PreservePadding => 1,
|
|
610
623
|
# 0x00 - undef[16]: UUID
|
|
611
624
|
# 0x10 - int32u[2]: "0 1" (version and/or item count?)
|
|
612
625
|
# 0x18 - int32u: PRVW atom size
|
|
@@ -738,6 +751,7 @@ my %eeBox2 = (
|
|
|
738
751
|
Name => 'SamsungTrailer',
|
|
739
752
|
SubDirectory => { TagTable => 'Image::ExifTool::Samsung::Trailer' },
|
|
740
753
|
},
|
|
754
|
+
# 'samn'? - seen in Vantrue N2S sample video
|
|
741
755
|
);
|
|
742
756
|
|
|
743
757
|
# MPEG-4 'ftyp' atom
|
|
@@ -6356,7 +6370,7 @@ my %eeBox2 = (
|
|
|
6356
6370
|
'player.movie.visual.tint' => 'Tint',
|
|
6357
6371
|
'player.movie.visual.contrast' => 'Contrast',
|
|
6358
6372
|
'player.movie.audio.gain' => 'AudioGain',
|
|
6359
|
-
'player.movie.audio.treble' => '
|
|
6373
|
+
'player.movie.audio.treble' => 'Treble',
|
|
6360
6374
|
'player.movie.audio.bass' => 'Bass',
|
|
6361
6375
|
'player.movie.audio.balance' => 'Balance',
|
|
6362
6376
|
'player.movie.audio.pitchshift' => 'PitchShift',
|
|
@@ -6450,10 +6464,12 @@ my %eeBox2 = (
|
|
|
6450
6464
|
# iTunes info ('----') atoms
|
|
6451
6465
|
%Image::ExifTool::QuickTime::iTunesInfo = (
|
|
6452
6466
|
PROCESS_PROC => \&ProcessMOV,
|
|
6453
|
-
GROUPS => { 2 => 'Audio' },
|
|
6467
|
+
GROUPS => { 1 => 'iTunes', 2 => 'Audio' },
|
|
6468
|
+
VARS => { LONG_TAGS => 0 }, # (hack for discrepancy in the way long tags are counted in BuildTagLookup)
|
|
6454
6469
|
NOTES => q{
|
|
6455
6470
|
ExifTool will extract any iTunesInfo tags that exist, even if they are not
|
|
6456
|
-
defined in this table.
|
|
6471
|
+
defined in this table. These tags belong to the family 1 "iTunes" group,
|
|
6472
|
+
and are not currently writable.
|
|
6457
6473
|
},
|
|
6458
6474
|
# 'mean'/'name'/'data' atoms form a triplet, but unfortunately
|
|
6459
6475
|
# I haven't been able to find any documentation on this.
|
|
@@ -6514,9 +6530,45 @@ my %eeBox2 = (
|
|
|
6514
6530
|
SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::EncodingParams' },
|
|
6515
6531
|
},
|
|
6516
6532
|
# also heard about 'iTunPGAP', but I haven't seen a sample
|
|
6517
|
-
|
|
6518
|
-
|
|
6519
|
-
|
|
6533
|
+
# all tags below were added based on samples I have seen - PH
|
|
6534
|
+
DISCNUMBER => 'DiscNumber',
|
|
6535
|
+
TRACKNUMBER => 'TrackNumber',
|
|
6536
|
+
ARTISTS => 'Artists',
|
|
6537
|
+
CATALOGNUMBER => 'CatalogNumber',
|
|
6538
|
+
RATING => 'Rating',
|
|
6539
|
+
MEDIA => 'Media',
|
|
6540
|
+
SCRIPT => 'Script', # character set? (seen 'Latn')
|
|
6541
|
+
BARCODE => 'Barcode',
|
|
6542
|
+
LABEL => 'Label',
|
|
6543
|
+
MOOD => 'Mood',
|
|
6544
|
+
popularimeter => 'Popularimeter',
|
|
6545
|
+
'Dynamic Range (DR)'=> 'DynamicRange',
|
|
6546
|
+
initialkey => 'InitialKey',
|
|
6547
|
+
originalyear => 'OriginalYear',
|
|
6548
|
+
originaldate => 'OriginalDate',
|
|
6549
|
+
'~length' => 'Length', # play length? (ie. duration?)
|
|
6550
|
+
replaygain_track_gain=>'ReplayTrackGain',
|
|
6551
|
+
replaygain_track_peak=>'ReplayTrackPeak',
|
|
6552
|
+
'Volume Level (ReplayGain)'=> 'ReplayVolumeLevel',
|
|
6553
|
+
'Dynamic Range (R128)'=> 'DynamicRangeR128',
|
|
6554
|
+
'Volume Level (R128)' => 'VolumeLevelR128',
|
|
6555
|
+
'Peak Level (Sample)' => 'PeakLevelSample',
|
|
6556
|
+
'Peak Level (R128)' => 'PeakLevelR128',
|
|
6557
|
+
# also seen (many from forum12777):
|
|
6558
|
+
# 'MusicBrainz Album Release Country'
|
|
6559
|
+
# 'MusicBrainz Album Type'
|
|
6560
|
+
# 'MusicBrainz Album Status'
|
|
6561
|
+
# 'MusicBrainz Track Id'
|
|
6562
|
+
# 'MusicBrainz Release Track Id'
|
|
6563
|
+
# 'MusicBrainz Album Id'
|
|
6564
|
+
# 'MusicBrainz Album Artist Id'
|
|
6565
|
+
# 'MusicBrainz Artist Id'
|
|
6566
|
+
# 'Acoustid Id' (sic)
|
|
6567
|
+
# 'Tool Version'
|
|
6568
|
+
# 'Tool Name'
|
|
6569
|
+
# 'ISRC'
|
|
6570
|
+
# 'HDCD'
|
|
6571
|
+
# 'Waveform'
|
|
6520
6572
|
);
|
|
6521
6573
|
|
|
6522
6574
|
# iTunes audio encoding parameters
|
|
@@ -9075,6 +9127,12 @@ sub ProcessMOV($$;$)
|
|
|
9075
9127
|
} else {
|
|
9076
9128
|
my $t = PrintableTagID($tag,2);
|
|
9077
9129
|
$et->VPrint(0,"$$et{INDENT}Tag '${t}' extends to end of file");
|
|
9130
|
+
if ($$tagTablePtr{"$tag-size"}) {
|
|
9131
|
+
my $pos = $raf->Tell();
|
|
9132
|
+
$raf->Seek(0, 2);
|
|
9133
|
+
$et->HandleTag($tagTablePtr, "$tag-size", $raf->Tell() - $pos);
|
|
9134
|
+
$et->HandleTag($tagTablePtr, "$tag-offset", $pos) if $$tagTablePtr{"$tag-offset"};
|
|
9135
|
+
}
|
|
9078
9136
|
}
|
|
9079
9137
|
last;
|
|
9080
9138
|
}
|
|
@@ -9301,6 +9359,7 @@ ItemID: foreach $id (keys %$items) {
|
|
|
9301
9359
|
Name => $name,
|
|
9302
9360
|
Description => $desc,
|
|
9303
9361
|
};
|
|
9362
|
+
$et->VPrint(0, $$et{INDENT}, "[adding QuickTime:$name]\n");
|
|
9304
9363
|
AddTagToTable($tagTablePtr, $tag, $tagInfo);
|
|
9305
9364
|
}
|
|
9306
9365
|
# ignore 8-byte header
|
|
@@ -9312,9 +9371,9 @@ ItemID: foreach $id (keys %$items) {
|
|
|
9312
9371
|
$val = \$buff;
|
|
9313
9372
|
}
|
|
9314
9373
|
}
|
|
9315
|
-
|
|
9374
|
+
$$tagInfo{List} = 1; # (allow any of these tags to have multiple data elements)
|
|
9375
|
+
$et->VerboseInfo($tag, $tagInfo, Value => $val) if $verbose;
|
|
9316
9376
|
} else {
|
|
9317
|
-
undef %triplet if $tag eq 'mean';
|
|
9318
9377
|
$triplet{$tag} = substr($val,4) if length($val) > 4;
|
|
9319
9378
|
undef $tagInfo; # don't store this tag
|
|
9320
9379
|
}
|
|
@@ -9380,7 +9439,7 @@ ItemID: foreach $id (keys %$items) {
|
|
|
9380
9439
|
for (;;) {
|
|
9381
9440
|
last if $pos + 16 > $size;
|
|
9382
9441
|
my ($len, $type, $flags, $ctry, $lang) = unpack("x${pos}Na4Nnn", $val);
|
|
9383
|
-
last if $pos + $len > $size;
|
|
9442
|
+
last if $pos + $len > $size or not $len;
|
|
9384
9443
|
my ($value, $langInfo, $oldDir);
|
|
9385
9444
|
my $format = $$tagInfo{Format};
|
|
9386
9445
|
if ($type eq 'data' and $len >= 16) {
|
|
@@ -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)
|
|
@@ -98,15 +99,15 @@ my %insvLimit = (
|
|
|
98
99
|
The tags below are extracted from timed metadata in QuickTime and other
|
|
99
100
|
formats of video files when the ExtractEmbedded option is used. Although
|
|
100
101
|
most of these tags are combined into the single table below, ExifTool
|
|
101
|
-
currently reads
|
|
102
|
+
currently reads 59 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' },
|
|
@@ -181,6 +182,13 @@ my %insvLimit = (
|
|
|
181
182
|
TagTable => 'Image::ExifTool::QuickTime::Stream',
|
|
182
183
|
ProcessProc => \&Process_text,
|
|
183
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
|
+
},
|
|
184
192
|
},{
|
|
185
193
|
Name => 'gpmd_GoPro',
|
|
186
194
|
SubDirectory => { TagTable => 'Image::ExifTool::GoPro::GPMF' },
|
|
@@ -901,14 +909,8 @@ sub Process_text($$$)
|
|
|
901
909
|
$tags{GPSDateTime} = $dateTime;
|
|
902
910
|
$tags{GPSLatitude} = (($4 || 0) + $5/60) * ($6 eq 'N' ? 1 : -1);
|
|
903
911
|
$tags{GPSLongitude} = (($7 || 0) + $8/60) * ($9 eq 'E' ? 1 : -1);
|
|
904
|
-
if
|
|
905
|
-
|
|
906
|
-
$tags{GPSSpeedRef} = 'K';
|
|
907
|
-
}
|
|
908
|
-
if (length $11) {
|
|
909
|
-
$tags{GPSTrack} = $11;
|
|
910
|
-
$tags{GPSTrackRef} = 'T';
|
|
911
|
-
}
|
|
912
|
+
$tags{GPSSpeed} = $10 * $knotsToKph if length $10;
|
|
913
|
+
$tags{GPSTrack} = $11 if length $11;
|
|
912
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) {
|
|
913
915
|
my $time = "$1:$2:$3";
|
|
914
916
|
if ($$et{LastTime}) {
|
|
@@ -988,10 +990,7 @@ sub Process_text($$$)
|
|
|
988
990
|
$val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$dataPt, 0x39, 5)));
|
|
989
991
|
$tags{GPSAltitude} = $val + 0 if $val =~ /^[-+]\d+$/;
|
|
990
992
|
$val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$dataPt, 0x3e, 3)));
|
|
991
|
-
if
|
|
992
|
-
$tags{GPSSpeed} = $val + 0;
|
|
993
|
-
$tags{GPSSpeedRef} = 'K';
|
|
994
|
-
}
|
|
993
|
+
$tags{GPSSpeed} = $val + 0 if $val =~ /^\d+$/;
|
|
995
994
|
if ($$dataPt =~ /^\0\0..\xaa\xaa/s) { # (BlueSkySea)
|
|
996
995
|
$val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$dataPt, 0xad, 12)));
|
|
997
996
|
# the first X,Y,Z accelerometer readings from the AccelerometerData
|
|
@@ -1022,10 +1021,7 @@ sub Process_text($$$)
|
|
|
1022
1021
|
$tags{GPSLatitude} = $2;
|
|
1023
1022
|
$tags{GPSLongitude} = $1;
|
|
1024
1023
|
$tags{GPSAltitude} = $1 if $$dataPt =~ /,\s*H\s+([-+]?\d+\.?\d*)m/;
|
|
1025
|
-
if
|
|
1026
|
-
$tags{GPSSpeed} = $1 * $mpsToKph;
|
|
1027
|
-
$tags{GPSSpeedRef} = 'K';
|
|
1028
|
-
}
|
|
1024
|
+
$tags{GPSSpeed} = $1 * $mpsToKph if $$dataPt =~ /,\s*H.S\s+([-+]?\d+\.?\d*)/;
|
|
1029
1025
|
$tags{Distance} = $1 * $mpsToKph if $$dataPt =~ /,\s*D\s+(\d+\.?\d*)m/;
|
|
1030
1026
|
$tags{VerticalSpeed} = $1 if $$dataPt =~ /,\s*V.S\s+([-+]?\d+\.?\d*)/;
|
|
1031
1027
|
$tags{FNumber} = $1 if $$dataPt =~ /\bF\/(\d+\.?\d*)/;
|
|
@@ -1086,14 +1082,8 @@ sub Process_text($$$)
|
|
|
1086
1082
|
$tags{GPSDateTime} = sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%.2dZ', $year, $14, $13, $1, $2, $3);
|
|
1087
1083
|
$tags{GPSLatitude} = (($5 || 0) + $6/60) * ($7 eq 'N' ? 1 : -1);
|
|
1088
1084
|
$tags{GPSLongitude} = (($8 || 0) + $9/60) * ($10 eq 'E' ? 1 : -1);
|
|
1089
|
-
if
|
|
1090
|
-
|
|
1091
|
-
$tags{GPSSpeedRef} = 'K';
|
|
1092
|
-
}
|
|
1093
|
-
if (length $12) {
|
|
1094
|
-
$tags{GPSTrack} = $12;
|
|
1095
|
-
$tags{GPSTrackRef} = 'T';
|
|
1096
|
-
}
|
|
1085
|
+
$tags{GPSSpeed} = $11 * $knotsToKph if length $11;
|
|
1086
|
+
$tags{GPSTrack} = $12 if length $12;
|
|
1097
1087
|
}
|
|
1098
1088
|
$tags{GSensor} = $1 if $$dataPt =~ /\bgsensori,(.*?)(;|$)/;
|
|
1099
1089
|
$tags{Car} = $1 if $$dataPt =~ /\bCAR,(.*?)(;|$)/;
|
|
@@ -1268,8 +1258,7 @@ sub ProcessSamples($)
|
|
|
1268
1258
|
next if length($buff) < 20 + $n;
|
|
1269
1259
|
$et->HandleTag($tagTbl, GPSLatitude => Get32s(\$buff, 12+$n) * 180/0x80000000);
|
|
1270
1260
|
$et->HandleTag($tagTbl, GPSLongitude => Get32s(\$buff, 16+$n) * 180/0x80000000);
|
|
1271
|
-
$et->HandleTag($tagTbl, GPSSpeed
|
|
1272
|
-
$et->HandleTag($tagTbl, GPSSpeedRef => 'K');
|
|
1261
|
+
$et->HandleTag($tagTbl, GPSSpeed => Get16u(\$buff, 8+$n) * $mphToKph);
|
|
1273
1262
|
SetGPSDateTime($et, $tagTbl, $time[$i]);
|
|
1274
1263
|
next; # all done (don't store/process as text)
|
|
1275
1264
|
}
|
|
@@ -1342,6 +1331,19 @@ sub ProcessSamples($)
|
|
|
1342
1331
|
$$et{HandlerType} = $$et{HanderDesc} = '';
|
|
1343
1332
|
}
|
|
1344
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
|
+
|
|
1345
1347
|
#------------------------------------------------------------------------------
|
|
1346
1348
|
# Process "freeGPS " data blocks referenced by a 'gps ' (GPSDataList) atom
|
|
1347
1349
|
# Inputs: 0) ExifTool ref, 1) dirInfo ref {DataPt,SampleTime,SampleDuration}, 2) tagTable ref
|
|
@@ -1353,7 +1355,7 @@ sub ProcessFreeGPS($$$)
|
|
|
1353
1355
|
my ($et, $dirInfo, $tagTbl) = @_;
|
|
1354
1356
|
my $dataPt = $$dirInfo{DataPt};
|
|
1355
1357
|
my $dirLen = length $$dataPt;
|
|
1356
|
-
my ($yr, $mon, $day, $hr, $min, $sec, $stat, $lbl);
|
|
1358
|
+
my ($yr, $mon, $day, $hr, $min, $sec, $stat, $lbl, $ddd);
|
|
1357
1359
|
my ($lat, $latRef, $lon, $lonRef, $spd, $trk, $alt, @acc, @xtra);
|
|
1358
1360
|
|
|
1359
1361
|
return 0 if $dirLen < 92;
|
|
@@ -1478,7 +1480,7 @@ sub ProcessFreeGPS($$$)
|
|
|
1478
1480
|
$lat = GetFloat($dataPt, 0x1c);
|
|
1479
1481
|
$lon = GetFloat($dataPt, 0x20);
|
|
1480
1482
|
$et->VPrint(0, sprintf("Raw lat/lon = %.9f %.9f\n", $lat, $lon));
|
|
1481
|
-
$et->WarnOnce('GPSLatitude/Longitude
|
|
1483
|
+
$et->WarnOnce('GPSLatitude/Longitude encryption is not yet known, so these will be wrong');
|
|
1482
1484
|
$lat = abs $lat;
|
|
1483
1485
|
$lon = abs $lon;
|
|
1484
1486
|
$spd = GetFloat($dataPt, 0x24) * $knotsToKph; # (convert knots to km/h)
|
|
@@ -1508,6 +1510,23 @@ sub ProcessFreeGPS($$$)
|
|
|
1508
1510
|
$trk -= 360 if $trk >= 360;
|
|
1509
1511
|
SetByteOrder('MM');
|
|
1510
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
|
+
|
|
1511
1530
|
} elsif ($$dataPt =~ /^.{16}YndAkasoCar/s) {
|
|
1512
1531
|
|
|
1513
1532
|
# Akaso V1 dascham
|
|
@@ -1526,13 +1545,17 @@ sub ProcessFreeGPS($$$)
|
|
|
1526
1545
|
return 0 unless $stat eq 'A' and ($latRef eq 'N' or $latRef eq 'S') and
|
|
1527
1546
|
($lonRef eq 'E' or $lonRef eq 'W');
|
|
1528
1547
|
|
|
1529
|
-
$et->WarnOnce(
|
|
1548
|
+
$et->WarnOnce('GPSLatitude/Longitude encryption is not yet known, so these will be wrong');
|
|
1530
1549
|
# (see https://exiftool.org/forum/index.php?topic=11320.0)
|
|
1531
|
-
return 1;
|
|
1532
1550
|
|
|
1533
1551
|
SetByteOrder('II');
|
|
1552
|
+
|
|
1553
|
+
$spd = GetFloat($dataPt, 0x60);
|
|
1554
|
+
$trk = GetFloat($dataPt, 0x64) + 180; # (why is this off by 180?)
|
|
1534
1555
|
$lat = GetDouble($dataPt, 0x50); # latitude is here, but encrypted somehow
|
|
1535
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
|
+
|
|
1536
1559
|
SetByteOrder('MM');
|
|
1537
1560
|
#my $serialNum = substr($$dataPt, 0x68, 20);
|
|
1538
1561
|
|
|
@@ -1558,6 +1581,31 @@ sub ProcessFreeGPS($$$)
|
|
|
1558
1581
|
substr($time,7,6) = pack 'C*', map { $_ ^= 0x70 } unpack 'C*', substr($time,7,6);
|
|
1559
1582
|
# (other values are currently unknown)
|
|
1560
1583
|
|
|
1584
|
+
} elsif ($$dataPt =~ /^.{64}A([NS])([EW])\0/s) {
|
|
1585
|
+
|
|
1586
|
+
# Vantrue S1 dashcam
|
|
1587
|
+
# 0000: 00 00 80 00 66 72 65 65 47 50 53 20 78 00 00 00 [....freeGPS x...]
|
|
1588
|
+
# 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
|
|
1589
|
+
# 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
|
|
1590
|
+
# 0030: 68 6f 72 73 6f 6e 74 65 63 68 00 00 00 00 00 00 [horsontech......]
|
|
1591
|
+
# 0040: 41 4e 45 00 15 00 00 00 07 00 00 00 02 00 00 00 [ANE.............]
|
|
1592
|
+
# 0050: 03 00 00 00 35 00 00 00 05 00 00 00 4f 74 4c 44 [....5.......OtLD]
|
|
1593
|
+
# 0060: e2 77 a0 45 89 c1 98 42 71 bd ac 42 02 ab 0d 43 [.w.E...Bq..B...C]
|
|
1594
|
+
# 0070: 05 00 00 00 7f 00 00 00 07 01 00 00 00 00 00 00 [................]
|
|
1595
|
+
($latRef, $lonRef) = ($1, $2);
|
|
1596
|
+
($yr,$mon,$day,$hr,$min,$sec,@acc) = unpack('x68V6x20V3', $$dataPt);
|
|
1597
|
+
return 0 unless $mon>=1 and $mon<=12 and $day>=1 and $day<=31;
|
|
1598
|
+
$yr += 2000 if $yr < 2000;
|
|
1599
|
+
# (not sure about acc scaling)
|
|
1600
|
+
map { $_ = $_ - 4294967296 if $_ >= 0x80000000; $_ /= 1000 } @acc;
|
|
1601
|
+
SetByteOrder('II');
|
|
1602
|
+
$lon = GetFloat($dataPt, 0x5c);
|
|
1603
|
+
$lat = GetFloat($dataPt, 0x60);
|
|
1604
|
+
$spd = GetFloat($dataPt, 0x64) * $knotsToKph;
|
|
1605
|
+
$trk = GetFloat($dataPt, 0x68);
|
|
1606
|
+
$alt = GetFloat($dataPt, 0x6c);
|
|
1607
|
+
SetByteOrder('MM');
|
|
1608
|
+
|
|
1561
1609
|
} else {
|
|
1562
1610
|
|
|
1563
1611
|
# decode binary GPS format (Viofo A119S, ref 2)
|
|
@@ -1596,10 +1644,7 @@ sub ProcessFreeGPS($$$)
|
|
|
1596
1644
|
#
|
|
1597
1645
|
FoundSomething($et, $tagTbl, $$dirInfo{SampleTime}, $$dirInfo{SampleDuration});
|
|
1598
1646
|
# lat/long are in DDDMM.MMMM format
|
|
1599
|
-
|
|
1600
|
-
$lat = $deg + ($lat - $deg * 100) / 60;
|
|
1601
|
-
$deg = int($lon / 100);
|
|
1602
|
-
$lon = $deg + ($lon - $deg * 100) / 60;
|
|
1647
|
+
ConvertLatLon($lat, $lon) unless $ddd;
|
|
1603
1648
|
$sec = '0' . $sec unless $sec =~ /^\d{2}/; # pad integer part of seconds to 2 digits
|
|
1604
1649
|
if (defined $yr) {
|
|
1605
1650
|
my $time = sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%sZ',$yr,$mon,$day,$hr,$min,$sec);
|
|
@@ -1611,14 +1656,8 @@ sub ProcessFreeGPS($$$)
|
|
|
1611
1656
|
$et->HandleTag($tagTbl, GPSLatitude => $lat * ($latRef eq 'S' ? -1 : 1));
|
|
1612
1657
|
$et->HandleTag($tagTbl, GPSLongitude => $lon * ($lonRef eq 'W' ? -1 : 1));
|
|
1613
1658
|
$et->HandleTag($tagTbl, GPSAltitude => $alt) if defined $alt;
|
|
1614
|
-
if
|
|
1615
|
-
|
|
1616
|
-
$et->HandleTag($tagTbl, GPSSpeedRef => 'K');
|
|
1617
|
-
}
|
|
1618
|
-
if (defined $trk) {
|
|
1619
|
-
$et->HandleTag($tagTbl, GPSTrack => $trk);
|
|
1620
|
-
$et->HandleTag($tagTbl, GPSTrackRef => 'T');
|
|
1621
|
-
}
|
|
1659
|
+
$et->HandleTag($tagTbl, GPSSpeed => $spd) if defined $spd;
|
|
1660
|
+
$et->HandleTag($tagTbl, GPSTrack => $trk) if defined $trk;
|
|
1622
1661
|
while (@xtra) {
|
|
1623
1662
|
my $tag = shift @xtra;
|
|
1624
1663
|
$et->HandleTag($tagTbl, $tag => shift @xtra);
|
|
@@ -1737,9 +1776,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
|
1737
1776
|
$et->HandleTag($tagTbl, GPSLatitude => Get32s(\$b, 0x10) / 1e7);
|
|
1738
1777
|
$et->HandleTag($tagTbl, GPSLongitude => Get32s(\$b, 0x18) / 1e7);
|
|
1739
1778
|
$et->HandleTag($tagTbl, GPSSpeed => Get32s(\$b, 0x20) / 100 * $mpsToKph);
|
|
1740
|
-
$et->HandleTag($tagTbl, GPSSpeedRef => 'K');
|
|
1741
1779
|
$et->HandleTag($tagTbl, GPSTrack => $trk);
|
|
1742
|
-
$et->HandleTag($tagTbl, GPSTrackRef => 'T');
|
|
1743
1780
|
$et->HandleTag($tagTbl, GPSAltitude => Get32s(\$b, 0x28) / 1000);
|
|
1744
1781
|
$lastRecPos = $recPos;
|
|
1745
1782
|
$foundNew = 1;
|
|
@@ -1860,17 +1897,12 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
|
1860
1897
|
$trk = GetFloat(\$dat, 16);
|
|
1861
1898
|
@acc = unpack('x20V3', $dat);
|
|
1862
1899
|
map { $_ = $_ - 4294967296 if $_ >= 0x80000000 } @acc;
|
|
1863
|
-
|
|
1864
|
-
$lat = $deg + ($lat - $deg * 100) / 60;
|
|
1865
|
-
$deg = int($lon / 100);
|
|
1866
|
-
$lon = $deg + ($lon - $deg * 100) / 60;
|
|
1900
|
+
ConvertLatLon($lat, $lon);
|
|
1867
1901
|
$$et{DOC_NUM} = ++$$et{DOC_COUNT};
|
|
1868
1902
|
$et->HandleTag($tagTbl, GPSLatitude => $lat * (substr($dat,1,1) eq 'S' ? -1 : 1));
|
|
1869
1903
|
$et->HandleTag($tagTbl, GPSLongitude => $lon * (substr($dat,2,1) eq 'W' ? -1 : 1));
|
|
1870
1904
|
$et->HandleTag($tagTbl, GPSSpeed => $spd);
|
|
1871
|
-
$et->HandleTag($tagTbl, GPSSpeedRef => 'K');
|
|
1872
1905
|
$et->HandleTag($tagTbl, GPSTrack => $trk);
|
|
1873
|
-
$et->HandleTag($tagTbl, GPSTrackRef => 'T');
|
|
1874
1906
|
$et->HandleTag($tagTbl, Accelerometer => "@acc");
|
|
1875
1907
|
}
|
|
1876
1908
|
return 1;
|
|
@@ -1916,9 +1948,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
|
1916
1948
|
$et->HandleTag($tagTbl, GPSLatitude => $lat);
|
|
1917
1949
|
$et->HandleTag($tagTbl, GPSLongitude => $lon);
|
|
1918
1950
|
$et->HandleTag($tagTbl, GPSSpeed => $spd / 100 * $mpsToKph);
|
|
1919
|
-
$et->HandleTag($tagTbl, GPSSpeedRef => 'K');
|
|
1920
1951
|
$et->HandleTag($tagTbl, GPSTrack => $trk);
|
|
1921
|
-
$et->HandleTag($tagTbl, GPSTrackRef => 'T');
|
|
1922
1952
|
last if $pos += 0x20 > length($$dataPt) - 0x1e;
|
|
1923
1953
|
}
|
|
1924
1954
|
return $$et{DOC_NUM} ? 1 : 0; # return 0 if nothing extracted
|
|
@@ -1931,23 +1961,12 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
|
1931
1961
|
$yr += 2000 if $yr < 2000;
|
|
1932
1962
|
my $time = sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%.2dZ', $yr, $mon, $day, $hr, $min, $sec);
|
|
1933
1963
|
# convert from DDMM.MMMMMM to DD.DDDDDD format if necessary
|
|
1934
|
-
unless
|
|
1935
|
-
my $deg = int($lat / 100);
|
|
1936
|
-
$lat = $deg + ($lat - $deg * 100) / 60;
|
|
1937
|
-
$deg = int($lon / 100);
|
|
1938
|
-
$lon = $deg + ($lon - $deg * 100) / 60;
|
|
1939
|
-
}
|
|
1964
|
+
ConvertLatLon($lat, $lon) unless $ddd;
|
|
1940
1965
|
$et->HandleTag($tagTbl, GPSDateTime => $time);
|
|
1941
1966
|
$et->HandleTag($tagTbl, GPSLatitude => $lat * ($latRef eq 'S' ? -1 : 1));
|
|
1942
1967
|
$et->HandleTag($tagTbl, GPSLongitude => $lon * ($lonRef eq 'W' ? -1 : 1));
|
|
1943
|
-
if
|
|
1944
|
-
|
|
1945
|
-
$et->HandleTag($tagTbl, GPSSpeedRef => 'K');
|
|
1946
|
-
}
|
|
1947
|
-
if (defined $trk) {
|
|
1948
|
-
$et->HandleTag($tagTbl, GPSTrack => $trk);
|
|
1949
|
-
$et->HandleTag($tagTbl, GPSTrackRef => 'T');
|
|
1950
|
-
}
|
|
1968
|
+
$et->HandleTag($tagTbl, GPSSpeed => $spd) if defined $spd; # (now in km/h)
|
|
1969
|
+
$et->HandleTag($tagTbl, GPSTrack => $trk) if defined $trk;
|
|
1951
1970
|
if (defined $alt) {
|
|
1952
1971
|
$et->HandleTag($tagTbl, GPSAltitude => $alt);
|
|
1953
1972
|
}
|
|
@@ -1955,6 +1974,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
|
1955
1974
|
return 1;
|
|
1956
1975
|
}
|
|
1957
1976
|
|
|
1977
|
+
|
|
1958
1978
|
#------------------------------------------------------------------------------
|
|
1959
1979
|
# Extract embedded information referenced from a track
|
|
1960
1980
|
# Inputs: 0) ExifTool ref, 1) tag name, 2) data ref
|
|
@@ -2039,16 +2059,12 @@ sub ParseTag($$$)
|
|
|
2039
2059
|
SetGPSDateTime($et, $tagTbl, $a[2]);
|
|
2040
2060
|
my $lat = $a[5] / 1e3;
|
|
2041
2061
|
my $lon = $a[7] / 1e3;
|
|
2042
|
-
|
|
2043
|
-
$lat =
|
|
2044
|
-
$
|
|
2045
|
-
$lon = $deg + ($lon - $deg * 100) / 60;
|
|
2046
|
-
$lat = -$lat if $a[4] eq 'S';
|
|
2047
|
-
$lon = -$lon if $a[6] eq 'W';
|
|
2062
|
+
ConvertLatLon($lat, $lon);
|
|
2063
|
+
$lat = -abs($lat) if $a[4] eq 'S';
|
|
2064
|
+
$lon = -abs($lon) if $a[6] eq 'W';
|
|
2048
2065
|
$et->HandleTag($tagTbl, GPSLatitude => $lat);
|
|
2049
2066
|
$et->HandleTag($tagTbl, GPSLongitude => $lon);
|
|
2050
|
-
$et->HandleTag($tagTbl, GPSSpeed
|
|
2051
|
-
$et->HandleTag($tagTbl, GPSSpeedRef => 'K');
|
|
2067
|
+
$et->HandleTag($tagTbl, GPSSpeed => $a[3] / 1e3);
|
|
2052
2068
|
$pos += 36;
|
|
2053
2069
|
}
|
|
2054
2070
|
SetByteOrder('MM');
|
|
@@ -2190,20 +2206,14 @@ sub Process_gps0($$$)
|
|
|
2190
2206
|
my $lat = GetDouble($dataPt, $pos);
|
|
2191
2207
|
my $lon = GetDouble($dataPt, $pos+8);
|
|
2192
2208
|
next if abs($lat) > 9000 or abs($lon) > 18000;
|
|
2193
|
-
|
|
2194
|
-
my $deg = int($lat / 100);
|
|
2195
|
-
$lat = $deg + ($lat - $deg * 100) / 60;
|
|
2196
|
-
$deg = int($lon / 100);
|
|
2197
|
-
$lon = $deg + ($lon - $deg * 100) / 60;
|
|
2209
|
+
ConvertLatLon($lat, $lon);
|
|
2198
2210
|
my @a = unpack('C*', substr($$dataPt, $pos+22, 6)); # unpack date/time
|
|
2199
2211
|
$a[0] += 2000;
|
|
2200
2212
|
$et->HandleTag($tagTbl, GPSDateTime => sprintf("%.4d:%.2d:%.2d %.2d:%.2d:%.2dZ", @a));
|
|
2201
2213
|
$et->HandleTag($tagTbl, GPSLatitude => $lat);
|
|
2202
2214
|
$et->HandleTag($tagTbl, GPSLongitude => $lon);
|
|
2203
2215
|
$et->HandleTag($tagTbl, GPSSpeed => Get16u($dataPt, $pos+0x14));
|
|
2204
|
-
$et->HandleTag($tagTbl, GPSSpeedRef => 'K');
|
|
2205
2216
|
$et->HandleTag($tagTbl, GPSTrack => Get8u($dataPt, $pos+0x1c) * 2); # (NC)
|
|
2206
|
-
$et->HandleTag($tagTbl, GPSTrackRef => 'T');
|
|
2207
2217
|
$et->HandleTag($tagTbl, GPSAltitude => Get32s($dataPt, $pos + 0x10));
|
|
2208
2218
|
# yet to be decoded:
|
|
2209
2219
|
# 0x1d - int8u[3] seen: "1 1 0"
|
|
@@ -2292,10 +2302,7 @@ sub ProcessRIFFTrailer($$$)
|
|
|
2292
2302
|
my $lat = GetDouble(\$buff, $pos+4);
|
|
2293
2303
|
my $lon = GetDouble(\$buff, $pos+12);
|
|
2294
2304
|
$et->Warn('Bad gps0 record') and last if abs($lat) > 9000 or abs($lon) > 18000;
|
|
2295
|
-
|
|
2296
|
-
$lat = $deg + ($lat - $deg * 100) / 60;
|
|
2297
|
-
$deg = int($lon / 100);
|
|
2298
|
-
$lon = $deg + ($lon - $deg * 100) / 60;
|
|
2305
|
+
ConvertLatLon($lat, $lon);
|
|
2299
2306
|
$lat = -$lat if Get8u(\$buff, $pos+0x21) == 2; # wild guess
|
|
2300
2307
|
$lon = -$lon if Get8u(\$buff, $pos+0x22) == 2; # wild guess
|
|
2301
2308
|
my @a = unpack('C*', substr($buff, $pos+26, 6)); # unpack date/time
|
|
@@ -2305,9 +2312,7 @@ sub ProcessRIFFTrailer($$$)
|
|
|
2305
2312
|
$et->HandleTag($tagTbl, GPSLatitude => $lat);
|
|
2306
2313
|
$et->HandleTag($tagTbl, GPSLongitude => $lon);
|
|
2307
2314
|
$et->HandleTag($tagTbl, GPSSpeed => Get16u(\$buff, $pos+0x18) * $knotsToKph);
|
|
2308
|
-
$et->HandleTag($tagTbl, GPSSpeedRef => 'K');
|
|
2309
2315
|
$et->HandleTag($tagTbl, GPSTrack => Get8u(\$buff, $pos+0x20) * 2);
|
|
2310
|
-
$et->HandleTag($tagTbl, GPSTrackRef => 'T');
|
|
2311
2316
|
}
|
|
2312
2317
|
} elsif ($tag eq 'gsen') {
|
|
2313
2318
|
# (similar to record decoded in Process_gsen)
|
|
@@ -2361,17 +2366,11 @@ sub ProcessNMEA($$$)
|
|
|
2361
2366
|
$et->HandleTag($tagTbl, GPSDateTime => $fix{dat});
|
|
2362
2367
|
$et->HandleTag($tagTbl, GPSLatitude => $fix{lat});
|
|
2363
2368
|
$et->HandleTag($tagTbl, GPSLongitude => $fix{lon});
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
}
|
|
2368
|
-
|
|
2369
|
-
$et->HandleTag($tagTbl, GPSTrack => $fix{trk});
|
|
2370
|
-
$et->HandleTag($tagTbl, GPSTrackRef => 'T');
|
|
2371
|
-
}
|
|
2372
|
-
$et->HandleTag($tagTbl, GPSAltitude => $fix{alt}) if defined $fix{alt};
|
|
2373
|
-
$et->HandleTag($tagTbl, GPSSatellites => $fix{nsats}+0) if defined $fix{nsats};
|
|
2374
|
-
$et->HandleTag($tagTbl, GPSDOP => $fix{hdop}) if defined $fix{hdop};
|
|
2369
|
+
$et->HandleTag($tagTbl, GPSSpeed => $fix{spd} * $knotsToKph) if defined $fix{spd};
|
|
2370
|
+
$et->HandleTag($tagTbl, GPSTrack => $fix{trk}) if defined $fix{trk};
|
|
2371
|
+
$et->HandleTag($tagTbl, GPSAltitude => $fix{alt}) if defined $fix{alt};
|
|
2372
|
+
$et->HandleTag($tagTbl, GPSSatellites=> $fix{nsats}+0) if defined $fix{nsats};
|
|
2373
|
+
$et->HandleTag($tagTbl, GPSDOP => $fix{hdop}) if defined $fix{hdop};
|
|
2375
2374
|
}
|
|
2376
2375
|
undef %fix;
|
|
2377
2376
|
}
|
|
@@ -2525,9 +2524,7 @@ sub ProcessTTAD($$$)
|
|
|
2525
2524
|
$et->HandleTag($tagTbl, GPSLongitude => GetDouble($dataPt, $pos+0x24));
|
|
2526
2525
|
$et->HandleTag($tagTbl, GPSAltitude => GetDouble($dataPt, $pos+0x14));
|
|
2527
2526
|
$et->HandleTag($tagTbl, GPSSpeed => GetDouble($dataPt, $pos+0x0c) * $mpsToKph);
|
|
2528
|
-
$et->HandleTag($tagTbl, GPSSpeedRef => 'K');
|
|
2529
2527
|
$et->HandleTag($tagTbl, GPSTrack => GetDouble($dataPt, $pos+0x30));
|
|
2530
|
-
$et->HandleTag($tagTbl, GPSTrackRef => 'T');
|
|
2531
2528
|
if ($unknown) {
|
|
2532
2529
|
my @a = map { GetDouble($dataPt, $pos+0x38+8*$_) } 0..2;
|
|
2533
2530
|
$et->HandleTag($tagTbl, Unknown03 => "@a");
|
|
@@ -2660,15 +2657,13 @@ sub ProcessInsta360($;$)
|
|
|
2660
2657
|
$a[$_] = GetDouble(\$a[$_], 0) foreach 4,6,8,9,10;
|
|
2661
2658
|
$a[4] = -abs($a[4]) if $a[5] eq 'S'; # (abs just in case it was already signed)
|
|
2662
2659
|
$a[6] = -abs($a[6]) if $a[7] ne 'E';
|
|
2663
|
-
$et->HandleTag($tagTbl, GPSDateTime
|
|
2664
|
-
$et->HandleTag($tagTbl, GPSLatitude
|
|
2660
|
+
$et->HandleTag($tagTbl, GPSDateTime => Image::ExifTool::ConvertUnixTime($a[0]) . 'Z');
|
|
2661
|
+
$et->HandleTag($tagTbl, GPSLatitude => $a[4]);
|
|
2665
2662
|
$et->HandleTag($tagTbl, GPSLongitude => $a[6]);
|
|
2666
|
-
$et->HandleTag($tagTbl, GPSSpeed
|
|
2667
|
-
$et->HandleTag($tagTbl,
|
|
2668
|
-
$et->HandleTag($tagTbl,
|
|
2669
|
-
$et->HandleTag($tagTbl,
|
|
2670
|
-
$et->HandleTag($tagTbl, GPSAltitude => $a[10]);
|
|
2671
|
-
$et->HandleTag($tagTbl, Unknown02 => "@a[1,2]") if $unknown; # millisecond counter (https://exiftool.org/forum/index.php?topic=9884.msg65143#msg65143)
|
|
2663
|
+
$et->HandleTag($tagTbl, GPSSpeed => $a[8] * $mpsToKph);
|
|
2664
|
+
$et->HandleTag($tagTbl, GPSTrack => $a[9]);
|
|
2665
|
+
$et->HandleTag($tagTbl, GPSAltitude => $a[10]);
|
|
2666
|
+
$et->HandleTag($tagTbl, Unknown02 => "@a[1,2]") if $unknown; # millisecond counter (https://exiftool.org/forum/index.php?topic=9884.msg65143#msg65143)
|
|
2672
2667
|
}
|
|
2673
2668
|
}
|
|
2674
2669
|
} elsif ($id == 0x101) {
|
|
@@ -2724,6 +2719,41 @@ sub Process360Fly($$$)
|
|
|
2724
2719
|
return 1;
|
|
2725
2720
|
}
|
|
2726
2721
|
|
|
2722
|
+
#------------------------------------------------------------------------------
|
|
2723
|
+
# Process GPS from Vantrue N2S dashcam
|
|
2724
|
+
# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
|
|
2725
|
+
# Returns: 1 on success
|
|
2726
|
+
sub ProcessFMAS($$$)
|
|
2727
|
+
{
|
|
2728
|
+
my ($et, $dirInfo, $tagTbl) = @_;
|
|
2729
|
+
my $dataPt = $$dirInfo{DataPt};
|
|
2730
|
+
return 0 unless $$dataPt =~ /^FMAS\0\0\0\0.{72}SAMM.{36}A/s and length($$dataPt) >= 160;
|
|
2731
|
+
$et->VerboseDir('FMAS', undef, length($$dataPt));
|
|
2732
|
+
# 0000: 46 4d 41 53 00 00 00 00 00 00 00 00 00 00 00 00 [FMAS............]
|
|
2733
|
+
# 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
|
|
2734
|
+
# 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
|
|
2735
|
+
# 0030: 02 08 01 08 06 08 02 04 07 02 06 00 00 00 00 00 [................]
|
|
2736
|
+
# 0040: 00 00 00 00 00 00 00 00 4f 46 4e 49 4d 4d 41 53 [........OFNIMMAS]
|
|
2737
|
+
# 0050: 53 41 4d 4d 01 00 00 00 00 00 00 00 00 00 00 00 [SAMM............]
|
|
2738
|
+
# 0060: e5 07 09 18 08 00 22 00 02 00 00 00 a1 82 8a bf [......".........]
|
|
2739
|
+
# 0070: 89 23 8e bd 0b 2c 30 bc 41 57 4e 51 16 00 a1 01 [.#...,0.AWNQ....]
|
|
2740
|
+
# 0080: 29 26 27 0c 4b 00 49 00 00 00 00 00 00 00 00 00 [)&'.K.I.........]
|
|
2741
|
+
# 0090: 00 00 00 00 00 00 00 00 00 52 00 00 00 00 00 00 [.........R......]
|
|
2742
|
+
my @a = unpack('x96vCCCCCCx16AAACCCvCCvvv',$$dataPt);
|
|
2743
|
+
SetByteOrder('II');
|
|
2744
|
+
my $acc = ReadValue($dataPt, 0x6c, 'float', 3); # (looks like Z comes first in my sample)
|
|
2745
|
+
my $lon = $a[10] + ($a[11] + $a[13]/6000) / 60; # (why zero byte at $a[12]?)
|
|
2746
|
+
my $lat = $a[14] + ($a[15] + $a[16]/6000) / 60;
|
|
2747
|
+
$et->HandleTag($tagTbl, GPSDateTime => sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%.2d', @a[0..5]));
|
|
2748
|
+
$et->HandleTag($tagTbl, GPSLatitude => $lat * ($a[9] eq 'S' ? -1 : 1));
|
|
2749
|
+
$et->HandleTag($tagTbl, GPSLongitude => $lon * ($a[8] eq 'W' ? -1 : 1));
|
|
2750
|
+
$et->HandleTag($tagTbl, GPSSpeed => $a[17] * $mphToKph); # convert mph -> kph
|
|
2751
|
+
$et->HandleTag($tagTbl, GPSTrack => $a[18]);
|
|
2752
|
+
$et->HandleTag($tagTbl, Accelerometer=> $acc);
|
|
2753
|
+
SetByteOrder('MM');
|
|
2754
|
+
return 1;
|
|
2755
|
+
}
|
|
2756
|
+
|
|
2727
2757
|
#------------------------------------------------------------------------------
|
|
2728
2758
|
# Scan media data for "freeGPS" metadata if not found already (ref PH)
|
|
2729
2759
|
# Inputs: 0) ExifTool ref
|