exiftool_vendored 13.06.0 → 13.08.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.
- checksums.yaml +4 -4
- data/bin/Changes +29 -3
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +2 -2
- data/bin/exiftool +6 -5
- data/bin/lib/Image/ExifTool/AIFF.pm +1 -1
- data/bin/lib/Image/ExifTool/APE.pm +1 -1
- data/bin/lib/Image/ExifTool/ASF.pm +1 -1
- data/bin/lib/Image/ExifTool/BuildTagLookup.pm +4 -3
- data/bin/lib/Image/ExifTool/Canon.pm +19 -1
- data/bin/lib/Image/ExifTool/DJI.pm +1 -1
- data/bin/lib/Image/ExifTool/Exif.pm +2 -2
- data/bin/lib/Image/ExifTool/FITS.pm +2 -2
- data/bin/lib/Image/ExifTool/FLIF.pm +2 -2
- data/bin/lib/Image/ExifTool/FlashPix.pm +11 -11
- data/bin/lib/Image/ExifTool/Font.pm +1 -1
- data/bin/lib/Image/ExifTool/HP.pm +1 -1
- data/bin/lib/Image/ExifTool/ID3.pm +3 -3
- data/bin/lib/Image/ExifTool/IPTC.pm +2 -2
- data/bin/lib/Image/ExifTool/InDesign.pm +1 -1
- data/bin/lib/Image/ExifTool/Jpeg2000.pm +6 -6
- data/bin/lib/Image/ExifTool/M2TS.pm +39 -9
- data/bin/lib/Image/ExifTool/MXF.pm +2 -2
- data/bin/lib/Image/ExifTool/Matroska.pm +1 -1
- data/bin/lib/Image/ExifTool/Microsoft.pm +1 -1
- data/bin/lib/Image/ExifTool/PDF.pm +15 -15
- data/bin/lib/Image/ExifTool/PLIST.pm +1 -1
- data/bin/lib/Image/ExifTool/PNG.pm +4 -4
- data/bin/lib/Image/ExifTool/Panasonic.pm +1 -1
- data/bin/lib/Image/ExifTool/PhaseOne.pm +3 -3
- data/bin/lib/Image/ExifTool/Photoshop.pm +63 -3
- data/bin/lib/Image/ExifTool/Protobuf.pm +4 -4
- data/bin/lib/Image/ExifTool/QuickTime.pm +23 -14
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +336 -91
- data/bin/lib/Image/ExifTool/README +4 -1
- data/bin/lib/Image/ExifTool/RIFF.pm +3 -3
- data/bin/lib/Image/ExifTool/RTF.pm +1 -1
- data/bin/lib/Image/ExifTool/Ricoh.pm +3 -3
- data/bin/lib/Image/ExifTool/Sony.pm +2 -2
- data/bin/lib/Image/ExifTool/TagInfoXML.pm +4 -3
- data/bin/lib/Image/ExifTool/TagLookup.pm +6979 -6970
- data/bin/lib/Image/ExifTool/TagNames.pod +26 -5
- data/bin/lib/Image/ExifTool/VCard.pm +2 -2
- data/bin/lib/Image/ExifTool/Validate.pm +3 -3
- data/bin/lib/Image/ExifTool/WriteExif.pl +2 -2
- data/bin/lib/Image/ExifTool/WriteQuickTime.pl +4 -4
- data/bin/lib/Image/ExifTool/WriteXMP.pl +2 -2
- data/bin/lib/Image/ExifTool/Writer.pl +16 -16
- data/bin/lib/Image/ExifTool/XMP.pm +9 -9
- data/bin/lib/Image/ExifTool/ZIP.pm +1 -1
- data/bin/lib/Image/ExifTool.pm +58 -57
- data/bin/lib/Image/ExifTool.pod +1 -1
- data/bin/perl-Image-ExifTool.spec +1 -1
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +2 -2
@@ -94,6 +94,7 @@ my %insvDataLen = (
|
|
94
94
|
# 0xb00 => 10, # ? (Insta360 X3)
|
95
95
|
# 0xd00 => 10, # ? (Insta360 Ace Pro)
|
96
96
|
# 0x1200 ? # ? (Insta360 Ace Pro)
|
97
|
+
# 0x1600 ? # ? (?)
|
97
98
|
);
|
98
99
|
|
99
100
|
# limit the default amount of data we read for some record types
|
@@ -109,7 +110,7 @@ my %insvLimit = (
|
|
109
110
|
The tags below are extracted from timed metadata in QuickTime and other
|
110
111
|
formats of video files when the ExtractEmbedded option is used. Although
|
111
112
|
most of these tags are combined into the single table below, ExifTool
|
112
|
-
currently reads
|
113
|
+
currently reads 96 different types of timed GPS metadata from video files.
|
113
114
|
},
|
114
115
|
VARS => { NO_ID => 1 },
|
115
116
|
GPSLatitude => { PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', RawConv => '$$self{FoundGPSLatitude} = 1; $val' },
|
@@ -353,6 +354,8 @@ my %insvLimit = (
|
|
353
354
|
Unknown01 => { Unknown => 1 },
|
354
355
|
Unknown02 => { Unknown => 1 },
|
355
356
|
Unknown03 => { Unknown => 1 },
|
357
|
+
M => { Name => 'Unknown_M', Unknown => 1 }, # (from LIGOGPSINFO)
|
358
|
+
H => { Name => 'Unknown_H', Unknown => 1 }, # (from LIGOGPSINFO)
|
356
359
|
);
|
357
360
|
|
358
361
|
# tags found in 'camm' type 0 timed metadata (ref 4)
|
@@ -911,9 +914,9 @@ sub SetGPSDateTime($$$;$)
|
|
911
914
|
if ($$et{CreateDateAtEnd}) { # adjust if CreateDate is at end of video
|
912
915
|
return unless $$value{TimeScale} and $$value{Duration};
|
913
916
|
$sampleTime -= $$value{Duration} / $$value{TimeScale};
|
914
|
-
$et->
|
917
|
+
$et->Warn('Approximating GPSDateTime as CreateDate - Duration + SampleTime', 1);
|
915
918
|
} else {
|
916
|
-
$et->
|
919
|
+
$et->Warn('Approximating GPSDateTime as CreateDate + SampleTime', 1);
|
917
920
|
}
|
918
921
|
my $utc = $et->Options('QuickTimeUTC');
|
919
922
|
$utc = $isUTC unless defined $utc; # (allow QuickTimeUTC=0 to override $isUTC default)
|
@@ -1274,7 +1277,7 @@ sub ProcessSamples($)
|
|
1274
1277
|
($startChunk, $samplesPerChunk, $descIdx) = @{shift @$stsc};
|
1275
1278
|
$nextChunk = $$stsc[0][0] if @$stsc;
|
1276
1279
|
}
|
1277
|
-
@$size < @$start + $samplesPerChunk and $et->
|
1280
|
+
@$size < @$start + $samplesPerChunk and $et->Warn('Sample size error'), last;
|
1278
1281
|
last unless defined $chunkStart and length $chunkStart;
|
1279
1282
|
my $sampleStart = $chunkStart;
|
1280
1283
|
my $chunkSize = 0;
|
@@ -1302,7 +1305,7 @@ Sample: for ($i=0; ; ) {
|
|
1302
1305
|
push @chunkSize, $chunkSize;
|
1303
1306
|
++$iChunk;
|
1304
1307
|
}
|
1305
|
-
@$start == @$size or $et->
|
1308
|
+
@$start == @$size or $et->Warn('Incorrect sample start/size count'), return;
|
1306
1309
|
# process as chunks if we are only interested in calculating hash
|
1307
1310
|
if ($type eq 'soun' or $type eq 'vide') {
|
1308
1311
|
$start = $stco;
|
@@ -1332,7 +1335,7 @@ Sample: for ($i=0; ; ) {
|
|
1332
1335
|
$hdrFmt = ($hdrLen == 4 ? 'N' : $hdrLen == 2 ? 'n' : 'C');
|
1333
1336
|
require Image::ExifTool::H264;
|
1334
1337
|
}
|
1335
|
-
|
1338
|
+
|
1336
1339
|
# loop through all samples
|
1337
1340
|
for ($i=0; $i<@$start and $i<@$size; ++$i) {
|
1338
1341
|
|
@@ -1352,11 +1355,11 @@ Sample: for ($i=0; ; ) {
|
|
1352
1355
|
}
|
1353
1356
|
}
|
1354
1357
|
# read the sample data
|
1355
|
-
$raf->Seek($$start[$i], 0) or $et->
|
1358
|
+
$raf->Seek($$start[$i], 0) or $et->Warn("Seek error in $type data"), next;
|
1356
1359
|
my $buff;
|
1357
1360
|
my $n = $raf->Read($buff, $size);
|
1358
1361
|
unless ($n == $size) {
|
1359
|
-
$et->
|
1362
|
+
$et->Warn("Error reading $type data");
|
1360
1363
|
next unless $n;
|
1361
1364
|
$size = $n;
|
1362
1365
|
}
|
@@ -1560,7 +1563,7 @@ sub ProcessFreeGPS($$$)
|
|
1560
1563
|
my ($et, $dirInfo, $tagTbl) = @_;
|
1561
1564
|
my $dataPt = $$dirInfo{DataPt};
|
1562
1565
|
my $dirLen = length $$dataPt;
|
1563
|
-
my ($yr, $mon, $day, $hr, $min, $sec, $stat, $lbl, $ddd);
|
1566
|
+
my ($yr, $mon, $day, $hr, $min, $sec, $ss, $stat, $lbl, $ddd, $done);
|
1564
1567
|
my ($lat, $latRef, $lon, $lonRef, $spd, $trk, $alt, @acc, @xtra);
|
1565
1568
|
|
1566
1569
|
return 0 if $dirLen < 82;
|
@@ -1699,7 +1702,7 @@ sub ProcessFreeGPS($$$)
|
|
1699
1702
|
($sec,$min,$hr,$day,$mon,$yr) = gmtime($time);
|
1700
1703
|
$yr += 1900;
|
1701
1704
|
++$mon;
|
1702
|
-
$et->
|
1705
|
+
$et->Warn('Converting GPSDateTime to UTC based on local time zone',1);
|
1703
1706
|
}
|
1704
1707
|
$lat = GetFloat($dataPt, 0x2c);
|
1705
1708
|
$lon = GetFloat($dataPt, 0x30);
|
@@ -1744,36 +1747,69 @@ sub ProcessFreeGPS($$$)
|
|
1744
1747
|
($lon = DecryptLucky($ln, $key)) =~ /^\d{1,5}\.\d+$/ or undef($lon), next;
|
1745
1748
|
last;
|
1746
1749
|
}
|
1747
|
-
$lon or $et->
|
1750
|
+
$lon or $et->Warn('Unknown encryption for latitude/longitude');
|
1748
1751
|
}
|
1749
1752
|
}
|
1750
1753
|
|
1751
|
-
} elsif ($$dataPt =~
|
1754
|
+
} elsif ($$dataPt =~ /^(.{16}|.{48}|.{80})LIGOGPSINFO\0/s and length($$dataPt) >= length($1) + 0x84) {
|
1752
1755
|
|
1753
1756
|
$debug and $et->FoundTag(GPSType => 5);
|
1754
|
-
|
1755
|
-
#
|
1756
|
-
#
|
1757
|
-
#
|
1758
|
-
#
|
1759
|
-
#
|
1760
|
-
#
|
1761
|
-
#
|
1762
|
-
#
|
1763
|
-
|
1764
|
-
|
1765
|
-
#
|
1766
|
-
|
1767
|
-
|
1768
|
-
|
1769
|
-
|
1770
|
-
|
1771
|
-
|
1772
|
-
|
1773
|
-
|
1774
|
-
|
1775
|
-
|
1776
|
-
|
1757
|
+
my $pos = length $1;
|
1758
|
+
# iiway s1 dual dash cam
|
1759
|
+
# 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 03 00 00 [..@.freeGPS ....]
|
1760
|
+
# 0010: 4c 49 47 4f 47 50 53 49 4e 46 4f 00 00 00 00 05 [LIGOGPSINFO.....]
|
1761
|
+
# 0020: 0a 00 00 00 23 23 23 23 6a 00 00 00 c0 20 20 20 [....####j.... ]
|
1762
|
+
# 0030: 20 f0 12 10 12 22 e1 0e 10 12 2f 90 10 13 02 f2 [ ...."..../.....]
|
1763
|
+
# ABASK A8 4K Dashcam (different scaling factor)
|
1764
|
+
# 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 03 00 00 [..@.freeGPS ....]
|
1765
|
+
# 0010: 4c 49 47 4f 47 50 53 49 4e 46 4f 00 00 00 00 05 [LIGOGPSINFO.....]
|
1766
|
+
# 0020: 00 00 00 00 23 23 23 23 69 00 00 00 c0 20 20 20 [....####i.... ]
|
1767
|
+
# 0030: 20 f0 12 10 12 23 e5 0e 10 12 2f 99 10 11 02 f2 [ ....#..../.....]
|
1768
|
+
# XGODY 12" 4K Dashcam
|
1769
|
+
# 0000: 00 00 00 a8 66 72 65 65 47 50 53 20 98 00 00 00 [....freeGPS ....]
|
1770
|
+
# 0010: 4c 49 47 4f 47 50 53 49 4e 46 4f 00 00 00 00 05 [LIGOGPSINFO.....]
|
1771
|
+
# 0020: cd 61 00 00 23 23 23 23 6d 00 00 00 c1 ec 41 20 [.a..####m.....A ]
|
1772
|
+
# 0030: 20 f0 12 10 12 24 e5 0e 10 11 2f 92 10 12 00 f6 [ ....$..../.....]
|
1773
|
+
# Rexing dashcam V1GW-4K
|
1774
|
+
# 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 03 00 00 [..@.freeGPS ....]
|
1775
|
+
# 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
|
1776
|
+
# 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
|
1777
|
+
# 0030: 4c 49 47 4f 47 50 53 49 4e 46 4f 00 00 00 00 05 [LIGOGPSINFO.....]
|
1778
|
+
# 0040: 01 00 00 00 23 23 23 23 73 00 00 00 c0 20 20 20 [....####s.... ]
|
1779
|
+
# 0050: 20 f0 12 10 12 23 e5 0e 10 12 2f 95 10 12 01 f3 [ ....#..../.....]
|
1780
|
+
# 0060: 16 18 10 26 b4 1a 10 04 f2 6e 18 12 20 f0 0e 11 [...&.....n.. ...]
|
1781
|
+
# 0070: 13 22 b3 16 10 01 fb 76 18 10 24 fa 0e 11 10 22 [.".....v..$...."]
|
1782
|
+
# Kingslim D4 dashcam
|
1783
|
+
# 0000: 0a 00 00 00 0b 00 00 00 07 00 00 00 e5 07 00 00 [................]
|
1784
|
+
# 0010: 06 00 00 00 03 00 00 00 41 4e 57 31 91 52 83 45 [........ANW1.R.E]
|
1785
|
+
# 0020: 15 70 fe c5 29 5c c3 41 ae c7 af 42 00 00 d1 be [.p..)\.A...B....]
|
1786
|
+
# 0030: 00 00 80 3b 00 00 2c 3e 00 00 00 00 00 00 00 00 [...;..,>........]
|
1787
|
+
# 0040: 00 00 00 00 00 00 00 00 00 00 00 00 26 26 26 26 [............&&&&]
|
1788
|
+
# 0050: 4c 49 47 4f 47 50 53 49 4e 46 4f 00 00 00 00 05 [LIGOGPSINFO.....]
|
1789
|
+
# 0060: 01 00 00 00 23 23 23 23 75 00 00 00 c0 22 20 20 [....####u...." ]
|
1790
|
+
# 0070: 20 f0 12 10 12 21 e5 0e 10 12 2f 90 10 13 01 f2 [ ....!..../.....]
|
1791
|
+
my %dirInfo = ( DataPt => $dataPt, DirStart => $pos, DirName => "LigoGPS_$pos" );
|
1792
|
+
# (this is weak, but the only difference I could find between these 2 headers)
|
1793
|
+
# (NOTE: ../testpics/gps_video/forum16229.mp4 uses this word for a counter!)
|
1794
|
+
$$et{LigoGPSScale} = 3 if $pos == 16 and $$dataPt =~ /^.{12}\xf0\x03\0\0.{16}\0{4}/s;
|
1795
|
+
ProcessLigoGPS($et, \%dirInfo, $tagTbl);
|
1796
|
+
$done = 1;
|
1797
|
+
|
1798
|
+
# also... when offset is 0x50 (Kingslim), the GPS also exists in this format:
|
1799
|
+
# ($latRef, $lonRef) = ($1, $2);
|
1800
|
+
# ($hr,$min,$sec,$yr,$mon,$day) = unpack("V6", $$dataPt);
|
1801
|
+
# # lat/lon aren't decoded properly, but spd,trk,acc are
|
1802
|
+
# $lat = GetFloat($dataPt, 0x1c);
|
1803
|
+
# $lon = GetFloat($dataPt, 0x20);
|
1804
|
+
# $et->VPrint(0, sprintf("Raw lat/lon = %.9f %.9f\n", $lat, $lon));
|
1805
|
+
# $et->Warn('GPSLatitude/Longitude encryption is not yet known, so these will be wrong');
|
1806
|
+
# $lat = abs $lat;
|
1807
|
+
# $lon = abs $lon;
|
1808
|
+
# $spd = GetFloat($dataPt, 0x24) * $knotsToKph; # (convert knots to km/h)
|
1809
|
+
# $trk = GetFloat($dataPt, 0x28);
|
1810
|
+
# $acc[0] = GetFloat($dataPt, 0x2c);
|
1811
|
+
# $acc[1] = GetFloat($dataPt, 0x30);
|
1812
|
+
# $acc[2] = GetFloat($dataPt, 0x34);
|
1777
1813
|
|
1778
1814
|
} elsif ($$dataPt =~ /^.{60}A\0{3}.{4}([NS])\0{3}.{4}([EW])\0{3}/s) {
|
1779
1815
|
|
@@ -1821,14 +1857,14 @@ sub ProcessFreeGPS($$$)
|
|
1821
1857
|
# 0060: 42 3e 49 49 40 42 45 3c 55 3c 45 47 3e 45 43 41 [B>II@BE<U<EG>ECA]
|
1822
1858
|
# decipher $GPRMC by subtracting 16 from each character value
|
1823
1859
|
$_ = pack 'C*', map { $_>=16 and $_-=16 } unpack('x60C80', $$dataPt);
|
1824
|
-
|
1825
|
-
|
1826
|
-
|
1860
|
+
if (/[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+)/) {
|
1861
|
+
($yr,$mon,$day,$hr,$min,$sec,$lat,$latRef,$lon,$lonRef) = ($13,$12,$11,$1,$2,$3,$5,$6,$7,$8);
|
1862
|
+
$yr += ($yr >= 70 ? 1900 : 2000);
|
1863
|
+
$spd = $9 * $knotsToKph if length $9;
|
1864
|
+
$trk = $10 if length $10;
|
1865
|
+
} else {
|
1866
|
+
$done = 1;
|
1827
1867
|
}
|
1828
|
-
($yr,$mon,$day,$hr,$min,$sec,$lat,$latRef,$lon,$lonRef) = ($13,$12,$11,$1,$2,$3,$5,$6,$7,$8);
|
1829
|
-
$yr += ($yr >= 70 ? 1900 : 2000);
|
1830
|
-
$spd = $9 * $knotsToKph if length $9;
|
1831
|
-
$trk = $10 if length $10;
|
1832
1868
|
|
1833
1869
|
} elsif ($$dataPt =~ /^.{64}[\x01-\x0c]\0{3}[\x01-\x1f]\0{3}A[NS][EW]\0{5}/s) {
|
1834
1870
|
|
@@ -1857,7 +1893,7 @@ sub ProcessFreeGPS($$$)
|
|
1857
1893
|
($hr,$min,$sec,$yr,$mon,$day,$stat,$latRef,$lonRef) =
|
1858
1894
|
unpack('x48V6a1a1a1x1', $$dataPt);
|
1859
1895
|
|
1860
|
-
$et->
|
1896
|
+
$et->Warn('GPSLatitude/Longitude encryption is not yet known, so these will be wrong');
|
1861
1897
|
# (see https://exiftool.org/forum/index.php?topic=11320.0)
|
1862
1898
|
|
1863
1899
|
$spd = GetFloat($dataPt, 0x60);
|
@@ -1865,7 +1901,7 @@ sub ProcessFreeGPS($$$)
|
|
1865
1901
|
$lat = GetDouble($dataPt, 0x50); # latitude is here, but encrypted somehow
|
1866
1902
|
$lon = GetDouble($dataPt, 0x58); # longitude is here, but encrypted somehow
|
1867
1903
|
$ddd = 1; # don't convert until we know what the format is
|
1868
|
-
#my $serialNum = substr($$dataPt, 0x68, 20);
|
1904
|
+
#my $serialNum = substr($$dataPt, 0x68, 20); # (confirmed)
|
1869
1905
|
|
1870
1906
|
} elsif ($$dataPt =~ /^.{12}\xac\0\0\0.{44}(.{72})/s) {
|
1871
1907
|
|
@@ -1881,15 +1917,14 @@ sub ProcessFreeGPS($$$)
|
|
1881
1917
|
# 0070: 43 41 3c 40 42 40 46 42 40 3c 3c 3c 51 3a 47 46 [CA<@B@FB@<<<Q:GF]
|
1882
1918
|
# 0080: 00 2a 36 35 00 00 00 00 00 00 00 00 00 00 00 00 [.*65............]
|
1883
1919
|
|
1884
|
-
$et->
|
1920
|
+
$et->Warn("Can't yet decrypt EACHPAI timed GPS", 1);
|
1885
1921
|
# (see https://exiftool.org/forum/index.php?topic=5095.msg61266#msg61266)
|
1886
|
-
|
1887
|
-
return 1;
|
1922
|
+
$done = 1;
|
1888
1923
|
|
1889
|
-
|
1890
|
-
|
1891
|
-
|
1892
|
-
|
1924
|
+
# my $time = pack 'C*', map { $_ ^= 0 } unpack 'C*', $1;
|
1925
|
+
# # bytes 7-12 are the timestamp in ASCII HHMMSS after xor-ing with 0x70
|
1926
|
+
# substr($time,7,6) = pack 'C*', map { $_ ^= 0x70 } unpack 'C*', substr($time,7,6);
|
1927
|
+
# # (other values are currently unknown)
|
1893
1928
|
|
1894
1929
|
} elsif ($$dataPt =~ /^.{64}A([NS])([EW])\0/s) {
|
1895
1930
|
|
@@ -1905,17 +1940,17 @@ sub ProcessFreeGPS($$$)
|
|
1905
1940
|
# 0070: 05 00 00 00 7f 00 00 00 07 01 00 00 00 00 00 00 [................]
|
1906
1941
|
($latRef, $lonRef) = ($1, $2);
|
1907
1942
|
($yr,$mon,$day,$hr,$min,$sec,@acc) = unpack('x68V6x20V3', $$dataPt);
|
1908
|
-
|
1909
|
-
|
1910
|
-
|
1943
|
+
if ($mon>=1 and $mon<=12 and $day>=1 and $day<=31) {
|
1944
|
+
# (not sure about acc scaling)
|
1945
|
+
@acc = map { SignedInt32 / 1000 } @acc;
|
1946
|
+
$lon = GetFloat($dataPt, 0x5c);
|
1947
|
+
$lat = GetFloat($dataPt, 0x60);
|
1948
|
+
$spd = GetFloat($dataPt, 0x64) * $knotsToKph;
|
1949
|
+
$trk = GetFloat($dataPt, 0x68);
|
1950
|
+
$alt = GetFloat($dataPt, 0x6c);
|
1951
|
+
} else {
|
1952
|
+
$done = 1;
|
1911
1953
|
}
|
1912
|
-
# (not sure about acc scaling)
|
1913
|
-
@acc = map { SignedInt32 / 1000 } @acc;
|
1914
|
-
$lon = GetFloat($dataPt, 0x5c);
|
1915
|
-
$lat = GetFloat($dataPt, 0x60);
|
1916
|
-
$spd = GetFloat($dataPt, 0x64) * $knotsToKph;
|
1917
|
-
$trk = GetFloat($dataPt, 0x68);
|
1918
|
-
$alt = GetFloat($dataPt, 0x6c);
|
1919
1954
|
|
1920
1955
|
} elsif (substr($$dataPt,0x45,3) eq 'ATC') {
|
1921
1956
|
|
@@ -1960,7 +1995,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
1960
1995
|
my $i;
|
1961
1996
|
for ($i=0; $i<@dateMax; ++$i) {
|
1962
1997
|
next if $now[$i] <= $dateMax[$i];
|
1963
|
-
$et->
|
1998
|
+
$et->Warn('Invalid GPS date/time');
|
1964
1999
|
next ATCRec; # ignore this record
|
1965
2000
|
}
|
1966
2001
|
# look for next ATC record in temporal sequence
|
@@ -2027,8 +2062,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
2027
2062
|
}
|
2028
2063
|
# save position of most recent record (needed when parsing the next freeGPS block)
|
2029
2064
|
$$et{FreeGPS2}{RecentRecPos} = $lastRecPos;
|
2030
|
-
|
2031
|
-
return 1;
|
2065
|
+
$done = 1;
|
2032
2066
|
|
2033
2067
|
} elsif ($$dataPt =~ /^.{60}A\0.{10}([NS])\0.{14}([EW])\0/s and $dirLen >= 0x88) {
|
2034
2068
|
|
@@ -2065,6 +2099,11 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
2065
2099
|
|
2066
2100
|
$debug and $et->FoundTag(GPSType => 13);
|
2067
2101
|
# INNOVV MP4 video (same format as INNOVV TS)
|
2102
|
+
# 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 03 00 00 [..@.freeGPS ....]
|
2103
|
+
# 0010: 41 4e 45 00 e4 56 96 45 86 b1 ca 44 5c 8f e2 40 [ANE..V.E...D\..@]
|
2104
|
+
# 0020: 33 33 58 43 c3 00 00 00 30 00 00 00 a0 fe ff ff [33XC....0.......]
|
2105
|
+
# 0030: 41 4e 45 00 e3 56 96 45 82 b1 ca 44 5c 8f fa 40 [ANE..V.E...D\..@]
|
2106
|
+
# 0040: c3 75 56 43 8c ff ff ff 8c 00 00 00 c3 fd ff ff [.uVC............]
|
2068
2107
|
while ($$dataPt =~ /(A[NS][EW]\0.{28})/sg) {
|
2069
2108
|
my $dat = $1;
|
2070
2109
|
$lat = abs(GetFloat(\$dat, 4)); # (abs just to be safe)
|
@@ -2080,10 +2119,9 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
2080
2119
|
$et->HandleTag($tagTbl, GPSTrack => $trk);
|
2081
2120
|
$et->HandleTag($tagTbl, Accelerometer => "@acc");
|
2082
2121
|
}
|
2083
|
-
|
2084
|
-
return 1;
|
2122
|
+
$done = 1;
|
2085
2123
|
|
2086
|
-
} elsif ($$dataPt =~ /^.{
|
2124
|
+
} elsif ($$dataPt =~ /^.{20}[\0-\x18][\0-\x3b]{2}[\0-\x09]A([NS])([EW])/s) {
|
2087
2125
|
|
2088
2126
|
$debug and $et->FoundTag(GPSType => 14);
|
2089
2127
|
# XBHT motorcycle dashcam Model XB702
|
@@ -2092,12 +2130,11 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
2092
2130
|
# 0020: 44 3d c5 02 48 6d ff 07 df 03 00 00 6b 00 00 00 [D=..Hm......k...]
|
2093
2131
|
# 0030: 00 00 00 00 00 17 05 11 0d 25 18 01 41 4e 45 64 [.........%..ANEd]
|
2094
2132
|
# 0040: 8b 3f 00 00 30 3d c5 02 50 6d ff 07 df 03 00 00 [.?..0=..Pm......]
|
2095
|
-
while ($$dataPt =~ /(.{
|
2133
|
+
while ($$dataPt =~ /(.{7}[\0-\x09]A[NS][EW].{25})/sg) {
|
2096
2134
|
my $dat = $1;
|
2097
|
-
|
2135
|
+
($yr,$mon,$day,$hr,$min,$sec,$ss,$latRef,$lonRef,$lat,$lon,$spd) =
|
2098
2136
|
unpack('xC7xCCx5VVx4v', $dat);
|
2099
2137
|
$yr += 2000; $lat /= 1e4; $lon /= 1e4;
|
2100
|
-
$ss = 0 if $ss > 9; # (just in case)
|
2101
2138
|
ConvertLatLon($lat, $lon);
|
2102
2139
|
$$et{DOC_NUM} = ++$$et{DOC_COUNT};
|
2103
2140
|
my $time = sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%.2d.%d',$yr,$mon,$day,$hr,$min,$sec,$ss);
|
@@ -2106,8 +2143,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
2106
2143
|
$et->HandleTag($tagTbl, GPSLongitude => $lon * ($lonRef eq 'W' ? -1 : 1));
|
2107
2144
|
$et->HandleTag($tagTbl, GPSSpeed => $spd);
|
2108
2145
|
}
|
2109
|
-
|
2110
|
-
return 1;
|
2146
|
+
$done = 1;
|
2111
2147
|
|
2112
2148
|
} elsif ($$dataPt =~ /^.{28}A.{11}([NS]).{15}([EW])/s) {
|
2113
2149
|
|
@@ -2231,7 +2267,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
2231
2267
|
}
|
2232
2268
|
|
2233
2269
|
} elsif ($$dataPt =~ m/^.{30}A.{20}VV/) {
|
2234
|
-
|
2270
|
+
|
2235
2271
|
$debug and $et->FoundTag(GPSType => 19);
|
2236
2272
|
# 70mai A810 dashcam (note: no timestamps in the samples I have)
|
2237
2273
|
# 0000: 00 00 40 00 66 72 65 65 47 50 53 20 ed 01 00 00 [..@.freeGPS ....]
|
@@ -2295,14 +2331,14 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
2295
2331
|
$et->HandleTag($tagTbl, GPSTrack => $trk);
|
2296
2332
|
last if $pos += 0x20 > length($$dataPt) - 0x1e;
|
2297
2333
|
}
|
2298
|
-
|
2299
|
-
return $$et{DOC_NUM} ? 1 : 0; # return 0 if nothing extracted
|
2334
|
+
$done = 1;
|
2300
2335
|
}
|
2336
|
+
SetByteOrder($oldOrder);
|
2337
|
+
return $$et{DOC_NUM} ? 1 : 0 if $done;
|
2338
|
+
return 0 if defined $yr and $mon < 1 or $mon > 12; # quick sanity check
|
2301
2339
|
#
|
2302
2340
|
# save tag values extracted by above code
|
2303
2341
|
#
|
2304
|
-
SetByteOrder($oldOrder);
|
2305
|
-
return 0 if defined $yr and $mon < 1 or $mon > 12; # quick sanity check
|
2306
2342
|
FoundSomething($et, $tagTbl, $$dirInfo{SampleTime}, $$dirInfo{SampleDuration});
|
2307
2343
|
$sec = '0' . $sec unless $sec =~ /^\d{2}/; # pad integer part of seconds to 2 digits
|
2308
2344
|
if (defined $yr) {
|
@@ -2442,8 +2478,8 @@ sub Process_tx3g($$$)
|
|
2442
2478
|
if ($text =~ /^HOME\(/) {
|
2443
2479
|
# --- sample text from Autel Evo II drone ---
|
2444
2480
|
# HOME(W: 109.318642, N: 40.769371) 2023-09-12 10:28:07
|
2445
|
-
# GPS(W: 109.339287, N: 40.768574, 2371.76m)
|
2446
|
-
# HDR ISO:100 SHUTTER:1000 EV:-0.7 F-NUM:1.8
|
2481
|
+
# GPS(W: 109.339287, N: 40.768574, 2371.76m)
|
2482
|
+
# HDR ISO:100 SHUTTER:1000 EV:-0.7 F-NUM:1.8
|
2447
2483
|
# F.PRY (1.0\xc2\xb0, -3.7\xc2\xb0, -59.0\xc2\xb0), G.PRY (-51.1\xc2\xb0, 0.0\xc2\xb0, -58.9\xc2\xb0)
|
2448
2484
|
my $line;
|
2449
2485
|
foreach $line (split /\x0a/, $text) {
|
@@ -2520,7 +2556,7 @@ sub Process_mebx($$$)
|
|
2520
2556
|
Size => $len - 8,
|
2521
2557
|
);
|
2522
2558
|
} else {
|
2523
|
-
$et->
|
2559
|
+
$et->Warn('No key information for mebx ID ' . PrintableTagID($id,1));
|
2524
2560
|
}
|
2525
2561
|
}
|
2526
2562
|
return 1;
|
@@ -2643,7 +2679,7 @@ sub Process_gdat($$$)
|
|
2643
2679
|
{
|
2644
2680
|
my ($et, $dirInfo, $tagTbl) = @_;
|
2645
2681
|
unless ($$et{OPTIONS}{ExtractEmbedded}) {
|
2646
|
-
$et->
|
2682
|
+
$et->Warn('Use the ExtractEmbedded option to extract timed GPSData',3);
|
2647
2683
|
return 0;
|
2648
2684
|
}
|
2649
2685
|
my $dataPt = $$dirInfo{DataPt};
|
@@ -2694,13 +2730,220 @@ sub Process_nbmt($$$)
|
|
2694
2730
|
delete $$et{NoMoreTextDecoding};
|
2695
2731
|
delete $$et{DOC_NUM};
|
2696
2732
|
} else {
|
2697
|
-
$et->
|
2733
|
+
$et->Warn('Use the ExtractEmbedded option to extract timed GPSData',3);
|
2734
|
+
}
|
2735
|
+
return 1;
|
2736
|
+
}
|
2737
|
+
|
2738
|
+
#------------------------------------------------------------------------------
|
2739
|
+
# Un-do LIGOGPS fuzzing
|
2740
|
+
# Inputs: 0) fuzzed latitude, 1) fuzzed longitude, 2) scale factor
|
2741
|
+
# Returns: 0) latitude, 1) longitude
|
2742
|
+
sub UnfuzzLigoGPS($$$)
|
2743
|
+
{
|
2744
|
+
my ($lat, $lon, $scl) = @_;
|
2745
|
+
my $lat2 = int($lat / 10) * 10;
|
2746
|
+
my $lon2 = int($lon / 10) * 10;
|
2747
|
+
return($lat2 + ($lon - $lon2) * $scl, $lon2 + ($lat - $lat2) * $scl);
|
2748
|
+
}
|
2749
|
+
|
2750
|
+
#------------------------------------------------------------------------------
|
2751
|
+
# Decrypt LIGOGPSINFO record (starting with "####")
|
2752
|
+
# Inputs: 0) encrypted GPS record incuding 8-byte header
|
2753
|
+
# Returns: decrypted record including 4-byte uint32 header, or undef on error
|
2754
|
+
sub DecryptLigoGPS($)
|
2755
|
+
{
|
2756
|
+
my $str = shift;
|
2757
|
+
my $num = unpack('x4V',$str);
|
2758
|
+
return undef if $num < 4;
|
2759
|
+
$num = 0x84 if $num > 0x84; # (be safe)
|
2760
|
+
my @in = unpack("x8C$num",$str);
|
2761
|
+
my @out;
|
2762
|
+
while (@in) {
|
2763
|
+
my $b = shift @in;
|
2764
|
+
my $steeringBits = $b & 0xe0;
|
2765
|
+
if ($steeringBits >= 0xc0) {
|
2766
|
+
return undef if @in < 4;
|
2767
|
+
push @out, (shift(@in) | $b & 0x01) ^ 0x20,
|
2768
|
+
(shift(@in) | $b & 0x02) ^ 0x20,
|
2769
|
+
(shift(@in) | $b & 0x0c) ^ 0x20,
|
2770
|
+
shift(@in) ^ 0x20 | $b & 0x30;
|
2771
|
+
} elsif ($steeringBits >= 0x40) {
|
2772
|
+
return undef if @in < 3;
|
2773
|
+
if ($steeringBits == 0x40) {
|
2774
|
+
push @out, 0x20,
|
2775
|
+
(shift(@in) | $b & 0x01) ^ 0x20,
|
2776
|
+
(shift(@in) | $b & 0x06) ^ 0x20,
|
2777
|
+
(shift(@in) | $b & 0x18) ^ 0x20;
|
2778
|
+
} elsif ($steeringBits == 0x60) {
|
2779
|
+
push @out, (shift(@in) | $b & 0x03) ^ 0x20,
|
2780
|
+
0x20,
|
2781
|
+
(shift(@in) | $b & 0x04) ^ 0x20,
|
2782
|
+
(shift(@in) | $b & 0x18) ^ 0x20;
|
2783
|
+
} elsif ($steeringBits == 0x80) {
|
2784
|
+
push @out, (shift(@in) | $b & 0x03) ^ 0x20,
|
2785
|
+
(shift(@in) | $b & 0x0c) ^ 0x20,
|
2786
|
+
0x20,
|
2787
|
+
(shift(@in) | $b & 0x10) ^ 0x20;
|
2788
|
+
} else {
|
2789
|
+
push @out, (shift(@in) | $b & 0x01) ^ 0x20,
|
2790
|
+
(shift(@in) | $b & 0x06) ^ 0x20,
|
2791
|
+
(shift(@in) | $b & 0x18) ^ 0x20,
|
2792
|
+
0x20;
|
2793
|
+
}
|
2794
|
+
} elsif ($steeringBits == 0x00) {
|
2795
|
+
return undef if @in < 1;
|
2796
|
+
push @out, shift(@in) | $b & 0x13;
|
2797
|
+
} else {
|
2798
|
+
return undef; # (shouldn't happen)
|
2799
|
+
}
|
2800
|
+
}
|
2801
|
+
return pack 'C*', @out;
|
2802
|
+
}
|
2803
|
+
|
2804
|
+
#------------------------------------------------------------------------------
|
2805
|
+
# Decipher and parse LIGOGPSINFO record (starting with "####")
|
2806
|
+
# Inputs: 0) ExifTool ref, 1) enciphered string, 2) tag table ref
|
2807
|
+
# Returns: true if this looked like an enciphered string
|
2808
|
+
# Notes: handles contained tags, but may defer handling until full cipher is known
|
2809
|
+
sub DecipherLigoGPS($$$)
|
2810
|
+
{
|
2811
|
+
my ($et, $str, $tagTbl) = @_;
|
2812
|
+
|
2813
|
+
# (enciphered characters must be in the range 0x30-0x5f ('0' - '_'))
|
2814
|
+
$str =~ m[^####.{4}([0-_])[0-_]{3}/[0-_]{2}/[0-_]{2} ..([0-_])..([0-_]).([0-_]) ]s or return undef;
|
2815
|
+
return undef unless $2 eq $3; # (colons in time string must be the same)
|
2816
|
+
|
2817
|
+
my $cipherInfo = $$et{LigoCipher};
|
2818
|
+
$cipherInfo or $cipherInfo = $$et{LigoCipher} = { cache => [ ], secs => [ ], two => -1 };
|
2819
|
+
my $decipher = $$cipherInfo{decipher};
|
2820
|
+
my $cache = $$cipherInfo{cache};
|
2821
|
+
|
2822
|
+
# determine the cipher code table based on the advancing 1's digit of seconds
|
2823
|
+
unless ($decipher) {
|
2824
|
+
push @$cache, $str; # cache records until we can decipher them
|
2825
|
+
my ($millennium, $colon) = ($1, $2);
|
2826
|
+
# determine the Caesar cipher lookup table
|
2827
|
+
# (only characters in range 0x30-0x5f are encrypted)
|
2828
|
+
my $secs = $$cipherInfo{secs};
|
2829
|
+
push @$secs, $4 unless @$secs and $${secs}[-1] eq $4;
|
2830
|
+
$$cipherInfo{two} = $#$secs if $4 eq $millennium; # save index of enciphered '2'
|
2831
|
+
return 1 if @$secs < 10; # must cache the data until we know all 10 digits
|
2832
|
+
my $two = $$cipherInfo{two}; # (index of '2' in the array)
|
2833
|
+
my %decipher = ( $colon => ':' ); # (':' is the time separator)
|
2834
|
+
foreach (0..9) {
|
2835
|
+
my $ch = $$secs[($_ + $two - 2 + 10) % 10];
|
2836
|
+
if ($two < 0 or defined $decipher{$ch}) { # (must be a unique code for each digit)
|
2837
|
+
@$cipherInfo{'secs','two'} = ([ ], -1); # reset and try again
|
2838
|
+
$et->Warn('Hiccup while deciphering LIGOGPSINFO');
|
2839
|
+
return 1;
|
2840
|
+
}
|
2841
|
+
$decipher{$ch} = chr($_ + 0x30);
|
2842
|
+
}
|
2843
|
+
# also know the lat/lon quadrant from the signs of the coordinates
|
2844
|
+
if ($str =~ / ([0-_])$colon(-?).*? ([0-_])$colon(-?)/) {
|
2845
|
+
@decipher{$1,$3} = ($2 ? 'S' : 'N', $4 ? 'W' : 'E');
|
2846
|
+
}
|
2847
|
+
# fill in unknown entries with '?' (only chars 0x30-0x5f are enciphered)
|
2848
|
+
defined $decipher{$_} or $decipher{$_} = '?' foreach map(chr, 0x30..0x5f);
|
2849
|
+
$decipher = $$cipherInfo{decipher} = \%decipher;
|
2850
|
+
$str = shift @$cache; # start deciphering at oldest cache entry
|
2851
|
+
}
|
2852
|
+
|
2853
|
+
# apply reverse Caesar cipher and extract GPS information
|
2854
|
+
do {
|
2855
|
+
my $pre = substr($str, 4, 4); # save second 4 bytes of header
|
2856
|
+
($str = substr($str,8)) =~ s/\0+$//; # remove 8-byte header and null padding
|
2857
|
+
$str =~ s/([0-_])/$$decipher{$1}/g; # decipher
|
2858
|
+
if ($$et{OPTIONS}{Verbose} > 1) {
|
2859
|
+
$et->VPrint(1, "$$et{INDENT}\(Deciphered: ".unpack('H8',$pre)." $str)\n");
|
2860
|
+
}
|
2861
|
+
# add back leading 4 bytes (int16u counter plus 2 unknown bytes), and parse
|
2862
|
+
# (not fuzzed in my only sample when found in standard 'skip' atom)
|
2863
|
+
ParseLigoGPS($et, "$pre$str", $tagTbl, $$et{LigoType} eq 'LigoGPSInfo');
|
2864
|
+
} while $str = shift @$cache;
|
2865
|
+
|
2866
|
+
return 1;
|
2867
|
+
}
|
2868
|
+
|
2869
|
+
#------------------------------------------------------------------------------
|
2870
|
+
# Parse decrypted/deciphered (but not defuzzed) LIGOGPSINFO record
|
2871
|
+
# (record starts with 4-byte int32u counter followed by date/time, etc)
|
2872
|
+
# Inputs: 0) ExifTool ref, 1) GPS string, 2) tag table ref, 3) not fuzzed
|
2873
|
+
# Returns: nothing
|
2874
|
+
sub ParseLigoGPS($$$;$)
|
2875
|
+
{
|
2876
|
+
my ($et, $str, $tagTbl, $noFuzz) = @_;
|
2877
|
+
|
2878
|
+
# example string input
|
2879
|
+
# "....2022/09/19 12:45:24 N:31.285065 W:124.759483 46.93 km/h x:-0.000 y:-0.000 z:-0.000"
|
2880
|
+
unless ($str=~ /^.{4}(\S+ \S+)\s+([NS?]):(-?)([.\d]+)\s+([EW?]):(-?)([\.\d]+)\s+([.\d]+)/s) {
|
2881
|
+
$et->Warn('LIGOGPSINFO format error');
|
2882
|
+
return;
|
2883
|
+
}
|
2884
|
+
my ($time,$latRef,$latNeg,$lat,$lonRef,$lonNeg,$lon,$spd) = ($1,$2,$3,$4,$5,$6,$7,$8);
|
2885
|
+
my %gpsScl = ( 1 => 1.524855137, 2 => 1.456027985, 3 => 1.15368 );
|
2886
|
+
my $spdScl = $noFuzz ? $knotsToKph : 1.85407333;
|
2887
|
+
$$et{DOC_NUM} = ++$$et{DOC_COUNT};
|
2888
|
+
$time =~ tr(/)(:);
|
2889
|
+
# convert from DDMM.MMMMMM to DD.DDDDDD if necessary
|
2890
|
+
# (speed wasn't scaled in my 1 sample with this format)
|
2891
|
+
$lat =~ /^\d{3}/ and ConvertLatLon($lat,$lon), $spdScl = 1;
|
2892
|
+
unless ($noFuzz) { # unfuzz the coordinates if necessary
|
2893
|
+
my $scl = $$et{OPTIONS}{LigoGPSScale} || $$et{LigoGPSScale} || 1;
|
2894
|
+
$scl = $gpsScl{$scl} if $gpsScl{$scl};
|
2895
|
+
($lat, $lon) = UnfuzzLigoGPS($lat, $lon, $scl);
|
2896
|
+
}
|
2897
|
+
# a final sanity check
|
2898
|
+
($lat > 90 or $lon > 180) and $et->Warn('LIGOGPSINFO coordinates out of range'), return;
|
2899
|
+
$$et{SET_GROUP1} = 'LIGO';
|
2900
|
+
$et->HandleTag($tagTbl, 'GPSDateTime', $time);
|
2901
|
+
# (ignore N/S/E/W if coordinate is signed)
|
2902
|
+
$et->HandleTag($tagTbl, 'GPSLatitude', $lat * (($latNeg or $latRef eq 'S') ? -1 : 1));
|
2903
|
+
$et->HandleTag($tagTbl, 'GPSLongitude', $lon * (($lonNeg or $lonRef eq 'W') ? -1 : 1));
|
2904
|
+
$et->HandleTag($tagTbl, 'GPSSpeed', $spd * $spdScl);
|
2905
|
+
$et->HandleTag($tagTbl, 'GPSTrack', $1) if $str =~ /\bA:(\S+)/;
|
2906
|
+
# (have a sample where tab is used to separate acc components)
|
2907
|
+
$et->HandleTag($tagTbl, 'Accelerometer',"$1 $2 $3") if $str =~ /x:(\S+)\sy:(\S+)\sz:(\S+)/;
|
2908
|
+
$et->HandleTag($tagTbl, 'M', $1) if $str =~ /\bM:(\S+)/;
|
2909
|
+
$et->HandleTag($tagTbl, 'H', $1) if $str =~ /\bH:(\S+)/;
|
2910
|
+
delete $$et{SET_GROUP1};
|
2911
|
+
}
|
2912
|
+
|
2913
|
+
#------------------------------------------------------------------------------
|
2914
|
+
# Process LIGOGPSINFO data (non-JSON format)
|
2915
|
+
# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
|
2916
|
+
# 3) 1=LIGOGPS lat/lon/spd weren't fuzzed
|
2917
|
+
# Returns: 1 on success
|
2918
|
+
sub ProcessLigoGPS($$$;$)
|
2919
|
+
{
|
2920
|
+
my ($et, $dirInfo, $tagTbl, $noFuzz) = @_;
|
2921
|
+
my $dataPt = $$dirInfo{DataPt};
|
2922
|
+
my $pos = ($$dirInfo{DirStart} || 0) + 0x14;
|
2923
|
+
my $cipherInfo = $$et{LigoCipher};
|
2924
|
+
return undef if $pos > length $$dataPt;
|
2925
|
+
$$et{LigoType} = $$dirInfo{DirName} || 'LigoGPS';
|
2926
|
+
push @{$$et{PATH}}, $$et{LigoType} unless $$dirInfo{DirID};
|
2927
|
+
# not fuzzed if header is "LIGOGPSINFO\0\0\0\0\x01" (BlueSkySeaDV688)
|
2928
|
+
$noFuzz = 1 if substr($$dataPt, $pos-8, 4) eq "\0\0\0\x01";
|
2929
|
+
$et->VerboseDir($$et{LigoType});
|
2930
|
+
for (; $pos + 0x84 <= length($$dataPt); $pos+=0x84) {
|
2931
|
+
my $dat = substr($$dataPt, $pos, 0x84);
|
2932
|
+
$dat =~ /^####/ or next; # (have seen blank records filled with zeros, so keep trying)
|
2933
|
+
# decipher if we already know the encryption
|
2934
|
+
$cipherInfo and $$cipherInfo{decipher} and DecipherLigoGPS($et, $dat, $tagTbl) and next;
|
2935
|
+
my $str = DecryptLigoGPS($dat);
|
2936
|
+
defined $str or DecipherLigoGPS($et, $dat, $tagTbl), next; # try to decipher
|
2937
|
+
$et->VPrint(1, "$$et{INDENT}\(Decrypted: ",unpack('V',$str),' ',substr($str,4),")\n") if $$et{OPTIONS}{Verbose} > 1;
|
2938
|
+
ParseLigoGPS($et, $str, $tagTbl, $noFuzz);
|
2698
2939
|
}
|
2940
|
+
pop @{$$et{PATH}} unless $$dirInfo{DirID};
|
2941
|
+
delete $$et{DOC_NUM};
|
2699
2942
|
return 1;
|
2700
2943
|
}
|
2701
2944
|
|
2702
2945
|
#------------------------------------------------------------------------------
|
2703
|
-
# Process
|
2946
|
+
# Process LIGOGPSINFO JSON-format GPS (Yada RoadCam Pro 4K BT58189)
|
2704
2947
|
# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
|
2705
2948
|
# Returns: 1 on success
|
2706
2949
|
# Sample data (chained 512-byte records starting like this):
|
@@ -2711,13 +2954,14 @@ sub Process_nbmt($$$)
|
|
2711
2954
|
# 0040: 22 3a 20 22 32 30 32 33 22 2c 20 22 4d 6f 6e 74 [": "2023", "Mont]
|
2712
2955
|
# 0050: 68 22 3a 20 22 31 32 22 2c 20 22 44 61 79 22 3a [h": "12", "Day":]
|
2713
2956
|
# 0060: 20 22 32 38 22 2c 20 22 73 74 61 74 75 73 22 3a [ "28", "status":]
|
2714
|
-
sub
|
2957
|
+
sub ProcessLigoJSON($$$)
|
2715
2958
|
{
|
2716
2959
|
my ($et, $dirInfo, $tagTbl) = @_;
|
2717
2960
|
my $dataPt = $$dirInfo{DataPt};
|
2718
2961
|
my $dirLen = $$dirInfo{DirLen};
|
2719
2962
|
require Image::ExifTool::Import;
|
2720
2963
|
$et->VerboseDir('LIGO_JSON', undef, length($$dataPt));
|
2964
|
+
$$et{SET_GROUP1} = 'LIGO';
|
2721
2965
|
while ($$dataPt =~ /LIGOGPSINFO (\{.*?\})/g) {
|
2722
2966
|
my $json = $1;
|
2723
2967
|
my %dbase;
|
@@ -2767,11 +3011,12 @@ sub ProcessLIGO_JSON($$$)
|
|
2767
3011
|
$et->HandleTag($tagTbl, GPSLongitude2 => $lon);
|
2768
3012
|
}
|
2769
3013
|
unless ($et->Options('ExtractEmbedded')) {
|
2770
|
-
$et->
|
3014
|
+
$et->Warn('Use the ExtractEmbedded option to extract all timed GPS',3);
|
2771
3015
|
last;
|
2772
3016
|
}
|
2773
3017
|
}
|
2774
3018
|
delete $$et{DOC_NUM};
|
3019
|
+
delete $$et{SET_GROUP1};
|
2775
3020
|
return 1;
|
2776
3021
|
}
|
2777
3022
|
|
@@ -2814,7 +3059,7 @@ sub ProcessKenwood($$$)
|
|
2814
3059
|
}
|
2815
3060
|
$et->HandleTag($tagTbl, Accelerometer => "@acc") if @acc;
|
2816
3061
|
unless ($et->Options('ExtractEmbedded')) {
|
2817
|
-
$et->
|
3062
|
+
$et->Warn('Use the ExtractEmbedded option to extract all timed GPS',3);
|
2818
3063
|
last;
|
2819
3064
|
}
|
2820
3065
|
}
|
@@ -2937,7 +3182,7 @@ sub ProcessKenwoodTrailer($$$)
|
|
2937
3182
|
$raf->Read($buff, 14) and $buff eq 'CCCCCCCCCCCCCC' or return 0;
|
2938
3183
|
$et->VerboseDir('Kenwood trailer', undef, undef);
|
2939
3184
|
unless ($$et{OPTIONS}{ExtractEmbedded}) {
|
2940
|
-
$et->
|
3185
|
+
$et->Warn('Use the ExtractEmbedded option to extract timed GPSData from Kenwood trailer',3);
|
2941
3186
|
return 1;
|
2942
3187
|
}
|
2943
3188
|
while ($raf->Read($buff, 121) and $buff =~ /^GPSDATA--(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/) {
|
@@ -3160,7 +3405,7 @@ sub ProcessTTAD($$$)
|
|
3160
3405
|
$et->HandleTag($tagTbl, "Unknown0$type" => "@a");
|
3161
3406
|
}
|
3162
3407
|
} else {
|
3163
|
-
$et->
|
3408
|
+
$et->Warn("Unknown TTAD record type $type",1);
|
3164
3409
|
}
|
3165
3410
|
# without -ee, stop after we find types 0,3,5 (ie. bitmask 0x29)
|
3166
3411
|
$eeOpt or ($found & 0x29) != 0x29 or EEWarn($et), last;
|
@@ -3212,7 +3457,7 @@ sub ProcessInsta360($;$)
|
|
3212
3457
|
}
|
3213
3458
|
unless ($et->Options('ExtractEmbedded')) {
|
3214
3459
|
# can arrive here when reading Insta360 trailer on JPEG image (INSP file)
|
3215
|
-
$et->
|
3460
|
+
$et->Warn('Use ExtractEmbedded option to extract timed metadata from Insta360 trailer',3);
|
3216
3461
|
return 1;
|
3217
3462
|
}
|
3218
3463
|
|
@@ -3409,8 +3654,8 @@ sub ProcessCAMM($$$)
|
|
3409
3654
|
my $rtnVal = 0;
|
3410
3655
|
while ($pos + 4 < $end) {
|
3411
3656
|
my $type = Get16u($dataPt, $pos + 2);
|
3412
|
-
my $size = $size{$type} or $et->
|
3413
|
-
$pos + $size > $end and $et->
|
3657
|
+
my $size = $size{$type} or $et->Warn("Unknown camm record type $type"), last;
|
3658
|
+
$pos + $size > $end and $et->Warn("Truncated camm record $type"), last;
|
3414
3659
|
my $tagTbl = GetTagTable("Image::ExifTool::QuickTime::camm$type");
|
3415
3660
|
$$dirInfo{DirStart} = $pos;
|
3416
3661
|
$$dirInfo{DirLen} = $size;
|