exiftool_vendored 12.54.0 → 12.56.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 +34 -4
- data/bin/MANIFEST +5 -0
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +19 -19
- data/bin/arg_files/xmp2exif.args +4 -1
- data/bin/exiftool +28 -28
- data/bin/fmt_files/kml.fmt +3 -0
- data/bin/fmt_files/kml_track.fmt +6 -3
- data/bin/lib/Image/ExifTool/BuildTagLookup.pm +7 -5
- data/bin/lib/Image/ExifTool/Canon.pm +8 -2
- data/bin/lib/Image/ExifTool/Exif.pm +31 -2
- data/bin/lib/Image/ExifTool/FlashPix.pm +69 -8
- data/bin/lib/Image/ExifTool/FujiFilm.pm +3 -1
- data/bin/lib/Image/ExifTool/Geotag.pm +13 -4
- data/bin/lib/Image/ExifTool/InfiRay.pm +227 -0
- data/bin/lib/Image/ExifTool/JPEG.pm +40 -6
- data/bin/lib/Image/ExifTool/Matroska.pm +4 -4
- data/bin/lib/Image/ExifTool/Nikon.pm +187 -384
- data/bin/lib/Image/ExifTool/OpenEXR.pm +32 -15
- data/bin/lib/Image/ExifTool/PNG.pm +80 -2
- data/bin/lib/Image/ExifTool/QuickTime.pm +19 -4
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +127 -39
- data/bin/lib/Image/ExifTool/README +3 -0
- data/bin/lib/Image/ExifTool/Real.pm +2 -2
- data/bin/lib/Image/ExifTool/Sony.pm +5 -1
- data/bin/lib/Image/ExifTool/TagLookup.pm +4544 -4525
- data/bin/lib/Image/ExifTool/TagNames.pod +229 -21
- data/bin/lib/Image/ExifTool/VCard.pm +19 -5
- data/bin/lib/Image/ExifTool.pm +56 -15
- data/bin/lib/Image/ExifTool.pod +51 -50
- data/bin/perl-Image-ExifTool.spec +18 -18
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +3 -2
@@ -81,12 +81,15 @@ my %processByMetaFormat = (
|
|
81
81
|
ctbx => 1, # ('marl' in GM videos)
|
82
82
|
);
|
83
83
|
|
84
|
-
# data lengths for each INSV record type
|
84
|
+
# data lengths for each INSV/INSP record type
|
85
85
|
my %insvDataLen = (
|
86
|
+
0x200 => 0, # PreivewImage (any size) (a duplicate of PreviewImage in APP2 of INSP files)
|
86
87
|
0x300 => 0, # accelerometer (could be either 20 or 56 bytes)
|
87
88
|
0x400 => 16, # exposure (ref 6)
|
88
89
|
0x600 => 8, # timestamps (ref 6)
|
89
90
|
0x700 => 53, # GPS
|
91
|
+
# 0x900 => 48, # ? (Insta360 X3)
|
92
|
+
# 0xb00 => 10, # ? (Insta360 X3)
|
90
93
|
);
|
91
94
|
|
92
95
|
# limit the default amount of data we read for some record types
|
@@ -102,7 +105,7 @@ my %insvLimit = (
|
|
102
105
|
The tags below are extracted from timed metadata in QuickTime and other
|
103
106
|
formats of video files when the ExtractEmbedded option is used. Although
|
104
107
|
most of these tags are combined into the single table below, ExifTool
|
105
|
-
currently reads
|
108
|
+
currently reads 66 different formats of timed GPS metadata from video files.
|
106
109
|
},
|
107
110
|
VARS => { NO_ID => 1 },
|
108
111
|
GPSLatitude => { PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', RawConv => '$$self{FoundGPSLatitude} = 1; $val' },
|
@@ -880,9 +883,10 @@ sub HandleTextTags($$$)
|
|
880
883
|
#------------------------------------------------------------------------------
|
881
884
|
# Process subtitle 'text'
|
882
885
|
# Inputs: 0) ExifTool ref, 1) data ref or dirInfo ref, 2) tag table ref
|
883
|
-
|
886
|
+
# 3) flag set if text was already stored
|
887
|
+
sub Process_text($$$;$)
|
884
888
|
{
|
885
|
-
my ($et, $dataPt, $tagTbl) = @_;
|
889
|
+
my ($et, $dataPt, $tagTbl, $handled) = @_;
|
886
890
|
my %tags;
|
887
891
|
|
888
892
|
return if $$et{NoMoreTextDecoding};
|
@@ -938,6 +942,16 @@ sub Process_text($$$)
|
|
938
942
|
$tags{GPSSatellites} = $10 if defined $10;
|
939
943
|
$tags{GPSDOP} = $11 if defined $11;
|
940
944
|
$tags{GPSAltitude} = $12 if defined $12;
|
945
|
+
# ($G and $GS are ref https://exiftool.org/forum/index.php?topic=13115.msg71743#msg71743)
|
946
|
+
} elsif ($tag eq 'G' and $dat =~ /:(\d{4})-(\d{2})-(\d{2}) (\d{2}:\d{2}:\d{2})-([NS])(\d+\.\d+)-([EW])(\d+\.\d+)-S(\d+)/) {
|
947
|
+
$tags{GPSDateTime} = "$1:$2:$3 $4";
|
948
|
+
$tags{GPSLatitude} = $6 * ($5 eq 'S' ? -1 : 1);
|
949
|
+
$tags{GPSLongitude} = $8 * ($7 eq 'W' ? -1 : 1);
|
950
|
+
$tags{GPSSpeed} = $9;
|
951
|
+
} elsif ($tag eq 'GS' and $dat =~ /:([-+]?\d+),([-+]?\d+),([-+]?\d+)/) {
|
952
|
+
# scale and re-arrange to match gsensor output from Win app (forum11665)
|
953
|
+
my @acc = ( ($2+2432)/1000, ($3 + 361)/1000, ($1-3708)/1000 );
|
954
|
+
$tags{Accelerometer} = "@acc";
|
941
955
|
} elsif ($tag eq 'BEGINGSENSOR' and $dat =~ /^:([-+]\d+\.\d+):([-+]\d+\.\d+):([-+]\d+\.\d+)/) {
|
942
956
|
$tags{Accelerometer} = "$1 $2 $3";
|
943
957
|
} elsif ($tag eq 'TIME' and $dat =~ /^:(\d+)/) {
|
@@ -946,7 +960,7 @@ sub Process_text($$$)
|
|
946
960
|
$tags{Text} = $dat if length $dat;
|
947
961
|
$tags{done} = 1;
|
948
962
|
} elsif ($tag ne 'END') {
|
949
|
-
$tags{Text} = "\$$tag$dat";
|
963
|
+
$tags{Text} = "\$$tag$dat" unless $handled;
|
950
964
|
}
|
951
965
|
}
|
952
966
|
%tags and HandleTextTags($et, $tagTbl, \%tags), return;
|
@@ -1234,6 +1248,7 @@ Sample: for ($i=0; ; ) {
|
|
1234
1248
|
($type eq 'sbtl' and $metaFormat eq 'tx3g' and $buff =~ /^..PNDM/s))
|
1235
1249
|
{
|
1236
1250
|
|
1251
|
+
my $handled;
|
1237
1252
|
FoundSomething($et, $tagTbl, $time[$i], $dur[$i]);
|
1238
1253
|
unless ($buff =~ /^\$BEGIN/) {
|
1239
1254
|
# remove ending "encd" box if it exists
|
@@ -1273,9 +1288,10 @@ Sample: for ($i=0; ; ) {
|
|
1273
1288
|
}
|
1274
1289
|
unless (defined $val) {
|
1275
1290
|
$et->HandleTag($tagTbl, Text => $buff); # just store any other text
|
1291
|
+
$handled = 1;
|
1276
1292
|
}
|
1277
1293
|
}
|
1278
|
-
Process_text($et, \$buff, $tagTbl);
|
1294
|
+
Process_text($et, \$buff, $tagTbl, $handled);
|
1279
1295
|
|
1280
1296
|
} elsif ($processByMetaFormat{$type}) {
|
1281
1297
|
|
@@ -1371,6 +1387,7 @@ sub ProcessFreeGPS($$$)
|
|
1371
1387
|
|
1372
1388
|
if (substr($$dataPt,18,8) eq "\xaa\xaa\xf2\xe1\xf0\xee\x54\x54") {
|
1373
1389
|
|
1390
|
+
$debug and $et->FoundTag(GPSType => '1A');
|
1374
1391
|
# (this is very similar to the encrypted text format)
|
1375
1392
|
# decode encrypted ASCII-based GPS (DashCam Azdome GS63H, ref 5)
|
1376
1393
|
# header looks like this in my sample:
|
@@ -1425,10 +1442,10 @@ sub ProcessFreeGPS($$$)
|
|
1425
1442
|
} elsif ($buf2 =~ /^.{173}([-+]\d{3})([-+]\d{3})([-+]\d{3})/s) { # (Azdome)
|
1426
1443
|
@acc = ($1/100, $2/100, $3/100);
|
1427
1444
|
}
|
1428
|
-
$debug and $et->FoundTag(GPSType => '1A');
|
1429
1445
|
|
1430
1446
|
} elsif ($$dataPt =~ /^.{52}(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/s) {
|
1431
1447
|
|
1448
|
+
$debug and $et->FoundTag(GPSType => '1B');
|
1432
1449
|
# decode NMEA-format GPS data (NextBase 512GW dashcam, ref PH)
|
1433
1450
|
# header looks like this in my sample:
|
1434
1451
|
# 0000: 00 00 80 00 66 72 65 65 47 50 53 20 40 01 00 00 [....freeGPS @...]
|
@@ -1454,10 +1471,10 @@ sub ProcessFreeGPS($$$)
|
|
1454
1471
|
# change to signed integer and divide by 256
|
1455
1472
|
map { $_ = $_ - 4294967296 if $_ >= 0x80000000; $_ /= 256 } @acc;
|
1456
1473
|
}
|
1457
|
-
$debug and $et->FoundTag(GPSType => '1B');
|
1458
1474
|
|
1459
1475
|
} elsif ($$dataPt =~ /^.{37}\0\0\0A([NS])([EW])/s) {
|
1460
1476
|
|
1477
|
+
$debug and $et->FoundTag(GPSType => '1C');
|
1461
1478
|
# decode freeGPS from ViofoA119v3 dashcam (similar to Novatek GPS format)
|
1462
1479
|
# 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 03 00 00 [..@.freeGPS ....]
|
1463
1480
|
# 0010: 05 00 00 00 2f 00 00 00 03 00 00 00 13 00 00 00 [..../...........]
|
@@ -1489,10 +1506,10 @@ sub ProcessFreeGPS($$$)
|
|
1489
1506
|
map { $_ = $_ - 4294967296 if $_ >= 0x80000000; $_ /= 256 } @acc;
|
1490
1507
|
}
|
1491
1508
|
SetByteOrder('MM');
|
1492
|
-
$debug and $et->FoundTag(GPSType => '1C');
|
1493
1509
|
|
1494
1510
|
} elsif ($$dataPt =~ /^.{21}\0\0\0A([NS])([EW])/s) {
|
1495
1511
|
|
1512
|
+
$debug and $et->FoundTag(GPSType => '1D');
|
1496
1513
|
# also decode 'gpmd' chunk from Kingslim D4 dashcam videos
|
1497
1514
|
# 0000: 0a 00 00 00 0b 00 00 00 07 00 00 00 e5 07 00 00 [................]
|
1498
1515
|
# 0010: 06 00 00 00 03 00 00 00 41 4e 57 31 91 52 83 45 [........ANW1.R.E]
|
@@ -1518,10 +1535,10 @@ sub ProcessFreeGPS($$$)
|
|
1518
1535
|
$acc[1] = GetFloat($dataPt, 0x30);
|
1519
1536
|
$acc[2] = GetFloat($dataPt, 0x34);
|
1520
1537
|
SetByteOrder('MM');
|
1521
|
-
$debug and $et->FoundTag(GPSType => '1D');
|
1522
1538
|
|
1523
1539
|
} elsif ($$dataPt =~ /^.{60}A\0{3}.{4}([NS])\0{3}.{4}([EW])\0{3}/s) {
|
1524
1540
|
|
1541
|
+
$debug and $et->FoundTag(GPSType => '1E');
|
1525
1542
|
# decode freeGPS from Akaso dashcam
|
1526
1543
|
# 0000: 00 00 80 00 66 72 65 65 47 50 53 20 60 00 00 00 [....freeGPS `...]
|
1527
1544
|
# 0010: 78 2e 78 78 00 00 00 00 00 00 00 00 00 00 00 00 [x.xx............]
|
@@ -1539,10 +1556,10 @@ sub ProcessFreeGPS($$$)
|
|
1539
1556
|
$trk = GetFloat($dataPt, 0x54) + 180; # (why is this off by 180?)
|
1540
1557
|
$trk -= 360 if $trk >= 360;
|
1541
1558
|
SetByteOrder('MM');
|
1542
|
-
$debug and $et->FoundTag(GPSType => '1E');
|
1543
1559
|
|
1544
1560
|
} elsif ($$dataPt =~ /^.{60}4W`b]S</s and length($$dataPt) >= 140) {
|
1545
1561
|
|
1562
|
+
$debug and $et->FoundTag(GPSType => '1F');
|
1546
1563
|
# 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 01 00 00 [..@.freeGPS ....]
|
1547
1564
|
# 0010: 5a 58 53 42 4e 58 59 53 00 00 00 00 00 00 00 00 [ZXSBNXYS........]
|
1548
1565
|
# 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
|
@@ -1557,10 +1574,10 @@ sub ProcessFreeGPS($$$)
|
|
1557
1574
|
$yr += ($yr >= 70 ? 1900 : 2000);
|
1558
1575
|
$spd = $9 * $knotsToKph if length $9;
|
1559
1576
|
$trk = $10 if length $10;
|
1560
|
-
$debug and $et->FoundTag(GPSType => '1F');
|
1561
1577
|
|
1562
1578
|
} elsif ($$dataPt =~ /^.{64}[\x01-\x0c]\0{3}[\x01-\x1f]\0{3}A[NS][EW]\0{5}/s) {
|
1563
1579
|
|
1580
|
+
$debug and $et->FoundTag(GPSType => '1G');
|
1564
1581
|
# Akaso V1 dascham
|
1565
1582
|
# 0000: 00 00 80 00 66 72 65 65 47 50 53 20 78 00 00 00 [....freeGPS x...]
|
1566
1583
|
# 0010: 59 6e 64 41 6b 61 73 6f 43 61 72 00 00 00 00 00 [YndAkasoCar.....]
|
@@ -1601,10 +1618,10 @@ sub ProcessFreeGPS($$$)
|
|
1601
1618
|
|
1602
1619
|
SetByteOrder('MM');
|
1603
1620
|
#my $serialNum = substr($$dataPt, 0x68, 20);
|
1604
|
-
$debug and $et->FoundTag(GPSType => '1G');
|
1605
1621
|
|
1606
1622
|
} elsif ($$dataPt =~ /^.{12}\xac\0\0\0.{44}(.{72})/s) {
|
1607
1623
|
|
1624
|
+
$debug and $et->FoundTag(GPSType => '1H');
|
1608
1625
|
# EACHPAI dash cam
|
1609
1626
|
# 0000: 00 00 80 00 66 72 65 65 47 50 53 20 ac 00 00 00 [....freeGPS ....]
|
1610
1627
|
# 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
|
@@ -1624,10 +1641,10 @@ sub ProcessFreeGPS($$$)
|
|
1624
1641
|
# bytes 7-12 are the timestamp in ASCII HHMMSS after xor-ing with 0x70
|
1625
1642
|
substr($time,7,6) = pack 'C*', map { $_ ^= 0x70 } unpack 'C*', substr($time,7,6);
|
1626
1643
|
# (other values are currently unknown)
|
1627
|
-
$debug and $et->FoundTag(GPSType => '1H');
|
1628
1644
|
|
1629
1645
|
} elsif ($$dataPt =~ /^.{64}A([NS])([EW])\0/s) {
|
1630
1646
|
|
1647
|
+
$debug and $et->FoundTag(GPSType => '1I');
|
1631
1648
|
# Vantrue S1 dashcam
|
1632
1649
|
# 0000: 00 00 80 00 66 72 65 65 47 50 53 20 78 00 00 00 [....freeGPS x...]
|
1633
1650
|
# 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
|
@@ -1650,10 +1667,10 @@ sub ProcessFreeGPS($$$)
|
|
1650
1667
|
$trk = GetFloat($dataPt, 0x68);
|
1651
1668
|
$alt = GetFloat($dataPt, 0x6c);
|
1652
1669
|
SetByteOrder('MM');
|
1653
|
-
$debug and $et->FoundTag(GPSType => '1I');
|
1654
1670
|
|
1655
1671
|
} else {
|
1656
1672
|
|
1673
|
+
$debug and $et->FoundTag(GPSType => '1J');
|
1657
1674
|
# decode binary GPS format (Viofo A119S, ref 2)
|
1658
1675
|
# header looks like this in my sample:
|
1659
1676
|
# 0000: 00 00 80 00 66 72 65 65 47 50 53 20 4c 00 00 00 [....freeGPS L...]
|
@@ -1687,7 +1704,6 @@ sub ProcessFreeGPS($$$)
|
|
1687
1704
|
$yr += 2000 if $yr < 2000;
|
1688
1705
|
$spd *= $knotsToKph; # convert speed to km/h
|
1689
1706
|
# ($trk is not confirmed; may be GPSImageDirection, ref PH)
|
1690
|
-
$debug and $et->FoundTag(GPSType => '1J');
|
1691
1707
|
}
|
1692
1708
|
#
|
1693
1709
|
# save tag values extracted by above code
|
@@ -1734,6 +1750,7 @@ sub ProcessFreeGPS2($$$)
|
|
1734
1750
|
|
1735
1751
|
if (substr($$dataPt,0x45,3) eq 'ATC') {
|
1736
1752
|
|
1753
|
+
$debug and $et->FoundTag(GPSType => '2A');
|
1737
1754
|
# header looks like this: (sample 1)
|
1738
1755
|
# 0000: 00 00 80 00 66 72 65 65 47 50 53 20 38 06 00 00 [....freeGPS 8...]
|
1739
1756
|
# 0010: 49 51 53 32 30 31 33 30 33 30 36 42 00 00 00 00 [IQS20130306B....]
|
@@ -1841,11 +1858,11 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
1841
1858
|
}
|
1842
1859
|
# save position of most recent record (needed when parsing the next freeGPS block)
|
1843
1860
|
$$et{FreeGPS2}{RecentRecPos} = $lastRecPos;
|
1844
|
-
$debug and $et->FoundTag(GPSType => '2A');
|
1845
1861
|
return 1;
|
1846
1862
|
|
1847
1863
|
} elsif ($$dataPt =~ /^.{60}A\0.{10}([NS])\0.{14}([EW])\0/s) {
|
1848
1864
|
|
1865
|
+
$debug and $et->FoundTag(GPSType => '2B');
|
1849
1866
|
# header looks like this in my sample:
|
1850
1867
|
# 0000: 00 00 80 00 66 72 65 65 47 50 53 20 08 01 00 00 [....freeGPS ....]
|
1851
1868
|
# 0010: 32 30 31 33 30 38 31 35 2e 30 31 00 00 00 00 00 [20130815.01.....]
|
@@ -1873,7 +1890,6 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
1873
1890
|
$lon = GetDouble($dataPt, 0x50);
|
1874
1891
|
$spd = GetDouble($dataPt, 0x60) * $knotsToKph;
|
1875
1892
|
$trk = GetDouble($dataPt, 0x68);
|
1876
|
-
$debug and $et->FoundTag(GPSType => '2B');
|
1877
1893
|
|
1878
1894
|
} elsif ($$dataPt =~ /^.{72}A([NS])([EW])/s) {
|
1879
1895
|
|
@@ -1900,6 +1916,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
1900
1916
|
($latRef, $lonRef) = ($1, $2);
|
1901
1917
|
($hr,$min,$sec,$yr,$mon,$day) = unpack('x48V6', $$dataPt);
|
1902
1918
|
if (substr($$dataPt, 16, 3) eq 'IQS') {
|
1919
|
+
$debug and $et->FoundTag(GPSType => '2C');
|
1903
1920
|
# Type 3b (ref PH)
|
1904
1921
|
# header looks like this in my sample:
|
1905
1922
|
# 0000: 00 00 80 00 66 72 65 65 47 50 53 20 4c 00 00 00 [....freeGPS L...]
|
@@ -1910,20 +1927,20 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
1910
1927
|
$lon = abs Get32s($dataPt, 0x50) / 1e7;
|
1911
1928
|
$spd = Get32s($dataPt, 0x54) / 100 * $mpsToKph;
|
1912
1929
|
$alt = GetFloat($dataPt, 0x58) / 1000; # (NC)
|
1913
|
-
$debug and $et->FoundTag(GPSType => '2C');
|
1914
1930
|
|
1915
1931
|
} else {
|
1932
|
+
$debug and $et->FoundTag(GPSType => '2D');
|
1916
1933
|
# Type 3 (ref 2)
|
1917
1934
|
# (no sample with this format)
|
1918
1935
|
$lat = GetFloat($dataPt, 0x4c);
|
1919
1936
|
$lon = GetFloat($dataPt, 0x50);
|
1920
1937
|
$spd = GetFloat($dataPt, 0x54) * $knotsToKph;
|
1921
1938
|
$trk = GetFloat($dataPt, 0x58);
|
1922
|
-
$debug and $et->FoundTag(GPSType => '2D');
|
1923
1939
|
}
|
1924
1940
|
|
1925
1941
|
} elsif ($$dataPt =~ /^.{60}A\0.{6}([NS])\0.{6}([EW])\0/s and $dirLen >= 112) {
|
1926
1942
|
|
1943
|
+
$debug and $et->FoundTag(GPSType => '2E');
|
1927
1944
|
# header looks like this in my sample (unknown dashcam, "Anticlock 2 2020_1125_1455_007.MOV"):
|
1928
1945
|
# 0000: 00 00 80 00 66 72 65 65 47 50 53 20 68 00 00 00 [....freeGPS h...]
|
1929
1946
|
# 0010: 32 30 31 33 30 33 32 35 41 00 00 00 00 00 00 00 [20130325A.......]
|
@@ -1940,10 +1957,10 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
1940
1957
|
$lon = GetFloat($dataPt, 0x48);
|
1941
1958
|
$spd = GetFloat($dataPt, 0x50);
|
1942
1959
|
$trk = GetFloat($dataPt, 0x54);
|
1943
|
-
$debug and $et->FoundTag(GPSType => '2E');
|
1944
1960
|
|
1945
1961
|
} elsif ($$dataPt =~ /^.{16}A([NS])([EW])\0/s) {
|
1946
1962
|
|
1963
|
+
$debug and $et->FoundTag(GPSType => '2F');
|
1947
1964
|
# INNOVV MP4 video (same format as INNOVV TS)
|
1948
1965
|
while ($$dataPt =~ /(A[NS][EW]\0.{28})/g) {
|
1949
1966
|
my $dat = $1;
|
@@ -1961,11 +1978,36 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
1961
1978
|
$et->HandleTag($tagTbl, GPSTrack => $trk);
|
1962
1979
|
$et->HandleTag($tagTbl, Accelerometer => "@acc");
|
1963
1980
|
}
|
1964
|
-
$debug and $et->FoundTag(GPSType => '2F');
|
1965
1981
|
return 1;
|
1966
1982
|
|
1983
|
+
} elsif ($$dataPt =~ /^.{28}A.{11}([NS]).{15}([EW])/s) {
|
1984
|
+
|
1985
|
+
$debug and $et->FoundTag(GPSType => '2G');
|
1986
|
+
# Vantrue N4 dashcam
|
1987
|
+
# 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 03 00 00 [..@.freeGPS ....]
|
1988
|
+
# 0010: 0d 00 00 00 16 00 00 00 1e 00 00 00 41 00 00 00 [............A...]
|
1989
|
+
# 0020: 2c b7 b4 1a 5a 71 b2 40 4e 00 00 00 00 00 00 00 [,...Zq.@N.......]
|
1990
|
+
# 0030: fb ae 08 fe 77 f6 89 40 45 00 00 00 00 00 00 00 [....w..@E.......]
|
1991
|
+
# 0040: be 9f 1a 2f dd 84 36 40 5c 8f c2 f5 28 fc 68 40 [.../..6@\...(.h@]
|
1992
|
+
# 0050: 16 00 00 00 0c 00 00 00 0e 00 00 00 f2 fb ff ff [................]
|
1993
|
+
# 0060: 42 00 00 00 02 00 00 00 20 24 47 4e 52 4d 43 2c [B....... $GNRMC,]
|
1994
|
+
# 0070: 31 33 32 32 33 30 2e 30 30 30 2c 41 2c 34 37 32 [132230.000,A,472]
|
1995
|
+
# 0080: 31 2e 33 35 31 39 37 2c 4e 2c 30 30 38 33 30 2e [1.35197,N,00830.]
|
1996
|
+
# 0090: 38 30 38 35 39 2c 45 2c 32 32 2e 35 31 39 2c 31 [80859,E,22.519,1]
|
1997
|
+
# 00a0: 39 39 2e 38 38 2c 31 34 31 32 32 32 2c 2c 2c 41 [99.88,141222,,,A]
|
1998
|
+
# 00b0: 2a 37 35 0d 0a 00 00 00 00 00 00 00 00 00 00 00 [*75.............]
|
1999
|
+
($latRef, $lonRef) = ($1, $2);
|
2000
|
+
($hr,$min,$sec,$yr,$mon,$day,@acc) = unpack('x16V3x52V3V3',$$dataPt);
|
2001
|
+
$lat = abs(GetDouble($dataPt, 32)); # (abs just to be safe)
|
2002
|
+
$lon = abs(GetDouble($dataPt, 48)); # (abs just to be safe)
|
2003
|
+
$spd = GetDouble($dataPt, 64) * $knotsToKph;
|
2004
|
+
$trk = GetDouble($dataPt, 72);
|
2005
|
+
map { $_ = $_ - 4294967296 if $_ >= 0x80000000; $_ /= 1000 } @acc; # (NC)
|
2006
|
+
# (not necessary to read RMC sentence because we already have it all)
|
2007
|
+
|
1967
2008
|
} else {
|
1968
2009
|
|
2010
|
+
$debug and $et->FoundTag(GPSType => '2H');
|
1969
2011
|
# (look for binary GPS as stored by NextBase 512G, ref PH)
|
1970
2012
|
# header looks like this in my sample:
|
1971
2013
|
# 0000: 00 00 80 00 66 72 65 65 47 50 53 20 78 01 00 00 [....freeGPS x...]
|
@@ -2008,7 +2050,6 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
2008
2050
|
$et->HandleTag($tagTbl, GPSTrack => $trk);
|
2009
2051
|
last if $pos += 0x20 > length($$dataPt) - 0x1e;
|
2010
2052
|
}
|
2011
|
-
$debug and $et->FoundTag(GPSType => '2G');
|
2012
2053
|
return $$et{DOC_NUM} ? 1 : 0; # return 0 if nothing extracted
|
2013
2054
|
}
|
2014
2055
|
#
|
@@ -2025,9 +2066,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
2025
2066
|
$et->HandleTag($tagTbl, GPSLongitude => $lon * ($lonRef eq 'W' ? -1 : 1));
|
2026
2067
|
$et->HandleTag($tagTbl, GPSSpeed => $spd) if defined $spd; # (now in km/h)
|
2027
2068
|
$et->HandleTag($tagTbl, GPSTrack => $trk) if defined $trk;
|
2028
|
-
if
|
2029
|
-
$et->HandleTag($tagTbl, GPSAltitude => $alt);
|
2030
|
-
}
|
2069
|
+
$et->HandleTag($tagTbl, GPSAltitude => $alt) if defined $alt;
|
2031
2070
|
$et->HandleTag($tagTbl, Accelerometer => "@acc") if @acc;
|
2032
2071
|
return 1;
|
2033
2072
|
}
|
@@ -2322,6 +2361,49 @@ sub Process_gsen($$$)
|
|
2322
2361
|
return 1;
|
2323
2362
|
}
|
2324
2363
|
|
2364
|
+
#------------------------------------------------------------------------------
|
2365
|
+
# Process Kenwood drv-a301w dashcam 'udta' atom (ref PH)
|
2366
|
+
# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
|
2367
|
+
# Returns: 1 on success
|
2368
|
+
# Sample data:
|
2369
|
+
# 0000: 56 49 44 45 4f 55 55 55 55 55 55 55 55 55 55 55 [VIDEOUUUUUUUUUUU]
|
2370
|
+
# 0010: 55 55 55 55 55 55 55 55 55 55 55 fe fe 32 30 32 [UUUUUUUUUUU..202]
|
2371
|
+
# 0020: 33 30 31 30 37 31 31 31 39 31 34 2e 32 30 32 33 [30107111914.2023]
|
2372
|
+
# 0030: 30 31 30 37 31 31 31 39 31 35 03 4e 34 37 33 37 [0107111915.N4737]
|
2373
|
+
# 0040: 37 30 35 33 57 31 32 32 30 39 39 30 31 34 2b 30 [7053W122099014+0]
|
2374
|
+
# 0050: 30 35 38 30 30 30 2b 30 30 36 2b 30 30 39 2b 30 [058000+006+009+0]
|
2375
|
+
# 0060: 30 34 2b 30 30 32 2b 30 30 39 2b 30 30 35 2b 30 [04+002+009+005+0]
|
2376
|
+
sub ProcessKenwood($$$)
|
2377
|
+
{
|
2378
|
+
my ($et, $dirInfo, $tagTbl) = @_;
|
2379
|
+
my $dataPt = $$dirInfo{DataPt};
|
2380
|
+
my $dirLen = $$dirInfo{DirLen};
|
2381
|
+
while ($$dataPt =~ /\xfe\xfe([^\xfe]+)/g) {
|
2382
|
+
my $dat = $1;
|
2383
|
+
next unless $dat =~ /^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})./gs;
|
2384
|
+
my $time = "$1:$2:$3 $4:$5:$6"; # (likely local time zone, but not confirmed)
|
2385
|
+
# ignore second date (what is this for?)
|
2386
|
+
next unless $dat =~ /\G(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})./gs;
|
2387
|
+
next unless $dat =~ /\G([NS])(\d+)([EW])(\d+)/g;
|
2388
|
+
my ($lat, $lon) = ($2/1e4, $4/1e4);
|
2389
|
+
ConvertLatLon($lat, $lon);
|
2390
|
+
$$et{DOC_NUM} = ++$$et{DOC_COUNT};
|
2391
|
+
$et->HandleTag($tagTbl, GPSDateTime => $time);
|
2392
|
+
$et->HandleTag($tagTbl, GPSLatitude => $lat * ($1 eq 'S' ? -1 : 1));
|
2393
|
+
$et->HandleTag($tagTbl, GPSLongitude => $lon * ($3 eq 'W' ? -1 : 1));
|
2394
|
+
next unless $dat =~ /\G([-+]\d{4})(\d+)/g;
|
2395
|
+
$et->HandleTag($tagTbl, GPSAltitude => $1 + 0); # (NC, educated guess)
|
2396
|
+
$et->HandleTag($tagTbl, GPSSpeed => $2); # (km/h)
|
2397
|
+
my @acc;
|
2398
|
+
while ($dat =~ /\G([-+]\d+)([-+]\d+)([-+]\d+)/g) {
|
2399
|
+
push @acc, $1/1000, $2/1000, $3/1000;
|
2400
|
+
}
|
2401
|
+
$et->HandleTag($tagTbl, Accelerometer => "@acc") if @acc;
|
2402
|
+
}
|
2403
|
+
delete $$et{DOC_NUM};
|
2404
|
+
return 1;
|
2405
|
+
}
|
2406
|
+
|
2325
2407
|
#------------------------------------------------------------------------------
|
2326
2408
|
# Process RIFF-format trailer written by Auto-Vox dashcam (ref PH)
|
2327
2409
|
# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
|
@@ -2679,7 +2761,6 @@ sub ProcessInsta360($;$)
|
|
2679
2761
|
my ($id, $len) = unpack('vV', $buff);
|
2680
2762
|
($epos -= $len) + $trailerLen < 0 and last;
|
2681
2763
|
$raf->Seek($epos, 2) or last;
|
2682
|
-
my $dlen = $insvDataLen{$id};
|
2683
2764
|
if ($verbose) {
|
2684
2765
|
$et->VPrint(0, sprintf("Insta360 Record 0x%x (offset 0x%x, %d bytes):\n", $id, $fileEnd + $epos, $len));
|
2685
2766
|
}
|
@@ -2692,20 +2773,25 @@ sub ProcessInsta360($;$)
|
|
2692
2773
|
# 2. 20 byte records
|
2693
2774
|
# 0000: c1 d8 d9 0b 00 00 00 00 f5 83 14 80 df 7f fe 7f [................]
|
2694
2775
|
# 0010: fe 7f 01 80
|
2695
|
-
|
2696
|
-
|
2697
|
-
|
2698
|
-
|
2699
|
-
|
2700
|
-
|
2701
|
-
|
2702
|
-
|
2703
|
-
|
2704
|
-
|
2705
|
-
|
2776
|
+
my $dlen = $insvDataLen{$id};
|
2777
|
+
if (defined $dlen and not $dlen) {
|
2778
|
+
if ($id == 0x300) {
|
2779
|
+
if ($len % 20 and not $len % 56) {
|
2780
|
+
$dlen = 56;
|
2781
|
+
} elsif ($len % 56 and not $len % 20) {
|
2782
|
+
$dlen = 20;
|
2783
|
+
} else {
|
2784
|
+
if ($raf->Read($buff, 20) == 20) {
|
2785
|
+
if (substr($buff, 16, 3) eq "\0\0\0") {
|
2786
|
+
$dlen = 56;
|
2787
|
+
} else {
|
2788
|
+
$dlen = 20;
|
2789
|
+
}
|
2706
2790
|
}
|
2791
|
+
$raf->Seek($epos, 2) or last;
|
2707
2792
|
}
|
2708
|
-
|
2793
|
+
} elsif ($id == 0x200) {
|
2794
|
+
$dlen = $len;
|
2709
2795
|
}
|
2710
2796
|
}
|
2711
2797
|
# limit the number of records we read if necessary
|
@@ -2719,6 +2805,8 @@ sub ProcessInsta360($;$)
|
|
2719
2805
|
if ($dlen) {
|
2720
2806
|
if ($len % $dlen) {
|
2721
2807
|
$et->Warn(sprintf('Unexpected Insta360 record 0x%x length',$id));
|
2808
|
+
} elsif ($id == 0x200) {
|
2809
|
+
$et->FoundTag(PreviewImage => $buff);
|
2722
2810
|
} elsif ($id == 0x300) {
|
2723
2811
|
for ($p=0; $p<$len; $p+=$dlen) {
|
2724
2812
|
$$et{DOC_NUM} = ++$$et{DOC_COUNT};
|
@@ -3,6 +3,9 @@ File: Image/ExifTool/README
|
|
3
3
|
|
4
4
|
Description: ExifTool support modules documentation
|
5
5
|
|
6
|
+
Note: This documentation is a reference to be used by developers when
|
7
|
+
adding new tags to ExifTool.
|
8
|
+
|
6
9
|
The ExifTool support modules are loaded by ExifTool to allow processing of
|
7
10
|
various meta information formats.
|
8
11
|
|
@@ -16,7 +16,7 @@ use vars qw($VERSION);
|
|
16
16
|
use Image::ExifTool qw(:DataAccess :Utils);
|
17
17
|
use Image::ExifTool::Canon;
|
18
18
|
|
19
|
-
$VERSION = '1.
|
19
|
+
$VERSION = '1.07';
|
20
20
|
|
21
21
|
sub ProcessRealMeta($$$);
|
22
22
|
sub ProcessRealProperties($$$);
|
@@ -608,7 +608,7 @@ sub ProcessReal($$)
|
|
608
608
|
} else {
|
609
609
|
last if $tag eq 'DATA'; # stop normal parsing at DATA tag
|
610
610
|
}
|
611
|
-
if ($size & 0x80000000) {
|
611
|
+
if ($size & 0x80000000 or $size < 10) {
|
612
612
|
$et->Warn('Bad chunk header');
|
613
613
|
last;
|
614
614
|
}
|
@@ -34,7 +34,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
|
|
34
34
|
use Image::ExifTool::Exif;
|
35
35
|
use Image::ExifTool::Minolta;
|
36
36
|
|
37
|
-
$VERSION = '3.
|
37
|
+
$VERSION = '3.57';
|
38
38
|
|
39
39
|
sub ProcessSRF($$$);
|
40
40
|
sub ProcessSR2($$$);
|
@@ -160,6 +160,7 @@ sub PrintInvLensSpec($;$$);
|
|
160
160
|
32875 => 'Sony FE 24-70mm F2.8 GM II', #JR
|
161
161
|
32876 => 'Sony E 11mm F1.8', #JR
|
162
162
|
32877 => 'Sony E 15mm F1.4 G', #JR
|
163
|
+
32878 => 'Sony FE 20-70mm F4 G', #JR
|
163
164
|
|
164
165
|
# (comment this out so LensID will report the LensModel, which is more useful)
|
165
166
|
# 32952 => 'Metabones Canon EF Speed Booster Ultra', #JR (corresponds to 184, but 'Advanced' mode, LensMount reported as E-mount)
|
@@ -191,6 +192,7 @@ sub PrintInvLensSpec($;$$);
|
|
191
192
|
49235 => 'Zeiss Loxia 85mm F2.4', #JR
|
192
193
|
49236 => 'Zeiss Loxia 25mm F2.4', #JR
|
193
194
|
|
195
|
+
49456 => 'Tamron E 18-200mm F3.5-6.3 Di III VC', #FrancoisPiette
|
194
196
|
49457 => 'Tamron 28-75mm F2.8 Di III RXD', #JR (Model A036)
|
195
197
|
49458 => 'Tamron 17-28mm F2.8 Di III RXD', #JR (Model A046)
|
196
198
|
49459 => 'Tamron 35mm F2.8 Di III OSD M1:2', #IB (Model F053)
|
@@ -256,6 +258,8 @@ sub PrintInvLensSpec($;$$);
|
|
256
258
|
50533 => 'Sigma 16-28mm F2.8 DG DN | C', #JR (022)
|
257
259
|
50534 => 'Sigma 20mm F1.4 DG DN | A', #JR (022)
|
258
260
|
50535 => 'Sigma 24mm F1.4 DG DN | A', #JR (022)
|
261
|
+
50536 => 'Sigma 60-600mm F4.5-6.3 DG DN OS | S', #JR (023)
|
262
|
+
50539 => 'Sigma 50mm F1.4 DG DN | A', #JR (023)
|
259
263
|
|
260
264
|
50992 => 'Voigtlander SUPER WIDE-HELIAR 15mm F4.5 III', #JR
|
261
265
|
50993 => 'Voigtlander HELIAR-HYPER WIDE 10mm F5.6', #IB
|