exiftool_vendored 12.06.0 → 12.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

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.