exiftool_vendored 13.19.0 → 13.21.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.
@@ -18,7 +18,7 @@ use strict;
18
18
  use vars qw($VERSION);
19
19
  use Image::ExifTool qw(:DataAccess :Utils);
20
20
 
21
- $VERSION = '1.02';
21
+ $VERSION = '1.03';
22
22
 
23
23
  sub ProcessProtobuf($$$;$);
24
24
 
@@ -178,7 +178,7 @@ sub ProcessProtobuf($$$;$)
178
178
  } else {
179
179
  $val = ReadValue(\$buff, 0, $$tagInfo{Format}, undef, length($buff));
180
180
  }
181
- } elsif ($type == 0) {
181
+ } elsif ($type == 0) { # varInt
182
182
  $val = $buff;
183
183
  my $hex = sprintf('%x', $val);
184
184
  if (length($hex) == 16 and $hex =~ /^ffffffff/) {
@@ -188,9 +188,9 @@ sub ProcessProtobuf($$$;$)
188
188
  my $signed = ($val & 1) ? -($val >> 1)-1 : ($val >> 1);
189
189
  $val .= " (0x$hex, signed $signed)";
190
190
  }
191
- } elsif ($type == 1) {
191
+ } elsif ($type == 1) { # 64-bit number
192
192
  $val = '0x' . unpack('H*', $buff) . ' (double ' . GetDouble(\$buff,0) . ')';
193
- } elsif ($type == 2) {
193
+ } elsif ($type == 2) { # string, bytes or protobuf
194
194
  if ($$tagInfo{SubDirectory}) {
195
195
  # (fall through to process known SubDirectory)
196
196
  } elsif ($$tagInfo{IsProtobuf}) {
@@ -203,14 +203,25 @@ sub ProcessProtobuf($$$;$)
203
203
  ProcessProtobuf($et, \%subdir, $tagTbl, "$prefix$id-");
204
204
  $$et{INDENT} = substr($$et{INDENT}, 0, -2);
205
205
  next;
206
- } elsif ($buff !~ /[^\x20-\x7e]/) {
207
- $val = $buff; # assume this is an ASCII string
208
- } elsif (length($buff) % 4) {
209
- $val = '0x' . unpack('H*', $buff);
210
206
  } else {
211
- $val = '0x' . join(' ', unpack('(H8)*', $buff)); # (group in 4-byte blocks)
207
+ # check for rational value (2 varInt values)
208
+ my $rat;
209
+ my %dir = ( DataPt => \$buff, Pos => 0 );
210
+ my $num = VarInt(\%dir);
211
+ if (defined $num) {
212
+ my $denom = VarInt(\%dir);
213
+ $rat = " (rational $num/$denom)" if $denom and $dir{Pos} == length($buff);
214
+ }
215
+ if ($buff !~ /[^\x20-\x7e]/) {
216
+ $val = $buff; # assume this is an ASCII string
217
+ } elsif (length($buff) % 4) {
218
+ $val = '0x' . unpack('H*', $buff);
219
+ } else {
220
+ $val = '0x' . join(' ', unpack('(H8)*', $buff)); # (group in 4-byte blocks)
221
+ }
222
+ $val .= $rat if $rat;
212
223
  }
213
- } elsif ($type == 5) {
224
+ } elsif ($type == 5) { # 32-bit number
214
225
  $val = '0x' . unpack('H*', $buff) . ' (int32u ' . Get32u(\$buff, 0);
215
226
  $val .= ', int32s ' . Get32s(\$buff, 0) if ord(substr($buff,3,1)) & 0x80;
216
227
  $val .= ', float ' . GetFloat(\$buff, 0) . ')';
@@ -43,12 +43,12 @@
43
43
  package Image::ExifTool::QuickTime;
44
44
 
45
45
  use strict;
46
- use vars qw($VERSION $AUTOLOAD %stringEncoding %avType %dontInherit);
46
+ use vars qw($VERSION $AUTOLOAD %stringEncoding %avType %dontInherit %eeBox);
47
47
  use Image::ExifTool qw(:DataAccess :Utils);
48
48
  use Image::ExifTool::Exif;
49
49
  use Image::ExifTool::GPS;
50
50
 
51
- $VERSION = '3.12';
51
+ $VERSION = '3.13';
52
52
 
53
53
  sub ProcessMOV($$;$);
54
54
  sub ProcessKeys($$$);
@@ -513,7 +513,7 @@ my %hashBox = ( vide => { %eeStd }, soun => { %eeStd } );
513
513
  # when the ExtractEmbedded is enabled (currently only the 'gps ' container name is
514
514
  # used, but others have been checked against all available sample files and may be
515
515
  # useful in the future if the names are used for different boxes on other locations)
516
- my %eeBox = (
516
+ %eeBox = (
517
517
  # (note: vide is only processed if specific atoms exist in the VisualSampleDesc)
518
518
  vide => { %eeStd, JPEG => 'stsd' },
519
519
  text => { %eeStd },
@@ -1600,28 +1600,6 @@ my %userDefined = (
1600
1600
  PrintConv => \&PrintGPSCoordinates,
1601
1601
  PrintConvInv => \&PrintInvGPSCoordinates,
1602
1602
  },
1603
- # \xa9 tags written by DJI Phantom 3: (ref PH)
1604
- "\xa9xsp" => 'SpeedX', #PH (guess)
1605
- "\xa9ysp" => 'SpeedY', #PH (guess)
1606
- "\xa9zsp" => 'SpeedZ', #PH (guess)
1607
- "\xa9fpt" => 'Pitch', #PH
1608
- "\xa9fyw" => 'Yaw', #PH
1609
- "\xa9frl" => 'Roll', #PH
1610
- "\xa9gpt" => 'CameraPitch', #PH
1611
- "\xa9gyw" => 'CameraYaw', #PH
1612
- "\xa9grl" => 'CameraRoll', #PH
1613
- "\xa9enc" => 'EncoderID', #PH (forum9271)
1614
- # and the following entries don't have the proper 4-byte header for \xa9 tags:
1615
- "\xa9dji" => { Name => 'UserData_dji', Format => 'undef', Binary => 1, Unknown => 1, Hidden => 1 },
1616
- "\xa9res" => { Name => 'UserData_res', Format => 'undef', Binary => 1, Unknown => 1, Hidden => 1 },
1617
- "\xa9uid" => { Name => 'UserData_uid', Format => 'undef', Binary => 1, Unknown => 1, Hidden => 1 },
1618
- "\xa9mdl" => {
1619
- Name => 'Model',
1620
- Notes => 'non-standard-format DJI tag',
1621
- Format => 'string',
1622
- Avoid => 1,
1623
- },
1624
- # end DJI tags
1625
1603
  name => 'Name',
1626
1604
  WLOC => {
1627
1605
  Name => 'WindowLocation',
@@ -2092,7 +2070,35 @@ my %userDefined = (
2092
2070
  "\xa9TSC" => 'StartTimeScale', # (Hero6)
2093
2071
  "\xa9TSZ" => 'StartTimeSampleSize', # (Hero6)
2094
2072
  "\xa9TIM" => 'StartTimecode', #PH (NC)
2095
- # --- HTC ----
2073
+ # ---- DJI ----
2074
+ # \xa9 tags written by DJI Phantom 3: (ref PH)
2075
+ "\xa9xsp" => 'SpeedX', #PH (guess)
2076
+ "\xa9ysp" => 'SpeedY', #PH (guess)
2077
+ "\xa9zsp" => 'SpeedZ', #PH (guess)
2078
+ "\xa9fpt" => 'Pitch', #PH
2079
+ "\xa9fyw" => 'Yaw', #PH
2080
+ "\xa9frl" => 'Roll', #PH
2081
+ "\xa9gpt" => 'CameraPitch', #PH
2082
+ "\xa9gyw" => 'CameraYaw', #PH
2083
+ "\xa9grl" => 'CameraRoll', #PH
2084
+ "\xa9enc" => 'EncoderID', #PH (forum9271)
2085
+ # and the following entries don't have the proper 4-byte header for \xa9 tags:
2086
+ "\xa9dji" => { Name => 'UserData_dji', Format => 'undef', Binary => 1, Unknown => 1, Hidden => 1 },
2087
+ "\xa9res" => { Name => 'UserData_res', Format => 'undef', Binary => 1, Unknown => 1, Hidden => 1 },
2088
+ "\xa9uid" => { Name => 'UserData_uid', Format => 'undef', Binary => 1, Unknown => 1, Hidden => 1 },
2089
+ "\xa9mdl" => {
2090
+ Name => 'Model',
2091
+ Notes => 'non-standard-format DJI tag',
2092
+ Format => 'string',
2093
+ Avoid => 1,
2094
+ },
2095
+ btec => {
2096
+ Name => 'GlamourSettings',
2097
+ SubDirectory => { TagTable => 'Image::ExifTool::DJI::Glamour' },
2098
+ },
2099
+ fsid => 'OriginalFilePath',
2100
+ # dbcm - seen "\0\0\0\x04"
2101
+ # ---- HTC ----
2096
2102
  htcb => {
2097
2103
  Name => 'HTCBinary',
2098
2104
  SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HTCBinary' },
@@ -8081,6 +8087,7 @@ my %userDefined = (
8081
8087
  Name => 'TimeCode',
8082
8088
  SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TimeCode' },
8083
8089
  },
8090
+ # dbgi - used by DJI - seen "\0\0\0\0"
8084
8091
  );
8085
8092
 
8086
8093
  # TimeCode header
@@ -8203,6 +8210,11 @@ my %userDefined = (
8203
8210
  Name => 'HandlerType',
8204
8211
  Format => 'undef[4]',
8205
8212
  RawConv => q{
8213
+ unless ($$self{HasHandler}{$val} or not $Image::ExifTool::QuickTime::eeBox{$val}
8214
+ or $val eq 'vide' or $$self{OPTIONS}{ExtractEmbedded} or $$self{OPTIONS}{Validate})
8215
+ {
8216
+ Image::ExifTool::QuickTime::EEWarn($self);
8217
+ }
8206
8218
  $$self{HandlerType} = $val unless $val eq 'alis' or $val eq 'url ';
8207
8219
  $$self{MediaType} = $val if @{$$self{PATH}} > 1 and $$self{PATH}[-2] eq 'Media';
8208
8220
  $$self{HasHandler}{$val} = 1; # remember all our handlers
@@ -9805,7 +9817,7 @@ sub ProcessMOV($$;$)
9805
9817
  }
9806
9818
  $$raf{NoBuffer} = 1 if $fast; # disable buffering in FastScan mode
9807
9819
 
9808
- my $ee = $$et{OPTIONS}{ExtractEmbedded};
9820
+ my $ee = $$et{OPTIONS}{ExtractEmbedded} || 0;
9809
9821
  my $hash = $$et{ImageDataHash};
9810
9822
  if ($ee or $hash) {
9811
9823
  $unkOpt = $$et{OPTIONS}{Unknown};
@@ -9879,7 +9891,7 @@ sub ProcessMOV($$;$)
9879
9891
  }
9880
9892
  if ($isUserData and $$et{SET_GROUP1}) {
9881
9893
  my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
9882
- unless ($$tagInfo{SubDirectory}) {
9894
+ unless ($tagInfo and $$tagInfo{SubDirectory}) {
9883
9895
  # add track name to UserData tags inside tracks
9884
9896
  $tag = $$et{SET_GROUP1} . $tag;
9885
9897
  if (not $$tagTablePtr{$tag} and $tagInfo) {
@@ -9902,10 +9914,8 @@ sub ProcessMOV($$;$)
9902
9914
  $eeTag = 1;
9903
9915
  $$et{OPTIONS}{Unknown} = 1; # temporarily enable "Unknown" option
9904
9916
  }
9905
- } elsif ($handlerType ne 'vide' and not $$et{OPTIONS}{Validate}) {
9906
- EEWarn($et);
9907
9917
  }
9908
- } elsif ($ee and $ee > 1 and $eeBox2{$handlerType} and $eeBox2{$handlerType}{$tag}) {
9918
+ } elsif ($ee > 1 and $eeBox2{$handlerType} and $eeBox2{$handlerType}{$tag}) {
9909
9919
  $eeTag = 1;
9910
9920
  $$et{OPTIONS}{Unknown} = 1;
9911
9921
  } elsif ($hash and $hashBox{$handlerType} and $hashBox{$handlerType}{$tag}) {
@@ -1446,7 +1446,6 @@ Sample: for ($i=0; ; ) {
1446
1446
  $$et{ee} = $ee; # need ee information for 'keys'
1447
1447
  $et->HandleTag($tagTbl, $metaFormat, undef,
1448
1448
  DataPt => \$buff,
1449
- DataPos => 0,
1450
1449
  Base => $$start[$i], # (Base must be set for CR3 files)
1451
1450
  TagInfo => $tagInfo,
1452
1451
  );
@@ -1494,7 +1493,6 @@ Sample: for ($i=0; ; ) {
1494
1493
  FoundSomething($et, $tagTbl, $time[$i], $dur[$i]);
1495
1494
  $et->HandleTag($tagTbl, $type, undef,
1496
1495
  DataPt => \$buff,
1497
- DataPos => 0,
1498
1496
  Base => $$start[$i], # (Base must be set for CR3 files)
1499
1497
  TagInfo => $tagInfo,
1500
1498
  );
@@ -1571,6 +1569,7 @@ sub ProcessFreeGPS($$$)
1571
1569
  my $debug = $et->Options('Debug');
1572
1570
  my $oldOrder = GetByteOrder();
1573
1571
  SetByteOrder('II');
1572
+ $$et{FoundEmbedded} = 1;
1574
1573
 
1575
1574
  if (substr($$dataPt,18,8) eq "\xaa\xaa\xf2\xe1\xf0\xee\x54\x54") {
1576
1575
 
@@ -3548,50 +3547,85 @@ sub ProcessWolfbox($$$)
3548
3547
  }
3549
3548
 
3550
3549
  #------------------------------------------------------------------------------
3551
- # Scan media data for "freeGPS" metadata if not found already (ref PH)
3550
+ # Scan media data for "freeGPS" and GoPro metadata if not found already (ref PH)
3552
3551
  # Inputs: 0) ExifTool ref
3553
3552
  sub ScanMediaData($)
3554
3553
  {
3555
3554
  my $et = shift;
3556
3555
  my $raf = $$et{RAF} or return;
3557
- my ($tagTbl, $verbose, $buff, $dataLen);
3558
- my ($pos, $buf2) = (0, '');
3556
+ my ($tagTbl, $verbose, $buff, $dataLen, $found);
3559
3557
 
3560
3558
  # don't rescan for freeGPS if we already found embedded metadata
3561
3559
  my $dataPos = $$et{MediaDataOffset};
3562
- if ($dataPos and not $$et{DOC_COUNT}) {
3560
+ return if $$et{FoundEmbedded} or not $dataPos;
3561
+
3562
+ my ($pos, $buf2) = (0, '');
3563
+ my $ee = $et->Options('ExtractEmbedded');
3564
+ if ($ee > 2) { # scan entire file from start of mdat if ExtractEmbedded > 2
3565
+ $raf->Seek(0,2);
3566
+ $dataLen = $raf->Tell() - $$et{MediaDataOffset};
3567
+ } else {
3563
3568
  $dataLen = $$et{MediaDataSize};
3564
- if ($dataLen) {
3565
- if ($raf->Seek($dataPos, 0)) {
3566
- $$et{FreeGPS2} = { }; # initialize variable space for FreeGPS2()
3567
- } else {
3568
- undef $dataLen;
3569
- }
3570
- }
3571
3569
  }
3570
+ return unless $dataLen and $raf->Seek($dataPos);
3572
3571
 
3573
3572
  # loop through 'mdat' media data looking for GPS information
3574
3573
  while ($dataLen) {
3575
- last if $pos + $gpsBlockSize > $dataLen;
3576
- last unless $raf->Read($buff, $gpsBlockSize);
3574
+ my $n = $gpsBlockSize;
3575
+ $n = $dataLen - $pos if $n + $pos > $dataLen;
3576
+ last unless $n > length($buf2) and $raf->Read($buff, $n - length($buf2));
3577
3577
  $buff = $buf2 . $buff if length $buf2;
3578
- last if length $buff < $gpsBlockSize;
3579
- # look for "freeGPS " block
3580
- # (found on an absolute 0x8000-byte boundary in all of my samples,
3578
+ # look for "freeGPS " or GoPro record
3579
+ # (freeGPS found on an absolute 0x8000-byte boundary in all of my samples,
3581
3580
  # but allow for any alignment when searching)
3582
- if ($buff !~ /\0..\0freeGPS /sg) { # (seen ".." = "\0\x80","\x01\0")
3581
+ if ($buff !~ /(\0..\0freeGPS |GP\x06\0\0)/sg) {
3583
3582
  $buf2 = substr($buff,-12);
3584
3583
  $pos += length($buff)-12;
3585
3584
  # in all of my samples the first freeGPS block is within 2 MB of the start
3586
3585
  # of the mdat, so limit the scan to the first 20 MB to be fast and safe
3587
- next if $tagTbl or $pos < 20e6;
3586
+ next if $found or $pos < 20e6 or $ee > 1;
3588
3587
  last;
3589
- } elsif (not $tagTbl) {
3588
+ } elsif ($1 eq "GP\x06\0\0") { # (GoPro GPS record header)
3589
+ # (found in Chigee Aio-5 Lite and some Insta360 videos)
3590
+ my $buffPos = pos($buff);
3591
+ my $filePos = $raf->Tell();
3592
+ my $start = $filePos - length($buff) + $buffPos - length($1);
3593
+ $raf->Seek($start) or last;
3594
+ unless (defined $found) {
3595
+ $et->VPrint(0, "---- Extract Embedded ----\n");
3596
+ $$et{INDENT} .= '| ';
3597
+ $found = 0;
3598
+ }
3599
+ my $maxLen = $dataLen - ($start - $$et{MediaDataOffset});
3600
+ require Image::ExifTool::GoPro;
3601
+ $et->VPrint(0, sprintf("Unreferenced GoPro record at 0x%x\n",$filePos));
3602
+ my $size = Image::ExifTool::GoPro::ProcessGP6($et, { RAF => $raf, DirLen => $maxLen });
3603
+ if ($size) {
3604
+ unless ($found) {
3605
+ # scan entire file if we found a valid GoPro record
3606
+ # (some records may exist in trailer)
3607
+ $raf->Seek(0, 2) and $dataLen = $raf->Tell() - $$et{MediaDataOffset};
3608
+ $found = 2;
3609
+ }
3610
+ $raf->Seek($start + $size) or last;
3611
+ $pos = $start + $size - $$et{MediaDataOffset};
3612
+ $buf2 = '';
3613
+ } else {
3614
+ # (could have been a random match -- continue with search)
3615
+ $raf->Seek($filePos) or last;
3616
+ $buf2 = substr($buff, $buffPos);
3617
+ $pos += $buffPos;
3618
+ }
3619
+ next;
3620
+ }
3621
+ last if length $buff < $gpsBlockSize;
3622
+ if (not $tagTbl) {
3590
3623
  # initialize variables for extracting metadata from this block
3591
3624
  $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream');
3592
3625
  $verbose = $$et{OPTIONS}{Verbose};
3593
3626
  $et->VPrint(0, "---- Extract Embedded ----\n");
3594
3627
  $$et{INDENT} .= '| ';
3628
+ $found = 1;
3595
3629
  }
3596
3630
  if (pos($buff) > 12) {
3597
3631
  $pos += pos($buff) - 12;
@@ -3618,7 +3652,7 @@ sub ScanMediaData($)
3618
3652
  $pos += $len;
3619
3653
  $buf2 = substr($buff, $len);
3620
3654
  }
3621
- if ($tagTbl) {
3655
+ if ($found) {
3622
3656
  delete $$et{DOC_NUM}; # reset DOC_NUM after extracting embedded metadata
3623
3657
  $et->VPrint(0, "--------------------------\n");
3624
3658
  $$et{INDENT} = substr $$et{INDENT}, 0, -2;
@@ -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.70';
33
+ $VERSION = '1.71';
34
34
 
35
35
  sub ConvertTimecode($);
36
36
  sub ProcessSGLT($$$);
@@ -1319,9 +1319,9 @@ my %code2charset = (
1319
1319
  Name => 'ImageWidth',
1320
1320
  Format => 'int16u',
1321
1321
  Priority => 0,
1322
- # add " (lossless)" to FileType since image has a VP8L (lossless) chunk
1322
+ # add " Lossless" to FileType since image has a VP8L (lossless) chunk
1323
1323
  RawConv => q{
1324
- $self->OverrideFileType($$self{VALUE}{FileType} . ' (lossless)', undef, 'webp');
1324
+ $self->OverrideFileType($$self{VALUE}{FileType} . ' Lossless', undef, 'webp');
1325
1325
  return $val;
1326
1326
  },
1327
1327
  ValueConv => '($val & 0x3fff) + 1',