exiftool_vendored 12.86.0 → 12.92.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +81 -1
  3. data/bin/MANIFEST +1 -0
  4. data/bin/META.json +2 -2
  5. data/bin/META.yml +17 -17
  6. data/bin/README +3 -2
  7. data/bin/build_geolocation +7 -4
  8. data/bin/config_files/onone.config +28 -0
  9. data/bin/exiftool +23 -15
  10. data/bin/lib/Image/ExifTool/AIFF.pm +8 -4
  11. data/bin/lib/Image/ExifTool/ASF.pm +4 -1
  12. data/bin/lib/Image/ExifTool/BuildTagLookup.pm +12 -7
  13. data/bin/lib/Image/ExifTool/Canon.pm +75 -10
  14. data/bin/lib/Image/ExifTool/CanonRaw.pm +1 -1
  15. data/bin/lib/Image/ExifTool/CanonVRD.pm +1 -1
  16. data/bin/lib/Image/ExifTool/FujiFilm.pm +46 -4
  17. data/bin/lib/Image/ExifTool/Geolocation.dat +0 -0
  18. data/bin/lib/Image/ExifTool/Geolocation.pm +6 -0
  19. data/bin/lib/Image/ExifTool/InDesign.pm +8 -4
  20. data/bin/lib/Image/ExifTool/Jpeg2000.pm +0 -1
  21. data/bin/lib/Image/ExifTool/Lang/de.pm +2 -2
  22. data/bin/lib/Image/ExifTool/Matroska.pm +66 -10
  23. data/bin/lib/Image/ExifTool/MinoltaRaw.pm +2 -2
  24. data/bin/lib/Image/ExifTool/Nikon.pm +36 -2
  25. data/bin/lib/Image/ExifTool/PNG.pm +10 -2
  26. data/bin/lib/Image/ExifTool/Panasonic.pm +1 -0
  27. data/bin/lib/Image/ExifTool/PanasonicRaw.pm +1 -0
  28. data/bin/lib/Image/ExifTool/Pentax.pm +80 -14
  29. data/bin/lib/Image/ExifTool/QuickTime.pm +51 -9
  30. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +111 -8
  31. data/bin/lib/Image/ExifTool/RIFF.pm +20 -10
  32. data/bin/lib/Image/ExifTool/Samsung.pm +28 -19
  33. data/bin/lib/Image/ExifTool/Sony.pm +21 -11
  34. data/bin/lib/Image/ExifTool/TagLookup.pm +6804 -6784
  35. data/bin/lib/Image/ExifTool/TagNames.pod +92 -21
  36. data/bin/lib/Image/ExifTool/WriteQuickTime.pl +84 -15
  37. data/bin/lib/Image/ExifTool/Writer.pl +7 -4
  38. data/bin/lib/Image/ExifTool/XMP.pm +8 -8
  39. data/bin/lib/Image/ExifTool/XMP2.pl +51 -30
  40. data/bin/lib/Image/ExifTool/ZIP.pm +8 -4
  41. data/bin/lib/Image/ExifTool.pm +22 -16
  42. data/bin/lib/Image/ExifTool.pod +15 -6
  43. data/bin/perl-Image-ExifTool.spec +1 -1
  44. data/lib/exiftool_vendored/version.rb +1 -1
  45. metadata +3 -2
@@ -48,7 +48,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
48
48
  use Image::ExifTool::Exif;
49
49
  use Image::ExifTool::GPS;
50
50
 
51
- $VERSION = '2.97';
51
+ $VERSION = '2.99';
52
52
 
53
53
  sub ProcessMOV($$;$);
54
54
  sub ProcessKeys($$$);
@@ -238,7 +238,11 @@ my %useExt = ( GLV => 'MP4' );
238
238
 
239
239
  # information for int32u date/time tags (time zero is Jan 1, 1904)
240
240
  my %timeInfo = (
241
- Notes => 'converted from UTC to local time if the QuickTimeUTC option is set',
241
+ Notes => q{
242
+ converted from UTC to local time if the QuickTimeUTC option is set. This
243
+ tag is part of a binary data structure so it may not be deleted -- instead
244
+ the value is set to zero if the tag is deleted individually
245
+ },
242
246
  Shift => 'Time',
243
247
  Writable => 1,
244
248
  Permanent => 1,
@@ -8988,12 +8992,20 @@ sub HandleItemInfo($)
8988
8992
  if ($$item{Extents} and @{$$item{Extents}}) {
8989
8993
  $len += $$_[2] foreach @{$$item{Extents}};
8990
8994
  }
8991
- $et->VPrint(0, "$$et{INDENT}Item $id) '${type}' ($len bytes)\n");
8995
+ my $enc = $$item{ContentEncoding} ? ", $$item{ContentEncoding} encoded" : '';
8996
+ $et->VPrint(0, "$$et{INDENT}Item $id) '${type}' ($len bytes$enc)\n");
8992
8997
  }
8993
8998
  # get ExifTool name for this item
8994
8999
  my $name = { Exif => 'EXIF', 'application/rdf+xml' => 'XMP', jpeg => 'PreviewImage' }->{$type} || '';
8995
9000
  my ($warn, $extent);
8996
- $warn = "Can't currently decode encoded $type metadata" if $$item{ContentEncoding};
9001
+ if ($$item{ContentEncoding}) {
9002
+ if ($$item{ContentEncoding} ne 'deflate') {
9003
+ # (other possible values are 'gzip' and 'compress', but I don't have samples of these)
9004
+ $warn = "Can't currently decode $$item{ContentEncoding} encoded $type metadata";
9005
+ } elsif (not eval { require Compress::Zlib }) {
9006
+ $warn = "Install Compress::Zlib to decode deflated $type metadata";
9007
+ }
9008
+ }
8997
9009
  $warn = "Can't currently decode protected $type metadata" if $$item{ProtectionIndex};
8998
9010
  $warn = "Can't currently extract $type with construction method $$item{ConstructionMethod}" if $$item{ConstructionMethod};
8999
9011
  $et->WarnOnce($warn) if $warn and $name;
@@ -9053,6 +9065,22 @@ sub HandleItemInfo($)
9053
9065
  next unless defined $buff;
9054
9066
  $buff = $val . $buff if length $val;
9055
9067
  next unless length $buff; # ignore empty directories
9068
+ if ($$item{ContentEncoding}) {
9069
+ my ($v2, $stat);
9070
+ my $inflate = Compress::Zlib::inflateInit();
9071
+ $inflate and ($v2, $stat) = $inflate->inflate($buff);
9072
+ if ($inflate and $stat == Compress::Zlib::Z_STREAM_END()) {
9073
+ $buff = $v2;
9074
+ my $len = length $buff;
9075
+ $et->VPrint(0, "$$et{INDENT}Inflated Item $id) '${type}' ($len bytes)\n");
9076
+ $et->VerboseDump(\$buff);
9077
+ } else {
9078
+ $warn = "Error inflating $name metadata";
9079
+ $et->WarnOnce($warn);
9080
+ $et->VPrint(0, "$$et{INDENT} [not extracted] ($warn)\n") if $verbose > 2;
9081
+ next;
9082
+ }
9083
+ }
9056
9084
  my ($start, $subTable, $proc);
9057
9085
  my $pos = $$item{Extents}[0][1] + $base;
9058
9086
  if ($name eq 'EXIF' and length $buff >= 4) {
@@ -9488,7 +9516,8 @@ sub ProcessMOV($$;$)
9488
9516
  my $dataPt = $$dirInfo{DataPt};
9489
9517
  my $verbose = $et->Options('Verbose');
9490
9518
  my $validate = $$et{OPTIONS}{Validate};
9491
- my $dataPos = $$dirInfo{Base} || 0;
9519
+ my $dirBase = $$dirInfo{Base} || 0;
9520
+ my $dataPos = $dirBase;
9492
9521
  my $dirID = $$dirInfo{DirID} || '';
9493
9522
  my $charsetQuickTime = $et->Options('CharsetQuickTime');
9494
9523
  my ($buff, $tag, $size, $track, $isUserData, %triplet, $doDefaultLang, $index);
@@ -9573,6 +9602,7 @@ sub ProcessMOV($$;$)
9573
9602
  $atomCount = $$tagTablePtr{VARS}{ATOM_COUNT};
9574
9603
  }
9575
9604
  my $lastTag = '';
9605
+ my $lastPos = 0;
9576
9606
  for (;;) {
9577
9607
  my ($eeTag, $ignore);
9578
9608
  last if defined $atomCount and --$atomCount < 0;
@@ -9611,6 +9641,8 @@ sub ProcessMOV($$;$)
9611
9641
  } elsif (not $et->Options('LargeFileSupport')) {
9612
9642
  $warnStr = 'End of processing at large atom (LargeFileSupport not enabled)';
9613
9643
  last;
9644
+ } elsif ($et->Options('LargeFileSupport') eq '2') {
9645
+ $et->WarnOnce('Processing large atom (LargeFileSupport is 2)');
9614
9646
  }
9615
9647
  }
9616
9648
  $size = $hi * 4294967296 + $lo - 16;
@@ -9705,7 +9737,7 @@ sub ProcessMOV($$;$)
9705
9737
  if ($size > 0x2000000) { # start to get worried above 32 MiB
9706
9738
  # check for RIFF trailer (written by Auto-Vox dashcam)
9707
9739
  if ($buff =~ /^(gpsa|gps0|gsen|gsea)...\0/s) { # (yet seen only gpsa as first record)
9708
- $et->VPrint(0, "Found RIFF trailer");
9740
+ $et->VPrint(0, sprintf("Found RIFF trailer at offset 0x%x",$lastPos));
9709
9741
  if ($et->Options('ExtractEmbedded')) {
9710
9742
  $raf->Seek(-8, 1) or last; # seek back to start of trailer
9711
9743
  my $tbl = GetTagTable('Image::ExifTool::QuickTime::Stream');
@@ -9714,6 +9746,11 @@ sub ProcessMOV($$;$)
9714
9746
  EEWarn($et);
9715
9747
  }
9716
9748
  last;
9749
+ } elsif ($buff eq 'CCCCCCCC') {
9750
+ $et->VPrint(0, sprintf("Found Kenwood trailer at offset 0x%x",$lastPos));
9751
+ my $tbl = GetTagTable('Image::ExifTool::QuickTime::Stream');
9752
+ ProcessKenwoodTrailer($et, { RAF => $raf }, $tbl);
9753
+ last;
9717
9754
  }
9718
9755
  $ignore = 1;
9719
9756
  if ($tagInfo and not $$tagInfo{Unknown} and not $eeTag) {
@@ -10085,14 +10122,15 @@ ItemID: foreach $id (reverse sort { $a <=> $b } keys %$items) {
10085
10122
  ) if $verbose;
10086
10123
  if ($size and (not $raf->Seek($size-1, 1) or $raf->Read($buff, 1) != 1)) {
10087
10124
  my $t = PrintableTagID($tag,2);
10088
- $warnStr = "Truncated '${t}' data";
10125
+ $warnStr = sprintf("Truncated '${t}' data at offset 0x%x", $lastPos);
10089
10126
  last;
10090
10127
  }
10091
10128
  }
10092
10129
  $dataPos += $size + 8; # point to start of next atom data
10093
10130
  last if $dirEnd and $dataPos >= $dirEnd; # (note: ignores last value if 0 bytes)
10131
+ $lastPos = $raf->Tell() + $dirBase;
10094
10132
  $raf->Read($buff, 8) == 8 or last;
10095
- $lastTag = $tag if $$tagTablePtr{$tag};
10133
+ $lastTag = $tag if $$tagTablePtr{$tag} and $tag ne 'free'; # (Insta360 sometimes puts free block before trailer)
10096
10134
  ($size, $tag) = unpack('Na4', $buff);
10097
10135
  ++$index if defined $index;
10098
10136
  }
@@ -10102,7 +10140,11 @@ ItemID: foreach $id (reverse sort { $a <=> $b } keys %$items) {
10102
10140
  if (($lastTag eq 'mdat' or $lastTag eq 'moov') and (not $$tagTablePtr{$tag} or
10103
10141
  ref $$tagTablePtr{$tag} eq 'HASH' and $$tagTablePtr{$tag}{Unknown}))
10104
10142
  {
10105
- $et->Warn('Unknown trailer with '.lcfirst($warnStr));
10143
+ if ($size == 0x1000000 - 8 and $tag =~ /^(\x94\xc0\x7e\0|\0\x02\0\0)/) {
10144
+ $et->Warn(sprintf('Insta360 trailer at offset 0x%x', $lastPos), 1);
10145
+ } else {
10146
+ $et->Warn('Unknown trailer with '.lcfirst($warnStr));
10147
+ }
10106
10148
  } else {
10107
10149
  $et->Warn($warnStr);
10108
10150
  }
@@ -109,7 +109,7 @@ my %insvLimit = (
109
109
  The tags below are extracted from timed metadata in QuickTime and other
110
110
  formats of video files when the ExtractEmbedded option is used. Although
111
111
  most of these tags are combined into the single table below, ExifTool
112
- currently reads 74 different formats of timed GPS metadata from video files.
112
+ currently reads 76 different formats of timed GPS metadata from video files.
113
113
  },
114
114
  VARS => { NO_ID => 1 },
115
115
  GPSLatitude => { PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', RawConv => '$$self{FoundGPSLatitude} = 1; $val' },
@@ -143,6 +143,7 @@ my %insvLimit = (
143
143
  ExposureCompensation => { PrintConv => 'Image::ExifTool::Exif::PrintFraction($val)', Groups => { 2 => 'Camera' } },
144
144
  ISO => { Groups => { 2 => 'Camera' } },
145
145
  CameraDateTime=>{ PrintConv => '$self->ConvertDateTime($val)', Groups => { 2 => 'Time' } },
146
+ DateTimeStamp =>{ PrintConv => '$self->ConvertDateTime($val)', Groups => { 2 => 'Time' } },
146
147
  VideoTimeStamp => { Groups => { 2 => 'Video' } },
147
148
  Accelerometer=> { Notes => '3-axis acceleration in units of g' },
148
149
  AccelerometerData => { },
@@ -992,8 +993,29 @@ sub Process_text($$$;$)
992
993
  $tags{Text} = defined $tags{Text} ? $tags{Text} . "\$$tag$dat" : "\$$tag$dat";
993
994
  }
994
995
  }
995
- %tags and HandleTextTags($et, $tagTbl, \%tags), return;
996
-
996
+ if (%tags) {
997
+ unless ($tags{Accelerometer}) { # (probably unnecessary test)
998
+ # check for NextBase 622GW accelerometer data
999
+ # Example data (leading 2-byte length word has been stripped by ProcessSamples):
1000
+ # 0000: 00 00 00 00 32 30 32 32 30 39 30 35 31 36 34 30 [....202209051640]
1001
+ # 0010: 33 33 00 00 29 00 ba ff 48 ff 18 00 f2 07 5a ff [33..)...H.....Z.]
1002
+ # 0020: 64 ff e8 ff 58 ff e8 ff c1 07 43 ff 41 ff d2 ff [d...X.....C.A...]
1003
+ # 0030: 58 ff ea ff dc 07 50 ff 30 ff e0 ff 72 ff d8 ff [X.....P.0...r...]
1004
+ # 0040: f5 07 51 ff 16 ff dc ff 6a ff ca ff 33 08 45 ff [..Q.....j...3.E.]
1005
+ if ($$dataPt =~ /^\0{4}(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})\0\0.{2}/s) {
1006
+ $tags{DateTimeStamp} = "$1:$2:$2 $4:$5:$6";
1007
+ my $num = unpack('x20v', $$dataPt); # number of accelerometer readings
1008
+ if ($num and $num * 12 + 22 < length $$dataPt) {
1009
+ $num *= 6;
1010
+ my @acc = unpack("x22v$num", $$dataPt);
1011
+ map { $_ = $_ - 0x10000 if $_ >= 0x8000 } @acc;
1012
+ $tags{AccelerometerData} = "@acc";
1013
+ }
1014
+ }
1015
+ }
1016
+ HandleTextTags($et, $tagTbl, \%tags);
1017
+ return;
1018
+ }
997
1019
  # check for enciphered binary GPS data
998
1020
  # BlueSkySea:
999
1021
  # 0000: 00 00 aa aa aa aa 54 54 98 9a 9b 93 9a 92 98 9a [......TT........]
@@ -1398,9 +1420,10 @@ Sample: for ($i=0; ; ) {
1398
1420
  } elsif ($type eq 'gps ') { # (ie. GPSDataList tag)
1399
1421
 
1400
1422
  if ($buff =~ /^....freeGPS /s) {
1401
- # process by brute scan instead if ExtractEmbedded >= 3
1402
- # (some videos don't reference all freeGPS info from 'gps ' table, eg. INNOV)
1403
- last if $eeOpt >= 3;
1423
+ # parse freeGPS data unless done already in brute-force scan
1424
+ # (some videos don't reference all freeGPS info from 'gps ' table, eg. INNOV,
1425
+ # and some videos don't put 'gps ' data in mdat, eg XGODY 12" 4K Dashcam)
1426
+ last if $$et{FoundGPSByScan};
1404
1427
  # decode "freeGPS " data (Novatek and others)
1405
1428
  ProcessFreeGPS($et, {
1406
1429
  DataPt => \$buff,
@@ -2027,9 +2050,41 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
2027
2050
  }
2028
2051
  }
2029
2052
 
2030
- } else {
2053
+ } elsif ($$dataPt =~ m<^.{23}(\d{4})/(\d{2})/(\d{2}) (\d{2}):(\d{2}):(\d{2}) [N|S]>s) {
2031
2054
 
2032
2055
  $debug and $et->FoundTag(GPSType => 16);
2056
+ # XGODY 12" 4K Dashcam
2057
+ # 0000: 00 00 00 a8 66 72 65 65 47 50 53 20 98 00 00 00 [....freeGPS ....]
2058
+ # 0010: 6e 6f 72 6d 61 6c 3a 32 30 32 34 2f 30 35 2f 32 [normal:2024/05/2]
2059
+ # 0020: 32 20 30 32 3a 35 34 3a 32 39 20 4e 3a 34 32 2e [2 02:54:29 N:42.]
2060
+ # 0030: 33 38 32 34 37 30 20 57 3a 38 33 2e 33 38 39 35 [382470 W:83.3895]
2061
+ # 0040: 37 30 20 35 33 2e 36 20 6b 6d 2f 68 20 78 3a 2d [70 53.6 km/h x:-]
2062
+ # 0050: 30 2e 30 32 20 79 3a 30 2e 39 39 20 7a 3a 30 2e [0.02 y:0.99 z:0.]
2063
+ # 0060: 31 30 20 41 3a 32 36 39 2e 32 20 48 3a 32 34 35 [10 A:269.2 H:245]
2064
+ # 0070: 2e 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [.5..............]
2065
+ ($yr,$mon,$day,$hr,$min,$sec) = ($1,$2,$3,$4,$5,$6);
2066
+ $$dataPt =~ s/\0+$//; # remove trailing nulls
2067
+ my @a = split ' ', substr($$dataPt,43);
2068
+ $ddd = 1;
2069
+ foreach (@a) {
2070
+ unless (/^([A-Z]):([-+]?\d+(\.\d+)?)$/i) {
2071
+ # (the "km/h" after spd is display units? because the value is stored in knots)
2072
+ defined $lon and not defined $spd and /^\d+\.\d+$/ and $spd = $_ * $knotsToKph;
2073
+ next;
2074
+ }
2075
+ ($1 eq 'N' or $1 eq 'S') and $lat = $2, $latRef = $1, next;
2076
+ ($1 eq 'E' or $1 eq 'W') and $lon = $2, $lonRef = $1, next;
2077
+ ($1 eq 'x' or $1 eq 'y' or $1 eq 'z') and push(@acc,$2), next;
2078
+ $1 eq 'A' and $trk = $2, next; # (verified, but why 'A'?)
2079
+ # seen 'H' - one might expect altitude ('H'eight), but it doesn't fit
2080
+ # the sample data, so save all other information as an "Unknown_X" tag
2081
+ $$tagTbl{$1} or AddTagToTable($tagTbl, $1, { Name => "Unknown_$1", Unknown => 1 });
2082
+ push(@xtra, $1 => $2), next;
2083
+ }
2084
+
2085
+ } else {
2086
+
2087
+ $debug and $et->FoundTag(GPSType => 17);
2033
2088
  # (look for binary GPS as stored by Nextbase 512G, ref PH)
2034
2089
  # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 78 01 00 00 [....freeGPS x...]
2035
2090
  # 0010: 78 2e 78 78 00 00 00 00 00 00 00 00 00 00 00 00 [x.xx............]
@@ -2093,7 +2148,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
2093
2148
  my $time = sprintf('%.2d:%.2d:%sZ',$hr,$min,$sec);
2094
2149
  $et->HandleTag($tagTbl, GPSTimeStamp => $time);
2095
2150
  }
2096
- if (defined $lat) {
2151
+ if (defined $lat and defined $lon) {
2097
2152
  # lat/long are in DDDMM.MMMM format unless $ddd is set
2098
2153
  ConvertLatLon($lat, $lon) unless $ddd;
2099
2154
  $et->HandleTag($tagTbl, GPSLatitude => $lat * ($latRef eq 'S' ? -1 : 1));
@@ -2658,6 +2713,53 @@ sub ProcessRIFFTrailer($$$)
2658
2713
  return 1;
2659
2714
  }
2660
2715
 
2716
+ #------------------------------------------------------------------------------
2717
+ # Process Kenwood Dashcam trailer (forum16229)
2718
+ # Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
2719
+ # Returns: 1 on success
2720
+ # Sample data (chained 512-byte records starting like this):
2721
+ # 0000: 43 43 43 43 43 43 43 43 43 43 43 43 43 43 47 50 [CCCCCCCCCCCCCCGP]
2722
+ # 0010: 53 44 41 54 41 2d 2d 32 30 32 34 30 37 31 31 31 [SDATA--202407111]
2723
+ # 0020: 32 30 34 31 32 4e 35 30 2e 36 31 32 33 38 36 30 [20412N50.6123860]
2724
+ # 0030: 36 37 37 45 38 2e 37 30 32 37 31 38 30 39 38 39 [677E8.7027180989]
2725
+ # 0040: 35 33 33 2e 30 30 30 30 30 30 30 30 30 30 30 30 [533.000000000000]
2726
+ # 0050: 2e 30 30 30 30 30 30 30 30 30 30 30 30 30 2e 30 [.0000000000000.0]
2727
+ # 0060: 31 39 39 39 39 39 39 39 35 35 33 2d 30 2e 30 39 [19999999553-0.09]
2728
+ # 0070: 30 30 30 30 30 30 33 35 37 2d 30 2e 31 34 30 30 [000000357-0.1400]
2729
+ # 0080: 30 30 30 30 30 35 39 47 50 53 44 41 54 41 2d 2d [0000059GPSDATA--]
2730
+ sub ProcessKenwoodTrailer($$$)
2731
+ {
2732
+ my ($et, $dirInfo, $tagTbl) = @_;
2733
+ my $raf = $$dirInfo{RAF};
2734
+ my $buff;
2735
+ # current file position is 8 bytes into the 14 C's, so test the next 6:
2736
+ $raf->Read($buff, 14) and $buff eq 'CCCCCCCCCCCCCC' or return 0;
2737
+ $et->VerboseDir('Kenwood trailer', undef, undef);
2738
+ unless ($$et{OPTIONS}{ExtractEmbedded}) {
2739
+ $et->WarnOnce('Use the ExtractEmbedded option to extract timed GPSData from Kenwood trailer',3);
2740
+ return 1;
2741
+ }
2742
+ while ($raf->Read($buff, 121) and $buff =~ /^GPSDATA--(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/) {
2743
+ FoundSomething($et, $tagTbl);
2744
+ $et->HandleTag($tagTbl, GPSDateTime => "$1:$2:$3 $4:$5:$6");
2745
+ my $i = 9 + 14;
2746
+ my ($val, @acc, $tag);
2747
+ foreach $tag (qw(GPSLatitude GPSLongitude GPSSpeed unk acc acc acc)) {
2748
+ $val = substr($buff, $i, 14); $i += 14;
2749
+ next if $tag eq 'unk';
2750
+ my $hemi;
2751
+ $hemi = $1 if $val =~ s/^([NSEW])//;
2752
+ $val =~ /^[-+]?\d+\.\d+$/ or next;
2753
+ $tag eq 'acc' and push(@acc,$val), next;
2754
+ $val = -$val if $hemi and ($hemi eq 'S' or $hemi eq 'W');
2755
+ $et->HandleTag($tagTbl, $tag => $val);
2756
+ }
2757
+ $et->HandleTag($tagTbl, Accelerometer => "@acc") if @acc == 3;
2758
+ }
2759
+ delete $$et{DOC_NUM};
2760
+ return 1;
2761
+ }
2762
+
2661
2763
  #------------------------------------------------------------------------------
2662
2764
  # Process 'gps ' atom containing NMEA from Pittasoft Blackvue dashcam (ref PH)
2663
2765
  # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
@@ -3331,6 +3433,7 @@ sub ScanMediaData($)
3331
3433
  }
3332
3434
  my $dirInfo = { DataPt => \$buff, DataPos => $pos + $dataPos, DirLen => $len };
3333
3435
  ProcessFreeGPS($et, $dirInfo, $tagTbl);
3436
+ $$et{FoundGPSByScan} = 1;
3334
3437
  }
3335
3438
  $pos += $len;
3336
3439
  $buf2 = substr($buff, $len);
@@ -30,7 +30,7 @@ use strict;
30
30
  use vars qw($VERSION $AUTOLOAD);
31
31
  use Image::ExifTool qw(:DataAccess :Utils);
32
32
 
33
- $VERSION = '1.67';
33
+ $VERSION = '1.68';
34
34
 
35
35
  sub ConvertTimecode($);
36
36
  sub ProcessSGLT($$$);
@@ -2041,11 +2041,16 @@ sub ProcessRIFF($$)
2041
2041
  last unless $moviEnd;
2042
2042
  # we arrived here because there was a problem parsing the movie data
2043
2043
  # so seek to the end to continue processing
2044
- if ($moviEnd > 0x7fffffff and not $et->Options('LargeFileSupport')) {
2045
- $et->Warn('Possibly corrupt LIST_movi data');
2046
- $et->Warn('Stopped parsing at large LIST_movi chunk (LargeFileSupport not set)');
2047
- undef $err;
2048
- last;
2044
+ if ($moviEnd > 0x7fffffff) {
2045
+ unless ($et->Options('LargeFileSupport')) {
2046
+ $et->Warn('Possibly corrupt LIST_movi data');
2047
+ $et->Warn('Stopped parsing at large LIST_movi chunk (LargeFileSupport not set)');
2048
+ undef $err;
2049
+ last;
2050
+ }
2051
+ if ($et->Options('LargeFileSupport') eq '2') {
2052
+ $et->WarnOnce('Processing large chunk (LargeFileSupport is 2)');
2053
+ }
2049
2054
  }
2050
2055
  if ($validate) {
2051
2056
  # (must actually try to read something after seeking to detect error)
@@ -2159,10 +2164,15 @@ sub ProcessRIFF($$)
2159
2164
  $moviEnd = $raf->Tell() + $len2;
2160
2165
  next; # parse into movi chunk
2161
2166
  } elsif (not $rewind) {
2162
- if ($len > 0x7fffffff and not $et->Options('LargeFileSupport')) {
2163
- $tag =~ s/([\0-\x1f\x7f-\xff])/sprintf('\\x%.2x',ord $1)/eg;
2164
- $et->Warn("Stopped parsing at large $tag chunk (LargeFileSupport not set)");
2165
- last;
2167
+ if ($len > 0x7fffffff) {
2168
+ unless ($et->Options('LargeFileSupport')) {
2169
+ $tag =~ s/([\0-\x1f\x7f-\xff])/sprintf('\\x%.2x',ord $1)/eg;
2170
+ $et->Warn("Stopped parsing at large $tag chunk (LargeFileSupport not set)");
2171
+ last;
2172
+ }
2173
+ if ($et->Options('LargeFileSupport') eq '2') {
2174
+ $et->WarnOnce('Processing large chunk (LargeFileSupport is 2)');
2175
+ }
2166
2176
  }
2167
2177
  if ($validate and $len2) {
2168
2178
  # (must actually try to read something after seeking to detect error)
@@ -22,13 +22,13 @@ use vars qw($VERSION %samsungLensTypes);
22
22
  use Image::ExifTool qw(:DataAccess :Utils);
23
23
  use Image::ExifTool::Exif;
24
24
 
25
- $VERSION = '1.56';
25
+ $VERSION = '1.57';
26
26
 
27
27
  sub WriteSTMN($$$);
28
28
  sub ProcessINFO($$$);
29
29
  sub ProcessSamsungMeta($$$);
30
30
  sub ProcessSamsungIFD($$$);
31
- sub ProcessSamsung($$$);
31
+ sub ProcessSamsung($$;$);
32
32
 
33
33
  # Samsung LensType lookup
34
34
  %samsungLensTypes = (
@@ -943,25 +943,25 @@ my %formatMinMax = (
943
943
  );
944
944
 
945
945
  # information extracted from Samsung trailer (ie. Samsung SM-T805 "Sound & Shot" JPEG) (ref PH)
946
+ # NOTE: These tags may use $$self{SamsungTagName} in a Condition statement
947
+ # if necessary to differentiate tags with the same ID but different names
946
948
  %Image::ExifTool::Samsung::Trailer = (
947
949
  GROUPS => { 0 => 'MakerNotes', 2 => 'Other' },
948
950
  VARS => { NO_ID => 1, HEX_ID => 0 },
949
951
  PROCESS_PROC => \&ProcessSamsung,
952
+ TAG_PREFIX => 'SamsungTrailer',
950
953
  PRIORITY => 0, # (first one takes priority so DepthMapWidth/Height match first DepthMapData)
951
954
  NOTES => q{
952
- Tags extracted from the trailer of JPEG images written when using certain
953
- features (such as "Sound & Shot" or "Shot & More") from Samsung models such
954
- as the Galaxy S4 and Tab S, and from the 'sefd' atom in HEIC images from the
955
- Samsung S10+.
956
- },
957
- '0x0001-name' => {
958
- Name => 'EmbeddedImageName', # ("DualShot_1","DualShot_2")
959
- RawConv => '$$self{EmbeddedImageName} = $val',
955
+ Tags extracted from the SEFT trailer of JPEG and PNG images written when
956
+ using certain features (such as "Sound & Shot" or "Shot & More") from
957
+ Samsung models such as the Galaxy S4 and Tab S, and from the 'sefd' atom in
958
+ HEIC images from models such as the S10+.
960
959
  },
960
+ '0x0001-name' => 'EmbeddedImageName', # ("DualShot_1","DualShot_2")
961
961
  '0x0001' => [
962
962
  {
963
963
  Name => 'EmbeddedImage',
964
- Condition => '$$self{EmbeddedImageName} eq "DualShot_1"',
964
+ Condition => '$$self{SamsungTagName} ne "DualShot_2"',
965
965
  Groups => { 2 => 'Preview' },
966
966
  Binary => 1,
967
967
  },
@@ -1277,8 +1277,10 @@ my %formatMinMax = (
1277
1277
  # 0x0bd0-name - seen 'Dual_Relighting_Bokeh_Info' #forum16086
1278
1278
  # 0x0be0-name - seen 'Livefocus_JDM_Info' #forum16086
1279
1279
  # 0x0bf0-name - seen 'Remaster_Info' #forum16086
1280
+ '0x0bf0' => 'RemasterInfo', #forum16086/16242
1280
1281
  # 0x0c21-name - seen 'Portrait_Effect_Info' #forum16086
1281
1282
  # 0x0c51-name - seen 'Samsung_Capture_Info' #forum16086
1283
+ '0x0c51' => 'SamsungCaptureInfo', #forum16086/16242
1282
1284
  # 0x0c61-name - seen 'Camera_Capture_Mode_Info' #forum16086
1283
1285
  # 0x0c71-name - seen 'Pro_White_Balance_Info' #forum16086
1284
1286
  # 0x0c81-name - seen 'Watermark_Info' #forum16086
@@ -1289,7 +1291,11 @@ my %formatMinMax = (
1289
1291
  # 0x0d11-name - seen 'Video_Snapshot_Info' #forum16086
1290
1292
  # 0x0d21-name - seen 'Camera_Scene_Info' #forum16086
1291
1293
  # 0x0d31-name - seen 'Food_Blur_Effect_Info' #forum16086
1292
- # 0x0d91-name - seen 'PEg_Info' #forum16086
1294
+ '0x0d91' => { #forum16086/16242
1295
+ Name => 'PEg_Info',
1296
+ Description => 'PEg Info',
1297
+ SubDirectory => { TagTable => 'Image::ExifTool::JSON::Main' },
1298
+ },
1293
1299
  # 0x0da1-name - seen 'Captured_App_Info' #forum16086
1294
1300
  # 0xa050-name - seen 'Jpeg360_2D_Info' (Samsung Gear 360)
1295
1301
  # 0xa050 - seen 'Jpeg3602D' (Samsung Gear 360)
@@ -1563,7 +1569,7 @@ sub ProcessSamsungIFD($$$)
1563
1569
  # Returns: 1 on success, 0 not valid Samsung trailer, or -1 error writing
1564
1570
  # - updates DataPos to point to start of Samsung trailer
1565
1571
  # - updates DirLen to existing trailer length
1566
- sub ProcessSamsung($$$)
1572
+ sub ProcessSamsung($$;$)
1567
1573
  {
1568
1574
  my ($et, $dirInfo) = @_;
1569
1575
  my $raf = $$dirInfo{RAF};
@@ -1653,8 +1659,13 @@ SamBlock:
1653
1659
  $audioSize = $size - 8 - $len;
1654
1660
  next;
1655
1661
  }
1656
- # add unknown tags if necessary
1662
+ last unless $raf->Seek($dirPos-$noff, 0) and $raf->Read($buf2, $size) == $size;
1663
+ # (could validate the first 4 bytes of the block because they
1664
+ # are the same as the first 4 bytes of the directory entry)
1665
+ $len = Get32u(\$buf2, 4);
1666
+ last if $len + 8 > $size;
1657
1667
  my $tag = sprintf("0x%.4x", $type);
1668
+ # add unknown tags if necessary
1658
1669
  unless ($$tagTablePtr{$tag}) {
1659
1670
  next unless $unknown or $verbose;
1660
1671
  my %tagInfo = (
@@ -1673,11 +1684,8 @@ SamBlock:
1673
1684
  );
1674
1685
  AddTagToTable($tagTablePtr, "$tag-name", \%tagInfo2);
1675
1686
  }
1676
- last unless $raf->Seek($dirPos-$noff, 0) and $raf->Read($buf2, $size) == $size;
1677
- # (could validate the first 4 bytes of the block because they
1678
- # are the same as the first 4 bytes of the directory entry)
1679
- $len = Get32u(\$buf2, 4);
1680
- last if $len + 8 > $size;
1687
+ # set SamsungTagName ExifTool member for use in tag Condition
1688
+ $$et{SamsungTagName} = substr($buf2, 8, $len);
1681
1689
  # extract tag name and value
1682
1690
  $et->HandleTag($tagTablePtr, "$tag-name", undef,
1683
1691
  DataPt => \$buf2,
@@ -1691,6 +1699,7 @@ SamBlock:
1691
1699
  Start => 8 + $len,
1692
1700
  Size => $size - (8 + $len),
1693
1701
  );
1702
+ delete $$et{SamsungTagName};
1694
1703
  }
1695
1704
  if ($outfile) {
1696
1705
  last unless $raf->Seek($dataPos, 0) and $raf->Read($buff, $dirLen) == $dirLen;
@@ -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.68';
37
+ $VERSION = '3.69';
38
38
 
39
39
  sub ProcessSRF($$$);
40
40
  sub ProcessSR2($$$);
@@ -169,6 +169,7 @@ sub PrintInvLensSpec($;$$);
169
169
  32884 => 'Sony FE 70-200mm F4 Macro G OSS II', #JR
170
170
  32885 => 'Sony FE 16-35mm F2.8 GM II', #JR
171
171
  32886 => 'Sony FE 300mm F2.8 GM OSS', #JR
172
+ 32887 => 'Sony E PZ 16-50mm F3.5-5.6 OSS II', #JR
172
173
 
173
174
  # (comment this out so LensID will report the LensModel, which is more useful)
174
175
  # 32952 => 'Metabones Canon EF Speed Booster Ultra', #JR (corresponds to 184, but 'Advanced' mode, LensMount reported as E-mount)
@@ -239,6 +240,7 @@ sub PrintInvLensSpec($;$$);
239
240
  49474.8 => 'Viltrox 50mm F1.8 FE', #JR
240
241
  49474.9 => 'Viltrox 75mm F1.2 E', #JR
241
242
  '49474.10' => 'Viltrox 20mm F2.8 FE', #JR
243
+ 49475 => 'Tamron 50-300mm F4.5-6.3 Di III VC VXD', #JR (Model A069)
242
244
 
243
245
  49712 => 'Tokina FiRIN 20mm F2 FE AF', # (firmware Ver.01)
244
246
  49713 => 'Tokina FiRIN 100mm F2.8 FE MACRO', # (firmware Ver.01)
@@ -292,15 +294,18 @@ sub PrintInvLensSpec($;$$);
292
294
  50540 => 'Sigma 14mm F1.4 DG DN | A', #JR (023)
293
295
  50543 => 'Sigma 70-200mm F2.8 DG DN OS | S', #JR (023)
294
296
  50544 => 'Sigma 23mm F1.4 DC DN | C', #JR (023)
297
+ 50545 => 'Sigma 24-70mm F2.8 DG DN II | A', #JR (024)
295
298
  50546 => 'Sigma 500mm F5.6 DG DN OS | S', #JR (024)
296
299
  50547 => 'Sigma 10-18mm F2.8 DC DN | C', #JR (023)
297
300
  50548 => 'Sigma 15mm F1.4 DG DN DIAGONAL FISHEYE | A', #JR (024)
301
+ 50549 => 'Sigma 50mm F1.2 DG DN | A', #JR (024)
302
+ 50551 => 'Sigma 28-45mm F1.8 DG DN | A', #JR (024)
298
303
 
299
304
  50992 => 'Voigtlander SUPER WIDE-HELIAR 15mm F4.5 III', #JR
300
305
  50993 => 'Voigtlander HELIAR-HYPER WIDE 10mm F5.6', #IB
301
306
  50994 => 'Voigtlander ULTRA WIDE-HELIAR 12mm F5.6 III', #IB
302
307
  50995 => 'Voigtlander MACRO APO-LANTHAR 65mm F2 Aspherical', #JR
303
- 50996 => 'Voigtlander NOKTON 40mm F1.2 Aspherical', #JR
308
+ 50996 => 'Voigtlander NOKTON 40mm F1.2 Aspherical', #JR (also SE version)
304
309
  50997 => 'Voigtlander NOKTON classic 35mm F1.4', #JR
305
310
  50998 => 'Voigtlander MACRO APO-LANTHAR 110mm F2.5', #JR
306
311
  50999 => 'Voigtlander COLOR-SKOPAR 21mm F3.5 Aspherical', #IB
@@ -309,6 +314,7 @@ sub PrintInvLensSpec($;$$);
309
314
  51002 => 'Voigtlander APO-LANTHAR 50mm F2 Aspherical', #JR
310
315
  51003 => 'Voigtlander NOKTON 35mm F1.2 Aspherical SE', #JR
311
316
  51006 => 'Voigtlander APO-LANTHAR 35mm F2 Aspherical', #JR
317
+ 51007 => 'Voigtlander NOKTON 50mm F1 Aspherical', #JR
312
318
 
313
319
  # lenses listed in the Sigma MC-11 list, but not yet seen:
314
320
  # 504xx => 'Sigma 18-200mm F3.5-6.3 DC MACRO OS HSM | C + MC-11', # (014)
@@ -330,6 +336,8 @@ sub PrintInvLensSpec($;$$);
330
336
  51516 => 'Samyang AF 24-70mm F2.8', #JR
331
337
  51517 => 'Samyang AF 50mm F1.4 II', #JR
332
338
  51518 => 'Samyang AF 135mm F1.8', #JR
339
+
340
+ 61569 => 'LAOWA FFII 10mm F2.8 C&D Dreamer', #JR
333
341
  );
334
342
 
335
343
  # ExposureProgram values (ref PH, mainly decoded from A200)
@@ -1713,7 +1721,7 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 );
1713
1721
  },
1714
1722
  },{
1715
1723
  Name => 'Tag9050d',
1716
- Condition => '$$self{Model} =~ /^(ILCE-(6700|7CM2|7CR)|ZV-E1)\b/',
1724
+ Condition => '$$self{Model} =~ /^(ILCE-(6700|7CM2|7CR)|ZV-(E1|E10M2))\b/',
1717
1725
  SubDirectory => {
1718
1726
  TagTable => 'Image::ExifTool::Sony::Tag9050d',
1719
1727
  ByteOrder => 'LittleEndian',
@@ -1975,7 +1983,7 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 );
1975
1983
  },
1976
1984
  0x940c => [{
1977
1985
  Name => 'Tag940c',
1978
- Condition => '$$self{Model} =~ /^(NEX-|ILCE-|ILME-|Lunar|ZV-E10|ZV-E1)\b/',
1986
+ Condition => '$$self{Model} =~ /^(NEX-|ILCE-|ILME-|Lunar|ZV-E10|ZV-E10M2|ZV-E1)\b/',
1979
1987
  SubDirectory => { TagTable => 'Image::ExifTool::Sony::Tag940c' },
1980
1988
  },{
1981
1989
  Name => 'Sony_0x940c',
@@ -2151,6 +2159,8 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 );
2151
2159
  395 => 'ZV-1M2', #JR
2152
2160
  396 => 'ILCE-7CR', #JR
2153
2161
  397 => 'ILCE-7CM2', #JR
2162
+ 398 => 'ILX-LR1', #JR
2163
+ 399 => 'ZV-E10M2', #JR
2154
2164
  },
2155
2165
  },
2156
2166
  0xb020 => { #2
@@ -8201,7 +8211,7 @@ my %isoSetting2010 = (
8201
8211
  # number of mechanical shutter actuations, does not increase during electronic shutter / Silent Shooting
8202
8212
  Condition => '$$self{Model} =~ /^(ILCE-(6700|7CM2|7CR))/',
8203
8213
  Format => 'int32u',
8204
- Notes => 'total number of image exposures made by the camera',
8214
+ Notes => 'total number of mechanical shutter actuations',
8205
8215
  RawConv => '$val & 0x00ffffff',
8206
8216
  PrintConv => 'sprintf("%6d",$val)',
8207
8217
  PrintConvInv => '$val',
@@ -8228,6 +8238,7 @@ my %isoSetting2010 = (
8228
8238
  },
8229
8239
  0x0038 => {
8230
8240
  Name => 'InternalSerialNumber', #(NC)
8241
+ Condition => '$$self{Model} !~ /^(ZV-E10M2)/',
8231
8242
  Format => 'int8u[6]',
8232
8243
  PrintConv => 'unpack "H*", pack "C*", split " ", $val',
8233
8244
  },
@@ -8459,7 +8470,7 @@ my %isoSetting2010 = (
8459
8470
  },
8460
8471
  0x002a => [{
8461
8472
  Name => 'Quality2',
8462
- Condition => '$$self{Model} !~ /^(ILCE-(1|6700|7CM2|7CR|7M4|7RM5|7SM3|9M3)|ILME-(FX3|FX30)|ZV-E1)\b/',
8473
+ Condition => '$$self{Model} !~ /^(ILCE-(1|6700|7CM2|7CR|7M4|7RM5|7SM3|9M3)|ILME-(FX3|FX30)|ZV-(E1|E10M2))\b/',
8463
8474
  PrintConv => {
8464
8475
  0 => 'JPEG',
8465
8476
  1 => 'RAW',
@@ -8484,7 +8495,7 @@ my %isoSetting2010 = (
8484
8495
  # },
8485
8496
  0x0053 => {
8486
8497
  Name => 'ModelReleaseYear',
8487
- Condition => '$$self{Model} !~ /^(ILCE-(1|6700|7CM2|7CR|7M4|7RM5|7SM3|9M3)|ILME-(FX3|FX30)|ZV-E1)\b/',
8498
+ Condition => '$$self{Model} !~ /^(ILCE-(1|6700|7CM2|7CR|7M4|7RM5|7SM3|9M3)|ILME-(FX3|FX30)|ZV-(E1|E10M2))\b/',
8488
8499
  Format => 'int8u',
8489
8500
  PrintConv => 'sprintf("20%.2d", $val)',
8490
8501
  },
@@ -9530,7 +9541,6 @@ my %isoSetting2010 = (
9530
9541
  Name => 'FocusMode',
9531
9542
  Condition => '$$self{Model} =~ /^ILCA-/',
9532
9543
  Notes => 'ILCA models only',
9533
- Writable => 'int8u',
9534
9544
  Priority => 0,
9535
9545
  PrintConv => {
9536
9546
  0 => 'Manual',
@@ -9855,7 +9865,7 @@ my %isoSetting2010 = (
9855
9865
  WRITE_PROC => \&WriteEnciphered,
9856
9866
  CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
9857
9867
  FORMAT => 'int8u',
9858
- NOTES => 'Valid for the ILCE-1/6700/7CM2/7CR/7M4/7RM5/7SM3/9M3, ILME-FX3/FX30, ZV-E1.',
9868
+ NOTES => 'Valid for the ILCE-1/6700/7CM2/7CR/7M4/7RM5/7SM3/9M3, ILME-FX3/FX30, ZV-E1/E10M2.',
9859
9869
  FIRST_ENTRY => 0,
9860
9870
  GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
9861
9871
  0x0000 => { Name => 'Tag9416_0000', PrintConv => 'sprintf("%3d",$val)', RawConv => '$$self{TagVersion} = $val' },
@@ -10018,7 +10028,7 @@ my %isoSetting2010 = (
10018
10028
  },
10019
10029
  0x089d => { # Note: 32 values for these newer models, and 32 non-zero values present for new lenses like SEL2470GM2 and SEL2070G
10020
10030
  Name => 'VignettingCorrParams',
10021
- Condition => '$$self{Model} =~ /^(ILCE-(6700|7CM2|7CR|7RM5)|ILME-FX30|ZV-E1)\b/',
10031
+ Condition => '$$self{Model} =~ /^(ILCE-(6700|7CM2|7CR|7RM5)|ILME-FX30|ZV-(E1|E10M2))\b/',
10022
10032
  Format => 'int16s[32]',
10023
10033
  },
10024
10034
  0x08b5 => {
@@ -10057,7 +10067,7 @@ my %isoSetting2010 = (
10057
10067
  },
10058
10068
  0x0945 => {
10059
10069
  Name => 'ChromaticAberrationCorrParams',
10060
- Condition => '$$self{Model} =~ /^(ILCE-(6700|7CM2|7CR|7RM5)|ILME-FX30|ZV-E1)\b/',
10070
+ Condition => '$$self{Model} =~ /^(ILCE-(6700|7CM2|7CR|7RM5)|ILME-FX30|ZV-(E1|E10M2))\b/',
10061
10071
  Format => 'int16s[32]',
10062
10072
  },
10063
10073
  );