exiftool_vendored 12.06.0 → 12.12.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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +96 -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 +43 -42
  7. data/bin/exiftool +156 -82
  8. data/bin/lib/Image/ExifTool.pm +22 -13
  9. data/bin/lib/Image/ExifTool.pod +59 -50
  10. data/bin/lib/Image/ExifTool/BuildTagLookup.pm +11 -5
  11. data/bin/lib/Image/ExifTool/Canon.pm +202 -13
  12. data/bin/lib/Image/ExifTool/DarwinCore.pm +9 -3
  13. data/bin/lib/Image/ExifTool/EXE.pm +8 -5
  14. data/bin/lib/Image/ExifTool/GIF.pm +2 -2
  15. data/bin/lib/Image/ExifTool/Geotag.pm +30 -11
  16. data/bin/lib/Image/ExifTool/GoPro.pm +47 -30
  17. data/bin/lib/Image/ExifTool/IPTC.pm +1 -0
  18. data/bin/lib/Image/ExifTool/Import.pm +14 -11
  19. data/bin/lib/Image/ExifTool/JSON.pm +27 -4
  20. data/bin/lib/Image/ExifTool/MPF.pm +2 -2
  21. data/bin/lib/Image/ExifTool/MacOS.pm +153 -37
  22. data/bin/lib/Image/ExifTool/Matroska.pm +3 -1
  23. data/bin/lib/Image/ExifTool/Minolta.pm +5 -1
  24. data/bin/lib/Image/ExifTool/Nikon.pm +11 -3
  25. data/bin/lib/Image/ExifTool/Olympus.pm +8 -1
  26. data/bin/lib/Image/ExifTool/Panasonic.pm +12 -12
  27. data/bin/lib/Image/ExifTool/PanasonicRaw.pm +1 -0
  28. data/bin/lib/Image/ExifTool/Pentax.pm +10 -3
  29. data/bin/lib/Image/ExifTool/QuickTime.pm +51 -16
  30. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +68 -45
  31. data/bin/lib/Image/ExifTool/README +5 -2
  32. data/bin/lib/Image/ExifTool/RSRC.pm +17 -11
  33. data/bin/lib/Image/ExifTool/Radiance.pm +7 -2
  34. data/bin/lib/Image/ExifTool/Sony.pm +56 -35
  35. data/bin/lib/Image/ExifTool/Stim.pm +2 -2
  36. data/bin/lib/Image/ExifTool/TagLookup.pm +5756 -5710
  37. data/bin/lib/Image/ExifTool/TagNames.pod +248 -49
  38. data/bin/lib/Image/ExifTool/WriteQuickTime.pl +7 -6
  39. data/bin/lib/Image/ExifTool/Writer.pl +5 -3
  40. data/bin/lib/Image/ExifTool/XMP.pm +63 -18
  41. data/bin/lib/Image/ExifTool/XMP2.pl +1 -0
  42. data/bin/perl-Image-ExifTool.spec +42 -41
  43. data/lib/exiftool_vendored/version.rb +1 -1
  44. metadata +7 -7
@@ -512,6 +512,7 @@ my %panasonicWhiteBalance = ( #forum9396
512
512
  # when format is int32u (S models), these values have been observed (ref IB):
513
513
  # 256 - Leica lens
514
514
  # 257 - Lumix lens
515
+ # 258 - ? (seen once)
515
516
  },
516
517
  0x1202 => { #IB
517
518
  Name => 'LensTypeModel',
@@ -58,7 +58,7 @@ use Image::ExifTool::Exif;
58
58
  use Image::ExifTool::GPS;
59
59
  use Image::ExifTool::HP;
60
60
 
61
- $VERSION = '3.34';
61
+ $VERSION = '3.35';
62
62
 
63
63
  sub CryptShutterCount($$);
64
64
  sub PrintFilter($$$);
@@ -2894,13 +2894,20 @@ my %binaryDataAttrs = (
2894
2894
  Writable => 'string',
2895
2895
  Notes => 'left blank by some cameras',
2896
2896
  },
2897
- 0x022a => { #PH (K-5)
2897
+ 0x022a => [{ #PH (RICOH models (GR III))
2898
+ Name => 'FilterInfo',
2899
+ Condition => '$$self{Make} =~ /^RICOH/',
2900
+ SubDirectory => {
2901
+ TagTable => 'Image::ExifTool::Pentax::FilterInfo',
2902
+ ByteOrder => 'LittleEndian',
2903
+ },
2904
+ },{ #PH (K-5)
2898
2905
  Name => 'FilterInfo',
2899
2906
  SubDirectory => {
2900
2907
  TagTable => 'Image::ExifTool::Pentax::FilterInfo',
2901
2908
  ByteOrder => 'BigEndian',
2902
2909
  },
2903
- },
2910
+ }],
2904
2911
  0x022b => { #PH (K-5)
2905
2912
  Name => 'LevelInfo',
2906
2913
  SubDirectory => { TagTable => 'Image::ExifTool::Pentax::LevelInfo' },
@@ -47,7 +47,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
47
47
  use Image::ExifTool::Exif;
48
48
  use Image::ExifTool::GPS;
49
49
 
50
- $VERSION = '2.52';
50
+ $VERSION = '2.55';
51
51
 
52
52
  sub ProcessMOV($$;$);
53
53
  sub ProcessKeys($$$);
@@ -217,8 +217,13 @@ my %ftypLookup = (
217
217
  # information for time/date-based tags (time zero is Jan 1, 1904)
218
218
  my %timeInfo = (
219
219
  Notes => 'converted from UTC to local time if the QuickTimeUTC option is set',
220
+ Shift => 'Time',
221
+ Writable => 1,
222
+ Permanent => 1,
223
+ DelValue => 0,
220
224
  # It is not uncommon for brain-dead software to use the wrong time zero,
221
225
  # so assume a time zero of Jan 1, 1970 if the date is before this
226
+ # Note: This value will be in UTC if generated by a system that is aware of the time zone
222
227
  RawConv => q{
223
228
  my $offset = (66 * 365 + 17) * 24 * 3600;
224
229
  return $val - $offset if $val >= $offset or $$self{OPTIONS}{QuickTimeUTC};
@@ -227,12 +232,17 @@ my %timeInfo = (
227
232
  }
228
233
  return $val;
229
234
  },
230
- Shift => 'Time',
231
- Writable => 1,
232
- Permanent => 1,
233
- DelValue => 0,
234
- # Note: This value will be in UTC if generated by a system that is aware of the time zone
235
- ValueConv => 'ConvertUnixTime($val, $self->Options("QuickTimeUTC"))',
235
+ RawConvInv => q{
236
+ if ($$self{FileType} eq 'CR3' and not $self->Options('QuickTimeUTC')) {
237
+ # convert to UTC
238
+ my $offset = (66 * 365 + 17) * 24 * 3600;
239
+ $val = ConvertUnixTime($val - $offset);
240
+ $val = GetUnixTime($val, 1) + $offset;
241
+ }
242
+ return $val;
243
+ },
244
+ # (all CR3 files store UTC times - PH)
245
+ ValueConv => 'ConvertUnixTime($val, $self->Options("QuickTimeUTC") || $$self{FileType} eq "CR3")',
236
246
  ValueConvInv => 'GetUnixTime($val, $self->Options("QuickTimeUTC")) + (66 * 365 + 17) * 24 * 3600',
237
247
  PrintConv => '$self->ConvertDateTime($val)',
238
248
  PrintConvInv => '$self->InverseDateTime($val)',
@@ -607,6 +617,11 @@ my %eeBox = (
607
617
  Groups => { 2 => 'Preview' },
608
618
  Binary => 1,
609
619
  },
620
+ 'thm ' => { #PH (70mai A800)
621
+ Name => 'ThumbnailImage',
622
+ Groups => { 2 => 'Preview' },
623
+ Binary => 1,
624
+ },
610
625
  ardt => { #PH
611
626
  Name => 'ARDroneFile',
612
627
  ValueConv => 'length($val) > 4 ? substr($val,4) : $val', # remove length
@@ -1913,7 +1928,7 @@ my %eeBox = (
1913
1928
  # SETT? 12 bytes (Hero4)
1914
1929
  # MUID? 32 bytes (Hero4, starts with serial number hash)
1915
1930
  # HMMT? 404 bytes (Hero4, all zero)
1916
- # BCID? 26 bytes (Hero5, all zero)
1931
+ # BCID? 26 bytes (Hero5, all zero), 36 bytes GoPro Max
1917
1932
  # GUMI? 16 bytes (Hero5)
1918
1933
  "FOV\0" => 'FieldOfView', #forum8938 (Hero2) seen: "Wide"
1919
1934
  GPMF => {
@@ -2550,7 +2565,23 @@ my %eeBox = (
2550
2565
  Start => 4,
2551
2566
  },
2552
2567
  },
2553
- # idat
2568
+ idat => {
2569
+ Name => 'MetaImageSize', #PH (NC)
2570
+ Format => 'int16u',
2571
+ # (don't know what the first two numbers are for)
2572
+ PrintConv => '$val =~ s/^(\d+) (\d+) (\d+) (\d+)/${3}x$4/; $val',
2573
+ },
2574
+ uuid => [
2575
+ { #PH (Canon R5/R6 HIF)
2576
+ Name => 'MetaVersion', # (NC)
2577
+ Condition => '$$valPt=~/^\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48/',
2578
+ RawConv => 'substr($val, 0x14)',
2579
+ },
2580
+ {
2581
+ Name => 'UUID-Unknown',
2582
+ %unknownInfo,
2583
+ },
2584
+ ],
2554
2585
  );
2555
2586
 
2556
2587
  # additional metadata container (ref ISO14496-12:2015)
@@ -2862,12 +2893,16 @@ my %eeBox = (
2862
2893
  WRITE_PROC => \&WriteQuickTime,
2863
2894
  GROUPS => { 2 => 'Image' },
2864
2895
  # (Note: ExifTool's ItemRefVersion may be used to test the iref version number)
2865
- # dimg - DerivedImage
2866
- # thmb - Thumbnail
2867
- # auxl - AuxiliaryImage
2896
+ NOTES => q{
2897
+ The Item reference entries listed in the table below contain information about
2898
+ the associations between items in the file. This information is used by
2899
+ ExifTool, but these entries are not extracted as tags.
2900
+ },
2901
+ dimg => { Name => 'DerivedImageRef', RawConv => 'undef' },
2902
+ thmb => { Name => 'ThumbnailRef', RawConv => 'undef' },
2903
+ auxl => { Name => 'AuxiliaryImageRef', RawConv => 'undef' },
2868
2904
  cdsc => {
2869
2905
  Name => 'ContentDescribes',
2870
- Notes => 'parsed, but not extracted as a tag',
2871
2906
  RawConv => \&ParseContentDescribes,
2872
2907
  WriteHook => \&ParseContentDescribes,
2873
2908
  },
@@ -6861,7 +6896,7 @@ my %eeBox = (
6861
6896
  #
6862
6897
  # AudioFormat Offset Child atoms
6863
6898
  # ----------- ------ ----------------
6864
- # mp4a 52 * wave, chan, esds, SA3D(Insta360 spherical video params?)
6899
+ # mp4a 52 * wave, chan, esds, SA3D(Insta360 spherical video params?,also GoPro Max)
6865
6900
  # in24 52 wave, chan
6866
6901
  # "ms\0\x11" 52 wave
6867
6902
  # sowt 52 chan
@@ -8613,10 +8648,10 @@ sub ProcessSampleDesc($$$)
8613
8648
  my $dirLen = $$dirInfo{DirLen} || (length($$dataPt) - $pos);
8614
8649
  return 0 if $pos + 8 > $dirLen;
8615
8650
 
8616
- my $num = Get32u($dataPt, 4); # get number of sample descriptions in table
8651
+ my $num = Get32u($dataPt, 4); # get number of sample entries in table
8617
8652
  $pos += 8;
8618
8653
  my $i;
8619
- for ($i=0; $i<$num; ++$i) { # loop through sample descriptions
8654
+ for ($i=0; $i<$num; ++$i) { # loop through sample entries
8620
8655
  last if $pos + 8 > $dirLen;
8621
8656
  my $size = Get32u($dataPt, $pos);
8622
8657
  last if $pos + $size > $dirLen;
@@ -10,6 +10,7 @@
10
10
  # 3) https://forum.flitsservice.nl/dashcam-info/dod-ls460w-gps-data-uit-mov-bestand-lezen-t87926.html
11
11
  # 4) https://developers.google.com/streetview/publish/camm-spec
12
12
  # 5) https://sergei.nz/extracting-gps-data-from-viofo-a119-and-other-novatek-powered-cameras/
13
+ # 6) Thomas Allen https://github.com/exiftool/exiftool/pull/62
13
14
  #------------------------------------------------------------------------------
14
15
  package Image::ExifTool::QuickTime;
15
16
 
@@ -78,7 +79,8 @@ my %processByMetaFormat = (
78
79
  # data lengths for each INSV record type
79
80
  my %insvDataLen = (
80
81
  0x300 => 56, # accelerometer
81
- 0x400 => 16, # unknown
82
+ 0x400 => 16, # exposure (ref 6)
83
+ 0x600 => 8, # timestamps (ref 6)
82
84
  0x700 => 53, # GPS
83
85
  );
84
86
 
@@ -121,6 +123,7 @@ my %insvLimit = (
121
123
  ExposureCompensation => { PrintConv => 'Image::ExifTool::Exif::PrintFraction($val)', Groups => { 2 => 'Camera' } },
122
124
  ISO => { Groups => { 2 => 'Camera' } },
123
125
  CameraDateTime=>{ PrintConv => '$self->ConvertDateTime($val)', Groups => { 2 => 'Time' } },
126
+ VideoTimeStamp => { Groups => { 2 => 'Video' } },
124
127
  Accelerometer=> { Notes => '3-axis acceleration in units of g' },
125
128
  AccelerometerData => { },
126
129
  AngularVelocity => { },
@@ -162,10 +165,17 @@ my %insvLimit = (
162
165
  ProcessProc => \&Process_mebx,
163
166
  },
164
167
  },
165
- gpmd => {
166
- Name => 'gpmd',
168
+ gpmd => [{
169
+ Name => 'gpmd_GoPro',
170
+ Condition => '$$valPt !~ /^\0\0\xf2\xe1\xf0\xeeTT/',
167
171
  SubDirectory => { TagTable => 'Image::ExifTool::GoPro::GPMF' },
168
- },
172
+ },{
173
+ Name => 'gpmd_Rove', # Rove Stealth 4K encrypted text
174
+ SubDirectory => {
175
+ TagTable => 'Image::ExifTool::QuickTime::Stream',
176
+ ProcessProc => \&Process_text,
177
+ },
178
+ }],
169
179
  fdsc => {
170
180
  Name => 'fdsc',
171
181
  Condition => '$$valPt =~ /^GPRO/',
@@ -834,15 +844,21 @@ sub HandleTextTags($$$)
834
844
 
835
845
  #------------------------------------------------------------------------------
836
846
  # Process subtitle 'text'
837
- # Inputs: 0) ExifTool ref, 1) tag table ref, 2) data ref
847
+ # Inputs: 0) ExifTool ref, 1) data ref or dirInfo ref, 2) tag table ref
838
848
  sub Process_text($$$)
839
849
  {
840
- my ($et, $tagTbl, $buffPt) = @_;
850
+ my ($et, $dataPt, $tagTbl) = @_;
841
851
  my %tags;
842
852
 
843
853
  return if $$et{NoMoreTextDecoding};
844
854
 
845
- while ($$buffPt =~ /\$(\w+)([^\$]*)/g) {
855
+ if (ref $dataPt eq 'HASH') {
856
+ my $dirName = $$dataPt{DirName};
857
+ $dataPt = $$dataPt{DataPt};
858
+ $et->VerboseDir($dirName, undef, length($$dataPt));
859
+ }
860
+
861
+ while ($$dataPt =~ /\$(\w+)([^\$]*)/g) {
846
862
  my ($tag, $dat) = ($1, $2);
847
863
  if ($tag =~ /^[A-Z]{2}RMC$/ and $dat =~ /^,(\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+)/) {
848
864
  my $time = "$1:$2:$3";
@@ -933,31 +949,31 @@ sub Process_text($$$)
933
949
  # 0110: 31 30 38 30 30 30 58 00 58 00 58 00 58 00 58 00 [108000X.X.X.X.X.]
934
950
  # 0120: 58 00 58 00 58 00 58 00 00 00 00 00 00 00 00 00 [X.X.X.X.........]
935
951
  # 0130: 00 00 00 00 00 00 00 [.......]
936
- if ($$buffPt =~ /^\0\0(..\xaa\xaa|\xf2\xe1\xf0\xee)/s and length $$buffPt >= 282) {
937
- my $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$buffPt, 8, 14)));
952
+ if ($$dataPt =~ /^\0\0(..\xaa\xaa|\xf2\xe1\xf0\xee)/s and length $$dataPt >= 282) {
953
+ my $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$dataPt, 8, 14)));
938
954
  if ($val =~ /^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/) {
939
955
  $tags{GPSDateTime} = "$1:$2:$3 $4:$5:$6";
940
- $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$buffPt, 38, 9)));
956
+ $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$dataPt, 38, 9)));
941
957
  if ($val =~ /^([NS])(\d{2})(\d+$)$/) {
942
958
  $tags{GPSLatitude} = ($2 + $3 / 600000) * ($1 eq 'S' ? -1 : 1);
943
959
  }
944
- $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$buffPt, 47, 10)));
960
+ $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$dataPt, 47, 10)));
945
961
  if ($val =~ /^([EW])(\d{3})(\d+$)$/) {
946
962
  $tags{GPSLongitude} = ($2 + $3 / 600000) * ($1 eq 'W' ? -1 : 1);
947
963
  }
948
- $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$buffPt, 0x39, 5)));
964
+ $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$dataPt, 0x39, 5)));
949
965
  $tags{GPSAltitude} = $val + 0 if $val =~ /^[-+]\d+$/;
950
- $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$buffPt, 0x3e, 3)));
966
+ $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$dataPt, 0x3e, 3)));
951
967
  if ($val =~ /^\d+$/) {
952
968
  $tags{GPSSpeed} = $val + 0;
953
969
  $tags{GPSSpeedRef} = 'K';
954
970
  }
955
- if ($$buffPt =~ /^\0\0..\xaa\xaa/s) { # (BlueSkySea)
956
- $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$buffPt, 0xad, 12)));
971
+ if ($$dataPt =~ /^\0\0..\xaa\xaa/s) { # (BlueSkySea)
972
+ $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$dataPt, 0xad, 12)));
957
973
  # the first X,Y,Z accelerometer readings from the AccelerometerData
958
974
  if ($val =~ /^([-+]\d{3})([-+]\d{3})([-+]\d{3})$/) {
959
975
  $tags{Accelerometer} = "$1 $2 $3";
960
- $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$buffPt, 0xba, 96)));
976
+ $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$dataPt, 0xba, 96)));
961
977
  my $order = GetByteOrder();
962
978
  SetByteOrder('II');
963
979
  $val = ReadValue(\$val, 0, 'float');
@@ -966,7 +982,7 @@ sub Process_text($$$)
966
982
  }
967
983
  } else { # (Ambarella)
968
984
  my @acc;
969
- $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$buffPt, 0x41, 195)));
985
+ $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$dataPt, 0x41, 195)));
970
986
  push @acc, $1, $2, $3 while $val =~ /\G([-+]\d{3})([-+]\d{3})([-+]\d{3})/g;
971
987
  $tags{Accelerometer} = "@acc" if @acc;
972
988
  }
@@ -977,36 +993,36 @@ sub Process_text($$$)
977
993
  # check for DJI telemetry data, eg:
978
994
  # "F/3.5, SS 1000, ISO 100, EV 0, GPS (8.6499, 53.1665, 18), D 24.26m,
979
995
  # H 6.00m, H.S 2.10m/s, V.S 0.00m/s \n"
980
- if ($$buffPt =~ /GPS \(([-+]?\d*\.\d+),\s*([-+]?\d*\.\d+)/) {
996
+ if ($$dataPt =~ /GPS \(([-+]?\d*\.\d+),\s*([-+]?\d*\.\d+)/) {
981
997
  $$et{CreateDateAtEnd} = 1; # set flag indicating the file creation date is at the end
982
998
  $tags{GPSLatitude} = $2;
983
999
  $tags{GPSLongitude} = $1;
984
- $tags{GPSAltitude} = $1 if $$buffPt =~ /,\s*H\s+([-+]?\d+\.?\d*)m/;
985
- if ($$buffPt =~ /,\s*H.S\s+([-+]?\d+\.?\d*)/) {
1000
+ $tags{GPSAltitude} = $1 if $$dataPt =~ /,\s*H\s+([-+]?\d+\.?\d*)m/;
1001
+ if ($$dataPt =~ /,\s*H.S\s+([-+]?\d+\.?\d*)/) {
986
1002
  $tags{GPSSpeed} = $1 * $mpsToKph;
987
1003
  $tags{GPSSpeedRef} = 'K';
988
1004
  }
989
- $tags{Distance} = $1 * $mpsToKph if $$buffPt =~ /,\s*D\s+(\d+\.?\d*)m/;
990
- $tags{VerticalSpeed} = $1 if $$buffPt =~ /,\s*V.S\s+([-+]?\d+\.?\d*)/;
991
- $tags{FNumber} = $1 if $$buffPt =~ /\bF\/(\d+\.?\d*)/;
992
- $tags{ExposureTime} = 1 / $1 if $$buffPt =~ /\bSS\s+(\d+\.?\d*)/;
993
- $tags{ExposureCompensation} = ($1 / ($2 || 1)) if $$buffPt =~ /\bEV\s+([-+]?\d+\.?\d*)(\/\d+)?/;
994
- $tags{ISO} = $1 if $$buffPt =~ /\bISO\s+(\d+\.?\d*)/;
1005
+ $tags{Distance} = $1 * $mpsToKph if $$dataPt =~ /,\s*D\s+(\d+\.?\d*)m/;
1006
+ $tags{VerticalSpeed} = $1 if $$dataPt =~ /,\s*V.S\s+([-+]?\d+\.?\d*)/;
1007
+ $tags{FNumber} = $1 if $$dataPt =~ /\bF\/(\d+\.?\d*)/;
1008
+ $tags{ExposureTime} = 1 / $1 if $$dataPt =~ /\bSS\s+(\d+\.?\d*)/;
1009
+ $tags{ExposureCompensation} = ($1 / ($2 || 1)) if $$dataPt =~ /\bEV\s+([-+]?\d+\.?\d*)(\/\d+)?/;
1010
+ $tags{ISO} = $1 if $$dataPt =~ /\bISO\s+(\d+\.?\d*)/;
995
1011
  HandleTextTags($et, $tagTbl, \%tags);
996
1012
  return;
997
1013
  }
998
1014
 
999
1015
  # check for Mini 0806 dashcam GPS, eg:
1000
1016
  # "A,270519,201555.000,3356.8925,N,08420.2071,W,000.0,331.0M,+01.84,-09.80,-00.61;\n"
1001
- if ($$buffPt =~ /^A,(\d{2})(\d{2})(\d{2}),(\d{2})(\d{2})(\d{2}(\.\d+)?)/) {
1017
+ if ($$dataPt =~ /^A,(\d{2})(\d{2})(\d{2}),(\d{2})(\d{2})(\d{2}(\.\d+)?)/) {
1002
1018
  $tags{GPSDateTime} = "20$3:$2:$1 $4:$5:$6Z";
1003
- if ($$buffPt =~ /^A,.*?,.*?,(\d{2})(\d+\.\d+),([NS])/) {
1019
+ if ($$dataPt =~ /^A,.*?,.*?,(\d{2})(\d+\.\d+),([NS])/) {
1004
1020
  $tags{GPSLatitude} = ($1 + $2/60) * ($3 eq 'S' ? -1 : 1);
1005
1021
  }
1006
- if ($$buffPt =~ /^A,.*?,.*?,.*?,.*?,(\d{3})(\d+\.\d+),([EW])/) {
1022
+ if ($$dataPt =~ /^A,.*?,.*?,.*?,.*?,(\d{3})(\d+\.\d+),([EW])/) {
1007
1023
  $tags{GPSLongitude} = ($1 + $2/60) * ($3 eq 'W' ? -1 : 1);
1008
1024
  }
1009
- my @a = split ',', $$buffPt;
1025
+ my @a = split ',', $$dataPt;
1010
1026
  $tags{GPSAltitude} = $a[8] if $a[8] and $a[8] =~ s/M$//;
1011
1027
  $tags{GPSSpeed} = $a[7] if $a[7] and $a[7] =~ /^\d+\.\d+$/; # (NC)
1012
1028
  $tags{Accelerometer} = "$a[9] $a[10] $a[11]" if $a[11] and $a[11] =~ s/;\s*$//;
@@ -1019,10 +1035,10 @@ sub Process_text($$$)
1019
1035
  # decoded:
1020
1036
  # "X0000.2340Y-000.0720Z0000.9900G0001.0400$GPRMC,082138,A,5330.6683,N,00641.9749,W,012.5,87.86,050213,002.1,A"
1021
1037
  # (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}~$/) {
1038
+ if ($$dataPt =~ /\*[0-9A-F]{2}~$/) {
1023
1039
  # (ref https://reverseengineering.stackexchange.com/questions/11582/how-to-reverse-engineer-dash-cam-metadata)
1024
1040
  my @decode = unpack 'C*', '-I8XQWRVNZOYPUTA0B1C2SJ9K.L,M$D3E4F5G6H7';
1025
- my @chars = unpack 'C*', substr($$buffPt, 0, -4);
1041
+ my @chars = unpack 'C*', substr($$dataPt, 0, -4);
1026
1042
  foreach (@chars) {
1027
1043
  my $n = $_ - 43;
1028
1044
  $_ = $decode[$n] if $n >= 0 and defined $decode[$n];
@@ -1031,14 +1047,14 @@ sub Process_text($$$)
1031
1047
  if ($buff =~ /X(.*?)Y(.*?)Z(.*?)G(.*?)\$/) {
1032
1048
  # yup. the decoding worked out
1033
1049
  $tags{Accelerometer} = "$1 $2 $3 $4";
1034
- $$buffPt = $buff; # (process GPRMC below)
1050
+ $$dataPt = $buff; # (process GPRMC below)
1035
1051
  }
1036
1052
  }
1037
1053
 
1038
1054
  # check for Thinkware format (and other NMEA RMC), eg:
1039
1055
  # "gsensori,4,512,-67,-12,100;GNRMC,161313.00,A,4529.87489,N,07337.01215,W,6.225,35.34,310819,,,A*52..;
1040
1056
  # CAR,0,0,0,0.0,0,0,0,0,0,0,0,0"
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
1057
+ if ($$dataPt =~ /[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
1042
1058
  # do some basic sanity checks on the date
1043
1059
  $13 <= 31 and $14 <= 12 and $15 <= 99)
1044
1060
  {
@@ -1055,8 +1071,8 @@ sub Process_text($$$)
1055
1071
  $tags{GPSTrackRef} = 'T';
1056
1072
  }
1057
1073
  }
1058
- $tags{GSensor} = $1 if $$buffPt =~ /\bgsensori,(.*?)(;|$)/;
1059
- $tags{Car} = $1 if $$buffPt =~ /\bCAR,(.*?)(;|$)/;
1074
+ $tags{GSensor} = $1 if $$dataPt =~ /\bgsensori,(.*?)(;|$)/;
1075
+ $tags{Car} = $1 if $$dataPt =~ /\bCAR,(.*?)(;|$)/;
1060
1076
 
1061
1077
  if (%tags) {
1062
1078
  HandleTextTags($et, $tagTbl, \%tags);
@@ -1112,7 +1128,7 @@ sub ProcessSamples($)
1112
1128
  ($startChunk, $samplesPerChunk, $descIdx) = @{shift @$stsc};
1113
1129
  $nextChunk = $$stsc[0][0] if @$stsc;
1114
1130
  }
1115
- @$size < @$start + $samplesPerChunk and $et->WarnOnce('Sample size error'), return;
1131
+ @$size < @$start + $samplesPerChunk and $et->WarnOnce('Sample size error'), last;
1116
1132
  my $sampleStart = $chunkStart;
1117
1133
  for ($i=0; ; ) {
1118
1134
  push @$start, $sampleStart;
@@ -1215,11 +1231,13 @@ sub ProcessSamples($)
1215
1231
  $val =~ tr/\t/ /;
1216
1232
  $et->HandleTag($tagTbl, RawGSensor => $val) if length $val;
1217
1233
  }
1218
- } elsif ($buff =~ /^PNDM/ and length $buff >= 20) {
1234
+ } elsif ($buff =~ /^(\0.{3})?PNDM/s) {
1219
1235
  # Garmin Dashcam format (actually binary, not text)
1220
- $et->HandleTag($tagTbl, GPSLatitude => Get32s(\$buff, 12) * 180/0x80000000);
1221
- $et->HandleTag($tagTbl, GPSLongitude => Get32s(\$buff, 16) * 180/0x80000000);
1222
- $et->HandleTag($tagTbl, GPSSpeed => Get16u(\$buff, 8));
1236
+ my $n = $1 ? 4 : 0; # skip leading 4-byte size word if it exists
1237
+ next if length($buff) < 20 + $n;
1238
+ $et->HandleTag($tagTbl, GPSLatitude => Get32s(\$buff, 12+$n) * 180/0x80000000);
1239
+ $et->HandleTag($tagTbl, GPSLongitude => Get32s(\$buff, 16+$n) * 180/0x80000000);
1240
+ $et->HandleTag($tagTbl, GPSSpeed => Get16u(\$buff, 8+$n));
1223
1241
  $et->HandleTag($tagTbl, GPSSpeedRef => 'M');
1224
1242
  SetGPSDateTime($et, $tagTbl, $time[$i]);
1225
1243
  next; # all done (don't store/process as text)
@@ -1228,7 +1246,7 @@ sub ProcessSamples($)
1228
1246
  $et->HandleTag($tagTbl, Text => $buff); # just store any other text
1229
1247
  }
1230
1248
  }
1231
- Process_text($et, $tagTbl, \$buff);
1249
+ Process_text($et, \$buff, $tagTbl);
1232
1250
 
1233
1251
  } elsif ($processByMetaFormat{$type}) {
1234
1252
 
@@ -1249,7 +1267,7 @@ sub ProcessSamples($)
1249
1267
  # "X0000.0000Y0000.0000Z0000.0000G0000.0000$GPRMC,000125,V,,,,,000.0,,280908,002.1,N*71~, 794021 \x0a"
1250
1268
  FoundSomething($et, $tagTbl, $time[$i], $dur[$i]);
1251
1269
  $et->HandleTag($tagTbl, Accelerometer => "$1 $2 $3 $4") if $buff =~ /X(.*?)Y(.*?)Z(.*?)G(.*?)\$/;
1252
- Process_text($et, $tagTbl, \$buff);
1270
+ Process_text($et, \$buff, $tagTbl);
1253
1271
  }
1254
1272
  } elsif ($verbose) {
1255
1273
  $et->VPrint(0, "Unknown $type format ($metaFormat)");
@@ -2444,11 +2462,16 @@ sub ProcessInsta360($;$)
2444
2462
  $et->HandleTag($tagTbl, Accelerometer => "@a[0..2]"); # (NC)
2445
2463
  $et->HandleTag($tagTbl, AngularVelocity => "@a[3..5]"); # (NC)
2446
2464
  }
2447
- } elsif ($id == 0x400 and $unknown) {
2465
+ } elsif ($id == 0x400) {
2448
2466
  for ($p=0; $p<$len; $p+=$dlen) {
2449
2467
  $$et{DOC_NUM} = ++$$et{DOC_COUNT};
2450
2468
  $et->HandleTag($tagTbl, TimeCode => sprintf('%.3f', Get64u(\$buff, $p) / 1000));
2451
- $et->HandleTag($tagTbl, Unknown01 => GetDouble(\$buff, $p + 8));
2469
+ $et->HandleTag($tagTbl, ExposureTime => GetDouble(\$buff, $p + 8)); #6
2470
+ }
2471
+ } elsif ($id == 0x600) { #6
2472
+ for ($p=0; $p<$len; $p+=$dlen) {
2473
+ $$et{DOC_NUM} = ++$$et{DOC_COUNT};
2474
+ $et->HandleTag($tagTbl, VideoTimeStamp => sprintf('%.3f', Get64u(\$buff, $p) / 1000));
2452
2475
  }
2453
2476
  } elsif ($id == 0x700) {
2454
2477
  for ($p=0; $p<$len; $p+=$dlen) {
@@ -387,8 +387,11 @@ numerical, and generated automatically otherwise.
387
387
  'Flattened' - [reserved] used internally to mark Struct tags
388
388
  which have been processed to generate flattened equivalents.
389
389
 
390
- 'GotGroups' - [reserved] flag used internally to indicate that
391
- the Groups hash has been initialized for this tag.
390
+ 'NotFlat' - [XMP tags only] Flag indicates that this tag ID
391
+ does not represent a flattened tag. Used to avoid a conflict
392
+ if the tag ID would be the same as a generated ID for a
393
+ flattened tag. The result is that the flattened tag will not
394
+ be accessible.
392
395
 
393
396
  'Hidden' - set to hide tag from the TagName documentation.
394
397
  Also suppresses verbose output of a BinaryData tag.