exiftool_vendored 11.99.0 → 12.06.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of exiftool_vendored might be problematic. Click here for more details.

Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +119 -2
  3. data/bin/MANIFEST +5 -0
  4. data/bin/META.json +1 -1
  5. data/bin/META.yml +1 -1
  6. data/bin/README +32 -32
  7. data/bin/exiftool +55 -50
  8. data/bin/lib/Image/ExifTool.pm +155 -109
  9. data/bin/lib/Image/ExifTool.pod +103 -77
  10. data/bin/lib/Image/ExifTool/AIFF.pm +2 -2
  11. data/bin/lib/Image/ExifTool/APE.pm +2 -2
  12. data/bin/lib/Image/ExifTool/BuildTagLookup.pm +11 -6
  13. data/bin/lib/Image/ExifTool/Canon.pm +2 -1
  14. data/bin/lib/Image/ExifTool/CanonCustom.pm +82 -16
  15. data/bin/lib/Image/ExifTool/DPX.pm +56 -2
  16. data/bin/lib/Image/ExifTool/DarwinCore.pm +16 -3
  17. data/bin/lib/Image/ExifTool/Exif.pm +15 -6
  18. data/bin/lib/Image/ExifTool/Font.pm +9 -2
  19. data/bin/lib/Image/ExifTool/GIF.pm +5 -0
  20. data/bin/lib/Image/ExifTool/GeoTiff.pm +2 -0
  21. data/bin/lib/Image/ExifTool/GoPro.pm +10 -1
  22. data/bin/lib/Image/ExifTool/H264.pm +1 -1
  23. data/bin/lib/Image/ExifTool/ID3.pm +86 -12
  24. data/bin/lib/Image/ExifTool/Lang/de.pm +3 -1
  25. data/bin/lib/Image/ExifTool/Lang/es.pm +1 -1
  26. data/bin/lib/Image/ExifTool/M2TS.pm +1 -1
  27. data/bin/lib/Image/ExifTool/MacOS.pm +1 -1
  28. data/bin/lib/Image/ExifTool/Minolta.pm +3 -2
  29. data/bin/lib/Image/ExifTool/Nikon.pm +134 -15
  30. data/bin/lib/Image/ExifTool/Olympus.pm +34 -17
  31. data/bin/lib/Image/ExifTool/PNG.pm +14 -3
  32. data/bin/lib/Image/ExifTool/PPM.pm +5 -5
  33. data/bin/lib/Image/ExifTool/Panasonic.pm +147 -13
  34. data/bin/lib/Image/ExifTool/PanasonicRaw.pm +33 -0
  35. data/bin/lib/Image/ExifTool/Parrot.pm +2 -1
  36. data/bin/lib/Image/ExifTool/Pentax.pm +2 -1
  37. data/bin/lib/Image/ExifTool/Photoshop.pm +2 -1
  38. data/bin/lib/Image/ExifTool/QuickTime.pm +204 -27
  39. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +355 -19
  40. data/bin/lib/Image/ExifTool/README +20 -19
  41. data/bin/lib/Image/ExifTool/Ricoh.pm +19 -1
  42. data/bin/lib/Image/ExifTool/Shift.pl +1 -0
  43. data/bin/lib/Image/ExifTool/SigmaRaw.pm +40 -33
  44. data/bin/lib/Image/ExifTool/Sony.pm +376 -11
  45. data/bin/lib/Image/ExifTool/TagLookup.pm +1949 -1872
  46. data/bin/lib/Image/ExifTool/TagNames.pod +329 -53
  47. data/bin/lib/Image/ExifTool/Validate.pm +4 -4
  48. data/bin/lib/Image/ExifTool/WriteExif.pl +1 -0
  49. data/bin/lib/Image/ExifTool/WriteQuickTime.pl +23 -15
  50. data/bin/lib/Image/ExifTool/Writer.pl +44 -21
  51. data/bin/lib/Image/ExifTool/XMP.pm +41 -4
  52. data/bin/lib/Image/ExifTool/XMPStruct.pl +3 -1
  53. data/bin/lib/Image/ExifTool/ZISRAW.pm +123 -0
  54. data/bin/perl-Image-ExifTool.spec +31 -31
  55. data/lib/exiftool_vendored/version.rb +1 -1
  56. metadata +4 -3
@@ -19,9 +19,11 @@ use Image::ExifTool qw(:DataAccess :Utils);
19
19
  use Image::ExifTool::QuickTime;
20
20
 
21
21
  sub Process_tx3g($$$);
22
+ sub Process_marl($$$);
22
23
  sub Process_mebx($$$);
23
24
  sub ProcessFreeGPS($$$);
24
25
  sub ProcessFreeGPS2($$$);
26
+ sub Process360Fly($$$);
25
27
 
26
28
  # QuickTime data types that have ExifTool equivalents
27
29
  # (ref https://developer.apple.com/library/content/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW35)
@@ -70,6 +72,7 @@ my %processByMetaFormat = (
70
72
  meta => 1, # ('CTMD' in CR3 images, 'priv' unknown in DJI video)
71
73
  data => 1, # ('RVMI')
72
74
  sbtl => 1, # (subtitle; 'tx3g' in Yuneec drone videos)
75
+ ctbx => 1, # ('marl' in GM videos)
73
76
  );
74
77
 
75
78
  # data lengths for each INSV record type
@@ -91,7 +94,7 @@ my %insvLimit = (
91
94
  NOTES => q{
92
95
  Timed metadata extracted from QuickTime media data and some AVI videos when
93
96
  the ExtractEmbedded option is used. Although most of these tags are
94
- combined into the single table below, ExifTool currently reads 37 different
97
+ combined into the single table below, ExifTool currently reads 46 different
95
98
  formats of timed GPS metadata from video files.
96
99
  },
97
100
  VARS => { NO_ID => 1 },
@@ -173,6 +176,10 @@ my %insvLimit = (
173
176
  Name => 'rtmd',
174
177
  SubDirectory => { TagTable => 'Image::ExifTool::Sony::rtmd' },
175
178
  },
179
+ marl => {
180
+ Name => 'marl',
181
+ SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::marl' },
182
+ },
176
183
  CTMD => { # (Canon Timed MetaData)
177
184
  Name => 'CTMD',
178
185
  SubDirectory => { TagTable => 'Image::ExifTool::Canon::CTMD' },
@@ -548,6 +555,137 @@ my %insvLimit = (
548
555
  },
549
556
  );
550
557
 
558
+ %Image::ExifTool::QuickTime::Tags360Fly = (
559
+ PROCESS_PROC => \&Process360Fly,
560
+ NOTES => 'Timed metadata found in MP4 videos from the 360Fly.',
561
+ 1 => {
562
+ Name => 'Accel360Fly',
563
+ SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Accel360Fly' },
564
+ },
565
+ 2 => {
566
+ Name => 'Gyro360Fly',
567
+ SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Gyro360Fly' },
568
+ },
569
+ 3 => {
570
+ Name => 'Mag360Fly',
571
+ SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Mag360Fly' },
572
+ },
573
+ 5 => {
574
+ Name => 'GPS360Fly',
575
+ SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::GPS360Fly' },
576
+ },
577
+ 6 => {
578
+ Name => 'Rot360Fly',
579
+ SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Rot360Fly' },
580
+ },
581
+ 250 => {
582
+ Name => 'Fusion360Fly',
583
+ SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Fusion360Fly' },
584
+ },
585
+ );
586
+
587
+ %Image::ExifTool::QuickTime::Accel360Fly = (
588
+ PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
589
+ GROUPS => { 2 => 'Location' },
590
+ 1 => { Name => 'AccelMode', Unknown => 1 }, # (always 2 in my sample)
591
+ 2 => {
592
+ Name => 'SampleTime',
593
+ Groups => { 2 => 'Video' },
594
+ Format => 'int64u',
595
+ ValueConv => '$val / 1e6',
596
+ PrintConv => 'ConvertDuration($val)',
597
+ },
598
+ 10 => { Name => 'AccelYPR', Format => 'float[3]' },
599
+ );
600
+
601
+ %Image::ExifTool::QuickTime::Gyro360Fly = (
602
+ PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
603
+ GROUPS => { 2 => 'Location' },
604
+ 1 => { Name => 'GyroMode', Unknown => 1 }, # (always 1 in my sample)
605
+ 2 => {
606
+ Name => 'SampleTime',
607
+ Groups => { 2 => 'Video' },
608
+ Format => 'int64u',
609
+ ValueConv => '$val / 1e6',
610
+ PrintConv => 'ConvertDuration($val)',
611
+ },
612
+ 10 => { Name => 'GyroYPR', Format => 'float[3]' },
613
+ );
614
+
615
+ %Image::ExifTool::QuickTime::Mag360Fly = (
616
+ PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
617
+ GROUPS => { 2 => 'Location' },
618
+ 1 => { Name => 'MagMode', Unknown => 1 }, # (always 1 in my sample)
619
+ 2 => {
620
+ Name => 'SampleTime',
621
+ Groups => { 2 => 'Video' },
622
+ Format => 'int64u',
623
+ ValueConv => '$val / 1e6',
624
+ PrintConv => 'ConvertDuration($val)',
625
+ },
626
+ 10 => { Name => 'MagnetometerXYZ', Format => 'float[3]' },
627
+ );
628
+
629
+ %Image::ExifTool::QuickTime::GPS360Fly = (
630
+ PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
631
+ GROUPS => { 2 => 'Location' },
632
+ 1 => { Name => 'GPSMode', Unknown => 1 }, # (always 16 in my sample)
633
+ 2 => {
634
+ Name => 'SampleTime',
635
+ Groups => { 2 => 'Video' },
636
+ Format => 'int64u',
637
+ ValueConv => '$val / 1e6',
638
+ PrintConv => 'ConvertDuration($val)',
639
+ },
640
+ 10 => { Name => 'GPSLatitude', Format => 'float', PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")' },
641
+ 14 => { Name => 'GPSLongitude', Format => 'float', PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")' },
642
+ 18 => { Name => 'GPSAltitude', Format => 'float', PrintConv => '"$val m"' }, # (questionable accuracy)
643
+ 22 => {
644
+ Name => 'GPSSpeed',
645
+ Notes => 'converted to km/hr',
646
+ Format => 'int16u',
647
+ ValueConv => '$val * 0.036',
648
+ PrintConv => 'sprintf("%.1f",$val)',
649
+ },
650
+ 24 => { Name => 'GPSTrack', Format => 'int16u', ValueConv => '$val / 100' },
651
+ 26 => { Name => 'Acceleration', Format => 'int16u', ValueConv => '$val / 1000' },
652
+ );
653
+
654
+ %Image::ExifTool::QuickTime::Rot360Fly = (
655
+ PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
656
+ GROUPS => { 2 => 'Location' },
657
+ 1 => { Name => 'RotMode', Unknown => 1 }, # (always 1 in my sample)
658
+ 2 => {
659
+ Name => 'SampleTime',
660
+ Groups => { 2 => 'Video' },
661
+ Format => 'int64u',
662
+ ValueConv => '$val / 1e6',
663
+ PrintConv => 'ConvertDuration($val)',
664
+ },
665
+ 10 => { Name => 'RotationXYZ', Format => 'float[3]' },
666
+ );
667
+
668
+ %Image::ExifTool::QuickTime::Fusion360Fly = (
669
+ PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
670
+ GROUPS => { 2 => 'Location' },
671
+ 1 => { Name => 'FusionMode', Unknown => 1 }, # (always 0 in my sample)
672
+ 2 => {
673
+ Name => 'SampleTime',
674
+ Groups => { 2 => 'Video' },
675
+ Format => 'int64u',
676
+ ValueConv => '$val / 1e6',
677
+ PrintConv => 'ConvertDuration($val)',
678
+ },
679
+ 10 => { Name => 'FusionYPR', Format => 'float[3]' },
680
+ );
681
+
682
+ # tags found in 'marl' ctbx timed metadata (ref PH)
683
+ %Image::ExifTool::QuickTime::marl = (
684
+ PROCESS_PROC => \&Process_marl,
685
+ GROUPS => { 2 => 'Other' },
686
+ NOTES => 'Tags extracted from the marl ctbx timed metadata of GM cars.',
687
+ );
688
+
551
689
  #------------------------------------------------------------------------------
552
690
  # Save information from keys in OtherSampleDesc directory for processing timed metadata
553
691
  # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
@@ -648,7 +786,7 @@ sub FoundSomething($$;$$)
648
786
 
649
787
  #------------------------------------------------------------------------------
650
788
  # Approximate GPSDateTime value from sample time and CreateDate
651
- # Inputs: 0) ExifTool ref, 1) tag table ptr, 2) sample time (ms)
789
+ # Inputs: 0) ExifTool ref, 1) tag table ptr, 2) sample time (s)
652
790
  # 3) true if CreateDate is at end of video
653
791
  # Notes: Uses ExifTool CreateDateAtEnd as flag to subtract video duration
654
792
  sub SetGPSDateTime($$$)
@@ -696,7 +834,7 @@ sub HandleTextTags($$$)
696
834
 
697
835
  #------------------------------------------------------------------------------
698
836
  # Process subtitle 'text'
699
- # Inputs: 0) ExifTool ref, 1) tag table ref, 2) data ref, 3) optional sample time
837
+ # Inputs: 0) ExifTool ref, 1) tag table ref, 2) data ref
700
838
  sub Process_text($$$)
701
839
  {
702
840
  my ($et, $tagTbl, $buffPt) = @_;
@@ -876,7 +1014,28 @@ sub Process_text($$$)
876
1014
  return;
877
1015
  }
878
1016
 
879
- # check for Thinkware format, eg:
1017
+ # check for Roadhawk dashcam text
1018
+ # ".;;;;D?JL;6+;;;D;R?;4;;;;DBB;;O;;;=D;L;;HO71G>F;-?=J-F:FNJJ;DPP-JF3F;;PL=DBRLBF0F;=?DNF-RD-PF;N;?=JF;;?D=F:*6F~"
1019
+ # decoded:
1020
+ # "X0000.2340Y-000.0720Z0000.9900G0001.0400$GPRMC,082138,A,5330.6683,N,00641.9749,W,012.5,87.86,050213,002.1,A"
1021
+ # (note: "002.1" is magnetic variation and is not decoded; it should have ",E" or ",W" afterward for direction)
1022
+ if ($$buffPt =~ /\*[0-9A-F]{2}~$/) {
1023
+ # (ref https://reverseengineering.stackexchange.com/questions/11582/how-to-reverse-engineer-dash-cam-metadata)
1024
+ my @decode = unpack 'C*', '-I8XQWRVNZOYPUTA0B1C2SJ9K.L,M$D3E4F5G6H7';
1025
+ my @chars = unpack 'C*', substr($$buffPt, 0, -4);
1026
+ foreach (@chars) {
1027
+ my $n = $_ - 43;
1028
+ $_ = $decode[$n] if $n >= 0 and defined $decode[$n];
1029
+ }
1030
+ my $buff = pack 'C*', @chars;
1031
+ if ($buff =~ /X(.*?)Y(.*?)Z(.*?)G(.*?)\$/) {
1032
+ # yup. the decoding worked out
1033
+ $tags{Accelerometer} = "$1 $2 $3 $4";
1034
+ $$buffPt = $buff; # (process GPRMC below)
1035
+ }
1036
+ }
1037
+
1038
+ # check for Thinkware format (and other NMEA RMC), eg:
880
1039
  # "gsensori,4,512,-67,-12,100;GNRMC,161313.00,A,4529.87489,N,07337.01215,W,6.225,35.34,310819,,,A*52..;
881
1040
  # CAR,0,0,0,0.0,0,0,0,0,0,0,0,0"
882
1041
  if ($$buffPt =~ /[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+)/ and
@@ -1080,8 +1239,8 @@ sub ProcessSamples($)
1080
1239
  $$et{ee} = $ee; # need ee information for 'keys'
1081
1240
  $et->HandleTag($tagTbl, $metaFormat, undef,
1082
1241
  DataPt => \$buff,
1083
- DataPos => $$start[$i],
1084
- Base => $$start[$i],
1242
+ DataPos => 0,
1243
+ Base => $$start[$i], # (Base must be set for CR3 files)
1085
1244
  TagInfo => $tagInfo,
1086
1245
  );
1087
1246
  delete $$et{ee};
@@ -1093,7 +1252,7 @@ sub ProcessSamples($)
1093
1252
  Process_text($et, $tagTbl, \$buff);
1094
1253
  }
1095
1254
  } elsif ($verbose) {
1096
- $et->VPrint(0, "Unknown meta format ($metaFormat)");
1255
+ $et->VPrint(0, "Unknown $type format ($metaFormat)");
1097
1256
  }
1098
1257
 
1099
1258
  } elsif ($type eq 'gps ') { # (ie. GPSDataList tag)
@@ -1115,8 +1274,8 @@ sub ProcessSamples($)
1115
1274
  FoundSomething($et, $tagTbl, $time[$i], $dur[$i]);
1116
1275
  $et->HandleTag($tagTbl, $type, undef,
1117
1276
  DataPt => \$buff,
1118
- DataPos => $$start[$i],
1119
- Base => $$start[$i],
1277
+ DataPos => 0,
1278
+ Base => $$start[$i], # (Base must be set for CR3 files)
1120
1279
  TagInfo => $tagInfo,
1121
1280
  );
1122
1281
  }
@@ -1150,13 +1309,35 @@ sub ProcessFreeGPS($$$)
1150
1309
 
1151
1310
  return 0 if $dirLen < 92;
1152
1311
 
1153
- if (substr($$dataPt,12,1) eq "\x05") {
1312
+ if (substr($$dataPt,18,8) eq "\xaa\xaa\xf2\xe1\xf0\xee\x54\x54") {
1154
1313
 
1314
+ # (this is very similar to the encrypted text format)
1155
1315
  # decode encrypted ASCII-based GPS (DashCam Azdome GS63H, ref 5)
1156
1316
  # header looks like this in my sample:
1157
1317
  # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 05 01 00 00 [....freeGPS ....]
1158
1318
  # 0010: 01 03 aa aa f2 e1 f0 ee 54 54 98 9a 9b 92 9a 93 [........TT......]
1159
1319
  # 0020: 98 9e 98 98 9e 93 98 92 a6 9f 9f 9c 9d ed fa 8a [................]
1320
+ # decrypted (from byte 18):
1321
+ # 0000: 00 00 58 4b 5a 44 fe fe 32 30 31 38 30 39 32 34 [..XKZD..20180924]
1322
+ # 0010: 32 32 34 39 32 38 0c 35 35 36 37 47 50 20 20 20 [224928.5567GP ]
1323
+ # 0020: 00 00 00 00 00 03 4e 34 30 34 36 34 33 35 30 57 [......N40464350W]
1324
+ # 0030: 30 30 37 30 34 30 33 30 38 30 30 30 30 30 30 30 [0070403080000000]
1325
+ # 0040: 37 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [7...............]
1326
+ # [...]
1327
+ # 00a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 2b 30 39 [.............+09]
1328
+ # 00b0: 33 2d 30 30 33 2d 30 30 35 00 00 00 00 00 00 00 [3-003-005.......]
1329
+ # header looks like this for EEEkit gps:
1330
+ # 0000: 00 00 04 00 66 72 65 65 47 50 53 20 f0 03 00 00 [....freeGPS ....]
1331
+ # 0010: 01 03 aa aa f2 e1 f0 ee 54 54 98 9a 98 9a 9a 9f [........TT......]
1332
+ # 0020: 9b 93 9b 9c 98 99 99 9f a6 9a 9a 98 9a 9a 9f 9b [................]
1333
+ # 0030: 93 9b 9c 98 99 99 9c a9 e4 99 9d 9e 9f 98 9e 9b [................]
1334
+ # 0040: 9c fd 9b 98 98 98 9f 9f 9a 9a 93 81 9a 9b 9d 9f [................]
1335
+ # decrypted (from byte 18):
1336
+ # 0000: 00 00 58 4b 5a 44 fe fe 32 30 32 30 30 35 31 39 [..XKZD..20200519]
1337
+ # 0010: 31 36 32 33 33 35 0c 30 30 32 30 30 35 31 39 31 [162335.002005191]
1338
+ # 0020: 36 32 33 33 36 03 4e 33 37 34 35 32 34 31 36 57 [62336.N37452416W]
1339
+ # 0030: 31 32 32 32 35 35 30 30 39 2b 30 31 37 35 30 31 [122255009+017501]
1340
+ # 0040: 31 2b 30 31 34 2b 30 30 32 2b 30 32 36 2b 30 31 [1+014+002+026+01]
1160
1341
  my $n = $dirLen - 18;
1161
1342
  $n = 0x101 if $n > 0x101;
1162
1343
  my $buf2 = pack 'C*', map { $_ ^ 0xaa } unpack 'C*', substr($$dataPt,18,$n);
@@ -1165,13 +1346,25 @@ sub ProcessFreeGPS($$$)
1165
1346
  $et->VerboseDump(\$buf2);
1166
1347
  }
1167
1348
  # (extract longitude as 9 digits, not 8, ref PH)
1168
- return 0 unless $buf2 =~ /^.{8}(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2}).(.{15})([NS])(\d{8})([EW])(\d{9})(\d{8})/s;
1349
+ return 0 unless $buf2 =~ /^.{8}(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2}).(.{15})([NS])(\d{8})([EW])(\d{9})(\d{8})?/s;
1169
1350
  ($yr,$mon,$day,$hr,$min,$sec,$lbl,$latRef,$lat,$lonRef,$lon,$spd) = ($1,$2,$3,$4,$5,$6,$7,$8,$9/1e4,$10,$11/1e4,$12);
1170
- $spd += 0; # remove leading 0's
1351
+ if (defined $spd) { # (Azdome)
1352
+ $spd += 0; # remove leading 0's
1353
+ } elsif ($buf2 =~ /^.{57}([-+]\d{4})(\d{3})/s) { # (EEEkit)
1354
+ # $alt = $1 + 0; (doesn't look right for my sample, but the Ambarella A12 text has this)
1355
+ $spd = $2 + 0;
1356
+ }
1171
1357
  $lbl =~ s/\0.*//s; $lbl =~ s/\s+$//; # truncate at null and remove trailing spaces
1172
1358
  push @xtra, UserLabel => $lbl if length $lbl;
1173
1359
  # extract accelerometer data (ref PH)
1174
- @acc = ($1/100,$2/100,$3/100) if $buf2 =~ /^.{173}([-+]\d{3})([-+]\d{3})([-+]\d{3})/s;
1360
+ if ($buf2 =~ /^.{65}(([-+]\d{3})([-+]\d{3})([-+]\d{3})([-+]\d{3})*)/s) {
1361
+ $_ = $1;
1362
+ @acc = ($2/100, $3/100, $4/100);
1363
+ s/([-+])/ $1/g; s/^ //;
1364
+ push @xtra, AccelerometerData => $_;
1365
+ } elsif ($buf2 =~ /^.{173}([-+]\d{3})([-+]\d{3})([-+]\d{3})/s) { # (Azdome)
1366
+ @acc = ($1/100, $2/100, $3/100);
1367
+ }
1175
1368
 
1176
1369
  } elsif ($$dataPt =~ /^.{52}(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/s) {
1177
1370
 
@@ -1222,12 +1415,12 @@ sub ProcessFreeGPS($$$)
1222
1415
 
1223
1416
  # decode freeGPS from Akaso dashcam
1224
1417
  # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 60 00 00 00 [....freeGPS `...]
1225
- # 0000: 78 2e 78 78 00 00 00 00 00 00 00 00 00 00 00 00 [x.xx............]
1226
- # 0000: 30 30 30 30 30 00 00 00 00 00 00 00 00 00 00 00 [00000...........]
1227
- # 0000: 12 00 00 00 2f 00 00 00 19 00 00 00 41 00 00 00 [..../.......A...]
1228
- # 0000: 13 b3 ca 44 4e 00 00 00 29 92 fb 45 45 00 00 00 [...DN...)..EE...]
1229
- # 0000: d9 ee b4 41 ec d1 d3 42 e4 07 00 00 01 00 00 00 [...A...B........]
1230
- # 0000: 0c 00 00 00 01 00 00 00 05 00 00 00 00 00 00 00 [................]
1418
+ # 0010: 78 2e 78 78 00 00 00 00 00 00 00 00 00 00 00 00 [x.xx............]
1419
+ # 0020: 30 30 30 30 30 00 00 00 00 00 00 00 00 00 00 00 [00000...........]
1420
+ # 0030: 12 00 00 00 2f 00 00 00 19 00 00 00 41 00 00 00 [..../.......A...]
1421
+ # 0040: 13 b3 ca 44 4e 00 00 00 29 92 fb 45 45 00 00 00 [...DN...)..EE...]
1422
+ # 0050: d9 ee b4 41 ec d1 d3 42 e4 07 00 00 01 00 00 00 [...A...B........]
1423
+ # 0060: 0c 00 00 00 01 00 00 00 05 00 00 00 00 00 00 00 [................]
1231
1424
  ($latRef, $lonRef) = ($1, $2);
1232
1425
  ($hr, $min, $sec, $yr, $mon, $day) = unpack('x48V3x28V3', $$dataPt);
1233
1426
  SetByteOrder('II');
@@ -1238,6 +1431,56 @@ sub ProcessFreeGPS($$$)
1238
1431
  $trk -= 360 if $trk >= 360;
1239
1432
  SetByteOrder('MM');
1240
1433
 
1434
+ } elsif ($$dataPt =~ /^.{16}YndAkasoCar/s) {
1435
+
1436
+ # Akaso V1 dascham
1437
+ # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 78 00 00 00 [....freeGPS x...]
1438
+ # 0010: 59 6e 64 41 6b 61 73 6f 43 61 72 00 00 00 00 00 [YndAkasoCar.....]
1439
+ # 0020: 30 30 30 30 30 00 00 00 00 00 00 00 00 00 00 00 [00000...........]
1440
+ # 0030: 0e 00 00 00 27 00 00 00 2c 00 00 00 e3 07 00 00 [....'...,.......]
1441
+ # 0040: 05 00 00 00 1d 00 00 00 41 4e 45 00 00 00 00 00 [........ANE.....]
1442
+ # 0050: f1 4e 3e 3d 90 df ca 40 e3 50 bf 0b 0b 31 a0 40 [.N>=...@.P...1.@]
1443
+ # 0060: 4b dc c8 41 9a 79 a7 43 34 58 43 31 4f 37 31 35 [K..A.y.C4XC1O715]
1444
+ # 0070: 35 31 32 36 36 35 37 35 59 4e 44 53 0d e7 cc f9 [51266575YNDS....]
1445
+ # 0080: 00 00 00 00 05 00 00 00 00 00 00 00 00 00 00 00 [................]
1446
+ ($hr,$min,$sec,$yr,$mon,$day,$stat,$latRef,$lonRef) =
1447
+ unpack('x48V6a1a1a1x1', $$dataPt);
1448
+ # ignore invalid fixes
1449
+ return 0 unless $stat eq 'A' and ($latRef eq 'N' or $latRef eq 'S') and
1450
+ ($lonRef eq 'E' or $lonRef eq 'W');
1451
+
1452
+ $et->WarnOnce("Can't yet decrypt Akaso V1 timed GPS", 1);
1453
+ # (see https://exiftool.org/forum/index.php?topic=11320.0)
1454
+ return 1;
1455
+
1456
+ SetByteOrder('II');
1457
+ $lat = GetDouble($dataPt, 0x50); # latitude is here, but encrypted somehow
1458
+ $lon = GetDouble($dataPt, 0x58); # longitude is here, but encrypted somehow
1459
+ SetByteOrder('MM');
1460
+ #my $serialNum = substr($$dataPt, 0x68, 20);
1461
+
1462
+ } elsif ($$dataPt =~ /^.{12}\xac\0\0\0.{44}(.{72})/s) {
1463
+
1464
+ # EACHPAI dash cam
1465
+ # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 ac 00 00 00 [....freeGPS ....]
1466
+ # 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
1467
+ # 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
1468
+ # 0030: 00 00 00 00 00 00 00 00 00 00 00 00 34 57 60 62 [............4W`b]
1469
+ # 0040: 5d 53 3c 41 47 45 45 42 42 3e 40 40 40 3c 51 3c []S<AGEEBB>@@@<Q<]
1470
+ # 0050: 44 42 44 40 3e 48 46 43 45 3c 5e 3c 40 48 43 41 [DBD@>HFCE<^<@HCA]
1471
+ # 0060: 42 3e 46 42 47 48 3c 67 3c 40 3e 40 42 3c 43 3e [B>FBGH<g<@>@B<C>]
1472
+ # 0070: 43 41 3c 40 42 40 46 42 40 3c 3c 3c 51 3a 47 46 [CA<@B@FB@<<<Q:GF]
1473
+ # 0080: 00 2a 36 35 00 00 00 00 00 00 00 00 00 00 00 00 [.*65............]
1474
+
1475
+ $et->WarnOnce("Can't yet decrypt EACHPAI timed GPS", 1);
1476
+ # (see https://exiftool.org/forum/index.php?topic=5095.msg61266#msg61266)
1477
+ return 1;
1478
+
1479
+ my $time = pack 'C*', map { $_ ^= 0 } unpack 'C*', $1;
1480
+ # bytes 7-12 are the timestamp in ASCII HHMMSS after xor-ing with 0x70
1481
+ substr($time,7,6) = pack 'C*', map { $_ ^= 0x70 } unpack 'C*', substr($time,7,6);
1482
+ # (other values are currently unknown)
1483
+
1241
1484
  } else {
1242
1485
 
1243
1486
  # decode binary GPS format (Viofo A119S, ref 2)
@@ -1252,6 +1495,21 @@ sub ProcessFreeGPS($$$)
1252
1495
  return 0 unless $stat eq 'A' and ($latRef eq 'N' or $latRef eq 'S') and
1253
1496
  ($lonRef eq 'E' or $lonRef eq 'W');
1254
1497
  ($lat,$lon,$spd,$trk) = unpack 'f*', pack 'L*', $lat, $lon, $spd, $trk;
1498
+ # lat/lon also stored as doubles by Transcend Driver Pro 230 (ref PH)
1499
+ SetByteOrder('II');
1500
+ my ($lat2, $lon2, $alt2) = (
1501
+ GetDouble($dataPt, 0x70),
1502
+ GetDouble($dataPt, 0x80),
1503
+ # GetDouble($dataPt, 0x98), # (don't know what this is)
1504
+ GetDouble($dataPt,0xa0),
1505
+ # GetDouble($dataPt,0xa8)) # (don't know what this is)
1506
+ );
1507
+ if (abs($lat2-$lat) < 0.001 and abs($lon2-$lon) < 0.001) {
1508
+ $lat = $lat2;
1509
+ $lon = $lon2;
1510
+ $alt = $alt2;
1511
+ }
1512
+ SetByteOrder('MM');
1255
1513
  $yr += 2000 if $yr < 2000;
1256
1514
  $spd *= $knotsToKph; # convert speed to km/h
1257
1515
  # ($trk is not confirmed; may be GPSImageDirection, ref PH)
@@ -1644,6 +1902,33 @@ sub ParseTag($$$)
1644
1902
  }
1645
1903
  $$et{HandlerType} = $tag; # fake handler type
1646
1904
  ProcessSamples($et); # we have all we need to process sample data now
1905
+ } elsif ($tag eq 'GPS ') {
1906
+ my $pos = 0;
1907
+ my $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream');
1908
+ SetByteOrder('II');
1909
+ while ($pos + 36 < $dataLen) {
1910
+ my $dat = substr($$dataPt, $pos, 36);
1911
+ last if $dat eq "\x0" x 36;
1912
+ my @a = unpack 'VVVVCVCV', $dat;
1913
+ $$et{DOC_NUM} = ++$$et{DOC_COUNT};
1914
+ # 0=1, 1=1, 2=secs, 3=?
1915
+ SetGPSDateTime($et, $tagTbl, $a[2]);
1916
+ my $lat = $a[5] / 1e3;
1917
+ my $lon = $a[7] / 1e3;
1918
+ my $deg = int($lat / 100);
1919
+ $lat = $deg + ($lat - $deg * 100) / 60;
1920
+ $deg = int($lon / 100);
1921
+ $lon = $deg + ($lon - $deg * 100) / 60;
1922
+ $lat = -$lat if $a[4] eq 'S';
1923
+ $lon = -$lon if $a[6] eq 'W';
1924
+ $et->HandleTag($tagTbl, GPSLatitude => $lat);
1925
+ $et->HandleTag($tagTbl, GPSLongitude => $lon);
1926
+ $et->HandleTag($tagTbl, GPSSpeed => $a[3] / 1e3);
1927
+ $et->HandleTag($tagTbl, GPSSpeedRef => 'K');
1928
+ $pos += 36;
1929
+ }
1930
+ SetByteOrder('MM');
1931
+ delete $$et{DOC_NUM};
1647
1932
  }
1648
1933
  }
1649
1934
 
@@ -1661,6 +1946,26 @@ sub Process_tx3g($$$)
1661
1946
  return 1;
1662
1947
  }
1663
1948
 
1949
+ #------------------------------------------------------------------------------
1950
+ # Process GM 'marl' ctbx metadata (ref PH)
1951
+ # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
1952
+ # Returns: 1 on success
1953
+ sub Process_marl($$$)
1954
+ {
1955
+ my ($et, $dirInfo, $tagTablePtr) = @_;
1956
+ my $dataPt = $$dirInfo{DataPt};
1957
+ return 0 if length $$dataPt < 2;
1958
+
1959
+ # 8-byte records:
1960
+ # byte 0 seems to be tag ID (0=timestamp in sec * 1e7)
1961
+ # bytes 1-3 seem to be 24-bit signed integer (unknown meaning)
1962
+ # bytes 4-7 are an int32u value, usually a multiple of 10000
1963
+
1964
+ $et->WarnOnce("Can't yet decode timed GM data", 1);
1965
+ # (see https://exiftool.org/forum/index.php?topic=11335.msg61393#msg61393)
1966
+ return 1;
1967
+ }
1968
+
1664
1969
  #------------------------------------------------------------------------------
1665
1970
  # Process QuickTime 'mebx' timed metadata
1666
1971
  # Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
@@ -2189,6 +2494,37 @@ sub ProcessInsta360($;$)
2189
2494
  return 1;
2190
2495
  }
2191
2496
 
2497
+ #------------------------------------------------------------------------------
2498
+ # Process 360Fly 'uuid' atom containing sensor data
2499
+ # (ref https://github.com/JamesHeinrich/getID3/blob/master/getid3/module.audio-video.quicktime.php)
2500
+ # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
2501
+ # Returns: 1 on success
2502
+ sub Process360Fly($$$)
2503
+ {
2504
+ my ($et, $dirInfo, $tagTbl) = @_;
2505
+ my $dataPt = $$dirInfo{DataPt};
2506
+ my $dataLen = length $$dataPt;
2507
+ my $pos = 16;
2508
+ my $lastTime = -1;
2509
+ my $streamTbl = GetTagTable('Image::ExifTool::QuickTime::Stream');
2510
+ while ($pos + 32 <= $dataLen) {
2511
+ my $type = ord substr $$dataPt, $pos, 1;
2512
+ my $time = Get64u($dataPt, $pos + 2); # (only valid for some types)
2513
+ if ($$tagTbl{$type}) {
2514
+ if ($time != $lastTime) {
2515
+ $$et{DOC_NUM} = ++$$et{DOC_COUNT};
2516
+ $lastTime = $time;
2517
+ }
2518
+ }
2519
+ $et->HandleTag($tagTbl, $type, undef, DataPt => $dataPt, Start => $pos, Size => 32);
2520
+ # synthesize GPSDateTime from the timestamp for GPS records
2521
+ SetGPSDateTime($et, $streamTbl, $time / 1e6) if $type == 5;
2522
+ $pos += 32;
2523
+ }
2524
+ delete $$et{DOC_NUM};
2525
+ return 1;
2526
+ }
2527
+
2192
2528
  #------------------------------------------------------------------------------
2193
2529
  # Scan media data for "freeGPS" metadata if not found already (ref PH)
2194
2530
  # Inputs: 0) ExifTool ref