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.
@@ -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 63 different formats of timed GPS metadata from video files.
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
- sub Process_text($$$)
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 (defined $alt) {
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
- if ($id == 0x300) {
2696
- if ($len % 20 and not $len % 56) {
2697
- $dlen = 56;
2698
- } elsif ($len % 56 and not $len % 20) {
2699
- $dlen = 20;
2700
- } else {
2701
- if ($raf->Read($buff, 20) == 20) {
2702
- if (substr($buff, 16, 3) eq "\0\0\0") {
2703
- $dlen = 56;
2704
- } else {
2705
- $dlen = 20;
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
- $raf->Seek($epos, 2) or last;
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.06';
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.56';
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