exiftool-vendored.exe 12.69.0 → 12.72.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.
Files changed (43) hide show
  1. package/bin/exiftool_files/Changes +78 -12
  2. package/bin/exiftool_files/README +10 -10
  3. package/bin/exiftool_files/exiftool.pl +32 -27
  4. package/bin/exiftool_files/lib/Image/ExifTool/AAC.pm +175 -0
  5. package/bin/exiftool_files/lib/Image/ExifTool/BuildTagLookup.pm +2 -1
  6. package/bin/exiftool_files/lib/Image/ExifTool/CBOR.pm +18 -2
  7. package/bin/exiftool_files/lib/Image/ExifTool/Canon.pm +82 -20
  8. package/bin/exiftool_files/lib/Image/ExifTool/DJI.pm +3 -2
  9. package/bin/exiftool_files/lib/Image/ExifTool/EXE.pm +54 -6
  10. package/bin/exiftool_files/lib/Image/ExifTool/Exif.pm +111 -11
  11. package/bin/exiftool_files/lib/Image/ExifTool/FujiFilm.pm +145 -20
  12. package/bin/exiftool_files/lib/Image/ExifTool/GIF.pm +5 -1
  13. package/bin/exiftool_files/lib/Image/ExifTool/GoPro.pm +16 -1
  14. package/bin/exiftool_files/lib/Image/ExifTool/ID3.pm +76 -10
  15. package/bin/exiftool_files/lib/Image/ExifTool/InDesign.pm +1 -1
  16. package/bin/exiftool_files/lib/Image/ExifTool/JPEG.pm +1 -1
  17. package/bin/exiftool_files/lib/Image/ExifTool/JSON.pm +4 -1
  18. package/bin/exiftool_files/lib/Image/ExifTool/Jpeg2000.pm +30 -15
  19. package/bin/exiftool_files/lib/Image/ExifTool/M2TS.pm +21 -16
  20. package/bin/exiftool_files/lib/Image/ExifTool/MakerNotes.pm +2 -2
  21. package/bin/exiftool_files/lib/Image/ExifTool/Nikon.pm +203 -102
  22. package/bin/exiftool_files/lib/Image/ExifTool/Olympus.pm +7 -1
  23. package/bin/exiftool_files/lib/Image/ExifTool/PNG.pm +8 -13
  24. package/bin/exiftool_files/lib/Image/ExifTool/Panasonic.pm +10 -1
  25. package/bin/exiftool_files/lib/Image/ExifTool/Pentax.pm +15 -6
  26. package/bin/exiftool_files/lib/Image/ExifTool/QuickTime.pm +59 -13
  27. package/bin/exiftool_files/lib/Image/ExifTool/QuickTimeStream.pl +59 -11
  28. package/bin/exiftool_files/lib/Image/ExifTool/README +7 -2
  29. package/bin/exiftool_files/lib/Image/ExifTool/RIFF.pm +53 -9
  30. package/bin/exiftool_files/lib/Image/ExifTool/Ricoh.pm +109 -1
  31. package/bin/exiftool_files/lib/Image/ExifTool/Samsung.pm +3 -2
  32. package/bin/exiftool_files/lib/Image/ExifTool/Sony.pm +177 -37
  33. package/bin/exiftool_files/lib/Image/ExifTool/TagLookup.pm +6961 -6856
  34. package/bin/exiftool_files/lib/Image/ExifTool/TagNames.pod +580 -344
  35. package/bin/exiftool_files/lib/Image/ExifTool/Text.pm +4 -5
  36. package/bin/exiftool_files/lib/Image/ExifTool/Validate.pm +6 -5
  37. package/bin/exiftool_files/lib/Image/ExifTool/WriteExif.pl +19 -4
  38. package/bin/exiftool_files/lib/Image/ExifTool/WriteQuickTime.pl +1 -0
  39. package/bin/exiftool_files/lib/Image/ExifTool/WriteRIFF.pl +9 -3
  40. package/bin/exiftool_files/lib/Image/ExifTool/Writer.pl +102 -50
  41. package/bin/exiftool_files/lib/Image/ExifTool.pm +74 -36
  42. package/bin/exiftool_files/lib/Image/ExifTool.pod +28 -17
  43. package/package.json +5 -4
@@ -40,7 +40,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
40
40
  use Image::ExifTool::Exif;
41
41
  use Image::ExifTool::APP12;
42
42
 
43
- $VERSION = '2.81';
43
+ $VERSION = '2.82';
44
44
 
45
45
  sub PrintLensInfo($$$);
46
46
 
@@ -186,7 +186,9 @@ my %olympusLensTypes = (
186
186
  '2 36 10' => 'Leica DG Elmarit 200mm F2.8 Power OIS', #IB
187
187
  '2 37 10' => 'Leica DG Vario-Elmarit 50-200mm F2.8-4 Asph. Power OIS', #IB
188
188
  '2 38 10' => 'Leica DG Vario-Summilux 10-25mm F1.7 Asph.', #IB
189
+ '2 39 10' => 'Leica DG Summilux 25mm F1.4 II Asph.', #forum15345
189
190
  '2 40 10' => 'Leica DG Vario-Summilux 25-50mm F1.7 Asph.', #IB (H-X2550)
191
+ '2 41 10' => 'Leica DG Summilux 9mm F1.7 Asph.', #forum15345
190
192
  '3 01 00' => 'Leica D Vario Elmarit 14-50mm F2.8-3.5 Asph.', #11
191
193
  '3 02 00' => 'Leica D Summilux 25mm F1.4 Asph.', #11
192
194
  # Tamron lenses
@@ -358,6 +360,7 @@ my %olympusCameraTypes = (
358
360
  D4521 => 'SH-25MR',
359
361
  D4523 => 'SP-720UZ',
360
362
  D4529 => 'VG170',
363
+ D4530 => 'VH210',
361
364
  D4531 => 'XZ-2',
362
365
  D4535 => 'SP-620UZ',
363
366
  D4536 => 'TG-320',
@@ -383,9 +386,11 @@ my %olympusCameraTypes = (
383
386
  D4585 => 'SH-2 / SH-3',
384
387
  D4586 => 'TG-4',
385
388
  D4587 => 'TG-860',
389
+ D4590 => 'TG-TRACKER',
386
390
  D4591 => 'TG-870',
387
391
  D4593 => 'TG-5', #IB
388
392
  D4603 => 'TG-6', #IB
393
+ D4605 => 'TG-7',
389
394
  D4809 => 'C2500L',
390
395
  D4842 => 'E-10',
391
396
  D4856 => 'C-1',
@@ -431,6 +436,7 @@ my %olympusCameraTypes = (
431
436
  S0076 => 'E-PL9', #IB
432
437
  S0080 => 'E-M1X', #IB
433
438
  S0085 => 'E-PL10', #IB
439
+ S0088 => 'E-M10MarkIV',
434
440
  S0089 => 'E-M5MarkIII',
435
441
  S0092 => 'E-M1MarkIII', #IB
436
442
  S0093 => 'E-P7', #IB
@@ -80,6 +80,7 @@ my %pngMap = (
80
80
  ICC_Profile => 'PNG',
81
81
  Photoshop => 'PNG',
82
82
  'PNG-pHYs' => 'PNG',
83
+ JUMBF => 'PNG',
83
84
  IPTC => 'Photoshop',
84
85
  MakerNotes => 'ExifIFD',
85
86
  );
@@ -341,6 +342,7 @@ my %noLeapFrog = ( SAVE => 1, SEEK => 1, IHDR => 1, JHDR => 1, IEND => 1, MEND =
341
342
  },
342
343
  caBX => { # C2PA metadata
343
344
  Name => 'JUMBF',
345
+ Deletable => 1,
344
346
  SubDirectory => { TagTable => 'Image::ExifTool::Jpeg2000::Main' },
345
347
  },
346
348
  cICP => {
@@ -973,20 +975,13 @@ sub FoundPNG($$$$;$$$$)
973
975
  undef $processProc if $wasCompressed and $processProc and $processProc eq \&ProcessPNG_Compressed;
974
976
  # rewrite this directory if necessary (but always process TextualData normally)
975
977
  if ($outBuff and not $processProc and $subTable ne \%Image::ExifTool::PNG::TextualData) {
976
- # allow JUMBF to be deleted (may want to expand this for other types too?)
977
- if ($dirName eq 'JUMBF' and $$et{DEL_GROUP}{$dirName}) {
978
- $$outBuff = '';
979
- ++$$et{CHANGED};
980
- $et->VPrint(0, " Deleting $dirName");
981
- } else {
982
- return 1 unless $$et{EDIT_DIRS}{$dirName};
983
- $$outBuff = $et->WriteDirectory(\%subdirInfo, $subTable);
984
- if ($tagName eq 'XMP' and $$outBuff) {
985
- # make sure the XMP is marked as read-only
986
- Image::ExifTool::XMP::ValidateXMP($outBuff,'r');
987
- }
988
- DoneDir($et, $dirName, $outBuff, $$tagInfo{NonStandard});
978
+ return 1 unless $$et{EDIT_DIRS}{$dirName};
979
+ $$outBuff = $et->WriteDirectory(\%subdirInfo, $subTable);
980
+ if ($tagName eq 'XMP' and $$outBuff) {
981
+ # make sure the XMP is marked as read-only
982
+ Image::ExifTool::XMP::ValidateXMP($outBuff,'r');
989
983
  }
984
+ DoneDir($et, $dirName, $outBuff, $$tagInfo{NonStandard});
990
985
  } else {
991
986
  $processed = $et->ProcessDirectory(\%subdirInfo, $subTable, $processProc);
992
987
  }
@@ -37,7 +37,7 @@ use vars qw($VERSION %leicaLensTypes);
37
37
  use Image::ExifTool qw(:DataAccess :Utils);
38
38
  use Image::ExifTool::Exif;
39
39
 
40
- $VERSION = '2.20';
40
+ $VERSION = '2.21';
41
41
 
42
42
  sub ProcessLeicaLEIC($$$);
43
43
  sub WhiteBalanceConv($;$$);
@@ -1991,6 +1991,15 @@ my %shootingMode = (
1991
1991
  },
1992
1992
  PrintConvInv => '$_=$val; tr/A-Z0-9//dc; s/(.{3})(19|20)/$1/; $_',
1993
1993
  },
1994
+ 0x05ff => {
1995
+ Name => 'CameraIFD', # (Leica Q3)
1996
+ Condition => '$$valPt =~ /^(II\x2a\0\x08\0\0\0|MM\0\x2a\0\0\0\x08)/',
1997
+ SubDirectory => {
1998
+ TagTable => 'Image::ExifTool::PanasonicRaw::CameraIFD',
1999
+ Base => '$start',
2000
+ ProcessProc => \&Image::ExifTool::ProcessTIFF,
2001
+ },
2002
+ },
1994
2003
  );
1995
2004
 
1996
2005
  # Leica type5 ShotInfo (ref PH) (X2)
@@ -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.44';
61
+ $VERSION = '3.45';
62
62
 
63
63
  sub CryptShutterCount($$);
64
64
  sub PrintFilter($$$);
@@ -410,7 +410,8 @@ sub DecodeAFPoints($$$$;$);
410
410
  #
411
411
  # Ricoh lenses
412
412
  #
413
- '31 1' => 'GR Lens', #PH (GR III 28mm F2.8)
413
+ '31 1' => '18.3mm F2.8', #PH (GR III built-in)
414
+ '31 4' => '26.1mm F2.8', #PH (GR IIIx built-in)
414
415
  );
415
416
 
416
417
  # Pentax model ID codes - PH
@@ -1141,8 +1142,12 @@ my %binaryDataAttrs = (
1141
1142
  3 => 'Manual',
1142
1143
  4 => 'Super Macro', #JD
1143
1144
  5 => 'Pan Focus',
1144
- # 8 - seen for Ricoh GR III
1145
- # 9 - seen for Ricoh GR III
1145
+ 6 => 'Auto-area', # (GR III)
1146
+ 8 => 'Select', # (GR III)
1147
+ 9 => 'Pinpoint', # (GR III)
1148
+ 10 => 'Tracking', # (GR III)
1149
+ 11 => 'Continuous', # (GR III)
1150
+ 12 => 'Snap', # (GR III)
1146
1151
  16 => 'AF-S (Focus-priority)', #17
1147
1152
  17 => 'AF-C (Focus-priority)', #17
1148
1153
  18 => 'AF-A (Focus-priority)', #PH (educated guess)
@@ -1903,6 +1908,7 @@ my %binaryDataAttrs = (
1903
1908
  '0 28' => 'Quick Macro', # (Q)
1904
1909
  '0 29' => 'Forest', # (Q)
1905
1910
  '0 30' => 'Backlight Silhouette', # (Q)
1911
+ '0 32' => 'DOF', #PH (GR III)
1906
1912
  # AUTO PICT modes (auto-selected)
1907
1913
  '1 4' => 'Auto PICT (Standard)', #13
1908
1914
  '1 5' => 'Auto PICT (Portrait)', #7 (K100D)
@@ -2146,6 +2152,7 @@ my %binaryDataAttrs = (
2146
2152
  10 => 'Cross Processing', #31 (K-70)
2147
2153
  11 => 'Flat', #31 (K-70)
2148
2154
  # 256 - seen for GR III
2155
+ # 257 - seen for GR III
2149
2156
  # 262 - seen for GR III
2150
2157
  32768 => 'n/a',
2151
2158
  },
@@ -2584,8 +2591,10 @@ my %binaryDataAttrs = (
2584
2591
  PrintConv => {
2585
2592
  0 => 'Off',
2586
2593
  1 => 'On',
2587
- '0 2' => 'Off (0 2)', #PH (NC, GR III)
2588
- '1 2' => 'On (1 2)', #PH (NC, GR III)
2594
+ '0 0' => 'Off (Off)', #PH (GR III)
2595
+ '1 1' => 'On (On)', #PH (GR III)
2596
+ '0 2' => 'Off (Auto)', #PH (GR III)
2597
+ '1 2' => 'On (Auto)', #PH (GR III)
2589
2598
  },
2590
2599
  },
2591
2600
  0x008b => { #PH (LS465)
@@ -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.88';
51
+ $VERSION = '2.91';
52
52
 
53
53
  sub ProcessMOV($$;$);
54
54
  sub ProcessKeys($$$);
@@ -638,6 +638,33 @@ my %isImageData = ( av01 => 1, avc1 => 1, hvc1 => 1, lhv1 => 1, hvt1 => 1 );
638
638
  Condition => '$$valPt=~/^\xef\xe1\x58\x9a\xbb\x77\x49\xef\x80\x95\x27\x75\x9e\xb1\xdc\x6f/ and $$self{OPTIONS}{ExtractEmbedded}',
639
639
  SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Tags360Fly' },
640
640
  },
641
+ { #https://c2pa.org/specifications/
642
+ Name => 'JUMBF',
643
+ Condition => '$$valPt=~/^\xd8\xfe\xc3\xd6\x1b\x0e\x48\x3c\x92\x97\x58\x28\x87\x7e\xc4\x81.{4}manifest\0/s',
644
+ Deletable => 1,
645
+ SubDirectory => {
646
+ TagTable => 'Image::ExifTool::Jpeg2000::Main',
647
+ # 16 bytes uuid
648
+ # +4 bytes 0
649
+ # +9 bytes "manifest\0"
650
+ # +8 bytes absolute(!!!) offset to C2PA uuid "merkle\0" box
651
+ # =37 bytes total
652
+ Start => 37,
653
+ },
654
+ },
655
+ { #https://c2pa.org/specifications/ (NC)
656
+ Name => 'CBOR',
657
+ Condition => '$$valPt=~/^\xd8\xfe\xc3\xd6\x1b\x0e\x48\x3c\x92\x97\x58\x28\x87\x7e\xc4\x81.{4}merkle\0/s',
658
+ Deletable => 1, # (NC)
659
+ SubDirectory => {
660
+ TagTable => 'Image::ExifTool::CBOR::Main',
661
+ # 16 bytes uuid
662
+ # +4 bytes 0
663
+ # +7 bytes "merkle\0"
664
+ # =27 bytes total
665
+ Start => 27,
666
+ },
667
+ },
641
668
  {
642
669
  Name => 'SensorData',
643
670
  Condition => '$$valPt=~/^\xef\xe1\x58\x9a\xbb\x77\x49\xef\x80\x95\x27\x75\x9e\xb1\xdc\x6f/',
@@ -2311,16 +2338,33 @@ my %isImageData = ( av01 => 1, avc1 => 1, hvc1 => 1, lhv1 => 1, hvt1 => 1 );
2311
2338
  # RDT9 - only 16-byte header?
2312
2339
  # the boxes below all have a similar header (little-endian):
2313
2340
  # 0 int32u - number of records
2314
- # 4 ? - "1e 00"
2341
+ # 4 int32u - sample rate (Hz)
2315
2342
  # 6 int16u - record length in bytes
2316
- # 8 ? - "23 01 00 00 00 00 00 00"
2317
- # 16 - start of records (each record ends in an int64u timestamp "ts" in ns)
2318
- # RDTA - float[4],ts: "-0.31289672 -0.2245330 11.303817 0 775.780"
2319
- # RDTB - float[4],ts: "-0.04841613 -0.2166595 0.0724792 0 775.780"
2320
- # RDTC - float[4],ts: "27.60925 -27.10037 -13.27285 0 775.829"
2343
+ # 8 int16u - 0x0123 = little-endian, 0x3210 = big endian
2344
+ # 10 int16u[3] - all zeros
2345
+ # 16 - start of records (each record ends in an int64u timestamp "ts" in ns)
2346
+ RDTA => {
2347
+ Name => 'RicohRDTA',
2348
+ SubDirectory => { TagTable => 'Image::ExifTool::Ricoh::RDTA' },
2349
+ },
2350
+ RDTB => {
2351
+ Name => 'RicohRDTB',
2352
+ SubDirectory => { TagTable => 'Image::ExifTool::Ricoh::RDTB' },
2353
+ },
2354
+ RDTC => {
2355
+ Name => 'RicohRDTC',
2356
+ SubDirectory => { TagTable => 'Image::ExifTool::Ricoh::RDTC' },
2357
+ },
2321
2358
  # RDTD - int16s[3],ts: "353 -914 16354 0 775.829"
2322
- # RDTG - ts: "775.825"
2359
+ RDTG => {
2360
+ Name => 'RicohRDTG',
2361
+ SubDirectory => { TagTable => 'Image::ExifTool::Ricoh::RDTG' },
2362
+ },
2323
2363
  # RDTI - float[4],ts: "0.00165951 0.005770059 0.06838259 0.1744695 775.862"
2364
+ RDTL => {
2365
+ Name => 'RicohRDTL',
2366
+ SubDirectory => { TagTable => 'Image::ExifTool::Ricoh::RDTL' },
2367
+ },
2324
2368
  # ---- Samsung ----
2325
2369
  vndr => 'Vendor', #PH (Samsung PL70)
2326
2370
  SDLN => 'PlayMode', #PH (NC, Samsung ST80 "SEQ_PLAY")
@@ -2344,7 +2388,7 @@ my %isImageData = ( av01 => 1, avc1 => 1, hvc1 => 1, lhv1 => 1, hvt1 => 1 );
2344
2388
  # edli - 52 bytes all zero (Samsung WB30F)
2345
2389
  # @etc - 4 bytes all zero (Samsung WB30F)
2346
2390
  # saut - 4 bytes all zero (Samsung SM-N900T)
2347
- # smrd - string "TRUEBLUE" (Samsung SM-C101)
2391
+ # smrd - string "TRUEBLUE" (Samsung SM-C101, etc)
2348
2392
  # ---- TomTom Bandit Action Cam ----
2349
2393
  TTMD => {
2350
2394
  Name => 'TomTomMetaData',
@@ -2364,7 +2408,7 @@ my %isImageData = ( av01 => 1, avc1 => 1, hvc1 => 1, lhv1 => 1, hvt1 => 1 );
2364
2408
  # opax - 164 bytes unknown (center and affine arrays? ref 26)
2365
2409
  # opai - 32 bytes (maybe contains a serial number starting at byte 16? - PH) (rgb gains, degamma, gamma? ref 26)
2366
2410
  # intv - 16 bytes all zero
2367
- # ---- Xaiomi ----
2411
+ # ---- Xiaomi ----
2368
2412
  mcvr => {
2369
2413
  Name => 'PreviewImage',
2370
2414
  Groups => { 2 => 'Preview' },
@@ -6576,11 +6620,13 @@ my %isImageData = ( av01 => 1, avc1 => 1, hvc1 => 1, lhv1 => 1, hvt1 => 1 );
6576
6620
  'collection.user' => 'UserCollection', #22
6577
6621
  'Encoded_With' => 'EncodedWith',
6578
6622
  'content.identifier' => 'ContentIdentifier', #forum14874
6623
+ 'encoder' => { }, # forum15418 (written by ffmpeg)
6579
6624
  #
6580
6625
  # the following tags aren't in the com.apple.quicktime namespace:
6581
6626
  #
6582
6627
  'com.apple.photos.captureMode' => 'CaptureMode',
6583
6628
  'com.android.version' => 'AndroidVersion',
6629
+ 'com.android.capture.fps' => 'AndroidCaptureFPS',
6584
6630
  #
6585
6631
  # also seen
6586
6632
  #
@@ -9504,7 +9550,7 @@ sub ProcessMOV($$;$)
9504
9550
  # stop processing at mdat/idat if -fast2 is used
9505
9551
  last if $fast > 1 and ($tag eq 'mdat' or ($tag eq 'idat' and $$et{FileType} ne 'HEIC'));
9506
9552
  # load values only if associated with a tag (or verbose) and not too big
9507
- if ($size > 0x2000000) { # start to get worried above 32 MB
9553
+ if ($size > 0x2000000) { # start to get worried above 32 MiB
9508
9554
  # check for RIFF trailer (written by Auto-Vox dashcam)
9509
9555
  if ($buff =~ /^(gpsa|gps0|gsen|gsea)...\0/s) { # (yet seen only gpsa as first record)
9510
9556
  $et->VPrint(0, "Found RIFF trailer");
@@ -9521,9 +9567,9 @@ sub ProcessMOV($$;$)
9521
9567
  if ($tagInfo and not $$tagInfo{Unknown} and not $eeTag) {
9522
9568
  my $t = PrintableTagID($tag,2);
9523
9569
  if ($size > 0x8000000) {
9524
- $et->Warn("Skipping '${t}' atom > 128 MB", 1);
9570
+ $et->Warn("Skipping '${t}' atom > 128 MiB", 1);
9525
9571
  } else {
9526
- $et->Warn("Skipping '${t}' atom > 32 MB", 2) or $ignore = 0;
9572
+ $et->Warn("Skipping '${t}' atom > 32 MiB", 2) or $ignore = 0;
9527
9573
  }
9528
9574
  }
9529
9575
  }
@@ -83,7 +83,8 @@ my %processByMetaFormat = (
83
83
 
84
84
  # data lengths for each INSV/INSP record type
85
85
  my %insvDataLen = (
86
- 0x200 => 0, # PreivewImage (any size) (a duplicate of PreviewImage in APP2 of INSP files)
86
+ 0x000 => 0, # directory table (any size)
87
+ 0x200 => 0, # PreviewImage (any size) (a duplicate of PreviewImage in APP2 of INSP files)
87
88
  0x300 => 0, # accelerometer (could be either 20 or 56 bytes)
88
89
  0x400 => 16, # exposure (ref 6)
89
90
  0x600 => 8, # timestamps (ref 6)
@@ -91,6 +92,8 @@ my %insvDataLen = (
91
92
  # 0x900 => 48, # ? (Insta360 X3)
92
93
  # 0xa00 => 5?, # ? (Insta360 ONE RS)
93
94
  # 0xb00 => 10, # ? (Insta360 X3)
95
+ # 0xd00 => 10, # ? (Insta360 Ace Pro)
96
+ # 0x1200 ? # ? (Insta360 Ace Pro)
94
97
  );
95
98
 
96
99
  # limit the default amount of data we read for some record types
@@ -106,7 +109,7 @@ my %insvLimit = (
106
109
  The tags below are extracted from timed metadata in QuickTime and other
107
110
  formats of video files when the ExtractEmbedded option is used. Although
108
111
  most of these tags are combined into the single table below, ExifTool
109
- currently reads 66 different formats of timed GPS metadata from video files.
112
+ currently reads 67 different formats of timed GPS metadata from video files.
110
113
  },
111
114
  VARS => { NO_ID => 1 },
112
115
  GPSLatitude => { PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', RawConv => '$$self{FoundGPSLatitude} = 1; $val' },
@@ -2043,7 +2046,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
2043
2046
  return 1;
2044
2047
 
2045
2048
  } elsif ($$dataPt =~ /^.{28}A.{11}([NS]).{15}([EW])/s) {
2046
-
2049
+
2047
2050
  $debug and $et->FoundTag(GPSType => '2G');
2048
2051
  # Vantrue N4 dashcam
2049
2052
  # 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 03 00 00 [..@.freeGPS ....]
@@ -2778,7 +2781,7 @@ sub ProcessInsta360($;$)
2778
2781
  my ($et, $dirInfo) = @_;
2779
2782
  my $raf = $$et{RAF};
2780
2783
  my $offset = $dirInfo ? $$dirInfo{Offset} || 0 : 0;
2781
- my $buff;
2784
+ my ($buff, $dirTable, $dirTablePos);
2782
2785
 
2783
2786
  return 0 unless $raf->Seek(-78-$offset, 2) and $raf->Read($buff, 78) == 78 and
2784
2787
  substr($buff,-32) eq "8db42d694ccc418790edff439fe026bf"; # check magic number
@@ -2868,7 +2871,19 @@ sub ProcessInsta360($;$)
2868
2871
  if ($len % $dlen and $id != 0x700) { # (have seen one 0x700 record which was expected format but not multiple of 53 bytes)
2869
2872
  $et->Warn(sprintf('Unexpected Insta360 record 0x%x length',$id));
2870
2873
  } elsif ($id == 0x200) {
2871
- $et->FoundTag(PreviewImage => $buff);
2874
+ # there are 4 types of record 0x200
2875
+ # 1. JPEG preview (starts with ff d8 ff e1)
2876
+ # 2. TIFF preview (starts with 01 00 00 00, then record length)
2877
+ # 3. Unknown 1 (starts with 00 00 00 01)
2878
+ # 4. Unknown 2 (starts with 00 00 01 34)
2879
+ if ($buff =~ /^\xff\xd8\xff/) {
2880
+ $et->FoundTag(PreviewImage => $buff);
2881
+ } elsif ($buff =~ /^\x01\0\0\0(.{4})\x01/s and unpack('V',$1) == $dlen) {
2882
+ my ($w, $h) = unpack('x16V2',$buff);
2883
+ # build the TIFF image (could the 1 at byte 9 be the SamplesPerPixel?)
2884
+ my $hdr = Image::ExifTool::MakeTiffHeader($w, $h, 1, 8);
2885
+ $et->FoundTag(PreviewTIFF => $hdr . substr($buff, 40));
2886
+ }
2872
2887
  } elsif ($id == 0x300) {
2873
2888
  for ($p=0; $p<$len; $p+=$dlen) {
2874
2889
  $$et{DOC_NUM} = ++$$et{DOC_COUNT};
@@ -2899,7 +2914,7 @@ sub ProcessInsta360($;$)
2899
2914
  my $tmp = substr($buff, $p, $dlen);
2900
2915
  my @a = unpack('VVvaa8aa8aa8a8a8', $tmp);
2901
2916
  unless (($a[5] eq 'N' or $a[5] eq 'S') and # (quick validation)
2902
- ($a[7] eq 'E' or $a[7] eq 'W' or
2917
+ ($a[7] eq 'E' or $a[7] eq 'W' or
2903
2918
  # (odd, but I've seen "O" instead of "W". Perhaps
2904
2919
  # when the language is french? ie. "Ouest"?)
2905
2920
  $a[7] eq 'O'))
@@ -2913,13 +2928,15 @@ sub ProcessInsta360($;$)
2913
2928
  $a[$_] = GetDouble(\$a[$_], 0) foreach 4,6,8,9,10;
2914
2929
  $a[4] = -abs($a[4]) if $a[5] eq 'S'; # (abs just in case it was already signed)
2915
2930
  $a[6] = -abs($a[6]) if $a[7] ne 'E';
2916
- $et->HandleTag($tagTbl, GPSDateTime => Image::ExifTool::ConvertUnixTime($a[0]) . 'Z');
2931
+ my $ms = '';
2932
+ $a[2] and ($ms = sprintf('.%.3d', $a[2])) =~ s/0+$//;
2933
+ $et->HandleTag($tagTbl, GPSDateTime => Image::ExifTool::ConvertUnixTime($a[0]) . $ms . 'Z');
2917
2934
  $et->HandleTag($tagTbl, GPSLatitude => $a[4]);
2918
2935
  $et->HandleTag($tagTbl, GPSLongitude => $a[6]);
2919
2936
  $et->HandleTag($tagTbl, GPSSpeed => $a[8] * $mpsToKph);
2920
2937
  $et->HandleTag($tagTbl, GPSTrack => $a[9]);
2921
2938
  $et->HandleTag($tagTbl, GPSAltitude => $a[10]);
2922
- $et->HandleTag($tagTbl, Unknown02 => "@a[1,2]") if $unknown; # millisecond counter (https://exiftool.org/forum/index.php?topic=9884.msg65143#msg65143)
2939
+ $et->HandleTag($tagTbl, Unknown02 => $a[1]) if $unknown;
2923
2940
  }
2924
2941
  }
2925
2942
  } elsif ($id == 0x101) {
@@ -2932,10 +2949,41 @@ sub ProcessInsta360($;$)
2932
2949
  $et->HandleTag($tagTablePtr, $t, $val);
2933
2950
  $p += 2 + $n;
2934
2951
  }
2952
+ } elsif ($id == 0x0) {
2953
+ last if not $len;
2954
+ # example directory table for record locations from Insta360AcePro MP4 video:
2955
+ # vv vv - record ID
2956
+ # vv vv vv vv - record size
2957
+ # vv vv vv vv - offset from start of footer
2958
+ # 00 00 00 00 00 00 00 00 00 00
2959
+ # 01 01 82 04 00 00 1b 45 62 00
2960
+ # 02 00 28 46 05 00 ed fe 5c 00
2961
+ # 03 00 40 aa 24 00 ed fe 34 00
2962
+ # 04 00 00 c1 01 00 ed fe 30 00
2963
+ # [...]
2964
+ unless ($dirTable) {
2965
+ $dirTable = $buff;
2966
+ $dirTablePos = 0;
2967
+ }
2935
2968
  }
2936
- ($epos -= 6) + $trailerLen < 0 and last; # step back to previous record
2937
- $raf->Seek($epos, 2) or last;
2938
- $raf->Read($buff, 6) == 6 or last;
2969
+ # step through directory table instead of sequential scanning if possible
2970
+ if ($dirTable) {
2971
+ undef $epos;
2972
+ for (;;) {
2973
+ last if $dirTablePos + 10 > length($dirTable);
2974
+ my ($id, $siz, $off) = unpack("x${dirTablePos}vVV", $dirTable);
2975
+ $dirTablePos += 10;
2976
+ if ($id and $siz and $off + $siz < $trailerLen) {
2977
+ $epos = $off + $siz - $trailerLen;
2978
+ last;
2979
+ }
2980
+ }
2981
+ last unless defined $epos;
2982
+ } else {
2983
+ ($epos -= 6) + $trailerLen < 0 and last; # step back to previous record
2984
+ }
2985
+ $raf->Seek($epos, 2) or last; # seek to start of next footer
2986
+ $raf->Read($buff, 6) == 6 or last; # read footer
2939
2987
  }
2940
2988
  $$et{DOC_NUM} = 0;
2941
2989
  SetByteOrder('MM');
@@ -616,9 +616,9 @@ numerical, and generated automatically otherwise.
616
616
  arguments: the value, a flag which is set for the inverse
617
617
  conversion, and a reference to the PrintConv hash, and returns
618
618
  the converted value or undef on error -- it may call warn() to
619
- return an error message. The lookup hash may also contain a
619
+ return an error message. The lookup hash may also contain a
620
620
  'Notes' entry which is used for documentation if the
621
- SeparateTable flag is set). In an expression, $self is a
621
+ SeparateTable flag is set). In an expression, $self is a
622
622
  reference to the current ExifTool object, $val is the Raw
623
623
  value, and $tag is the tag key. The subroutine takes 2
624
624
  arguments: the Raw value and a reference to the current
@@ -894,6 +894,11 @@ numerical, and generated automatically otherwise.
894
894
  writing this tag. Only needed if tag can be written to
895
895
  groups other than the normal groups for this tag (very rare).
896
896
 
897
+ Deletable : [Writable SubDirectory's only] Overrides internal test for
898
+ metadata types with permanent directories (currently QuickTime
899
+ and Jpeg2000), allowing the tag containing these directories
900
+ to be deleted
901
+
897
902
  OffsetPair : Used in EXIF table to specify the tagID for the corresponding
898
903
  offset or length tag.
899
904
 
@@ -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.66';
33
+ $VERSION = '1.67';
34
34
 
35
35
  sub ConvertTimecode($);
36
36
  sub ProcessSGLT($$$);
@@ -500,6 +500,11 @@ my %code2charset = (
500
500
  Name => 'OldXMP',
501
501
  Binary => 1,
502
502
  },
503
+ C2PA => { #https://c2pa.org/specifications/
504
+ Name => 'JUMBF',
505
+ Deletable => 1,
506
+ SubDirectory => { TagTable => 'Image::ExifTool::Jpeg2000::Main' },
507
+ },
503
508
  olym => {
504
509
  Name => 'Olym',
505
510
  SubDirectory => { TagTable => 'Image::ExifTool::Olympus::WAV' },
@@ -1069,7 +1074,16 @@ my %code2charset = (
1069
1074
  },
1070
1075
  1 => {
1071
1076
  Name => 'MaxDataRate',
1072
- PrintConv => 'sprintf("%.4g kB/s",$val / 1024)',
1077
+ Notes => q{
1078
+ converted using SI byte prefixes unles the API ByteUnit option is set to
1079
+ "Binary"
1080
+ },
1081
+ PrintConv => q{
1082
+ my ($unit, $div) = $self->Options('ByteUnit') eq 'Binary' ? ('KiB/s',1024) : ('kB/s',1000);
1083
+ my $tmp = $val / $div;
1084
+ $tmp > 9999 and $tmp /= $div, $unit =~ s/^./M/;
1085
+ sprintf('%.4g %s', $tmp, $unit);
1086
+ },
1073
1087
  },
1074
1088
  # 2 => 'PaddingGranularity',
1075
1089
  # 3 => 'Flags',
@@ -1989,7 +2003,7 @@ sub ProcessRIFF($$)
1989
2003
  {
1990
2004
  my ($et, $dirInfo) = @_;
1991
2005
  my $raf = $$dirInfo{RAF};
1992
- my ($buff, $buf2, $type, $mime, $err, $rf64);
2006
+ my ($buff, $buf2, $type, $mime, $err, $rf64, $moviEnd);
1993
2007
  my $verbose = $et->Options('Verbose');
1994
2008
  my $unknown = $et->Options('Unknown');
1995
2009
  my $validate = $et->Options('Validate');
@@ -2023,8 +2037,34 @@ sub ProcessRIFF($$)
2023
2037
  # Read chunks in RIFF image
2024
2038
  #
2025
2039
  for (;;) {
2040
+ if ($err) {
2041
+ last unless $moviEnd;
2042
+ # we arrived here because there was a problem parsing the movie data
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;
2049
+ }
2050
+ if ($validate) {
2051
+ # (must actually try to read something after seeking to detect error)
2052
+ $raf->Seek($moviEnd-1, 0) and $raf->Read($buff, 1) == 1 or last;
2053
+ } else {
2054
+ $raf->Seek($moviEnd, 0) or last;
2055
+ }
2056
+ $pos = $moviEnd;
2057
+ $et->Warn('Possibly corrupt LIST_movi data');
2058
+ undef $err;
2059
+ undef $moviEnd;
2060
+ }
2061
+ if ($moviEnd) {
2062
+ $pos > $moviEnd and $err = 1, next; # error if we parsed past the end of the movie data
2063
+ undef $moviEnd if $pos == $moviEnd; # parsed all movie data?
2064
+ }
2026
2065
  my $num = $raf->Read($buff, 8);
2027
2066
  if ($num < 8) {
2067
+ $moviEnd and $err = 1, next;
2028
2068
  $err = 1 if $num;
2029
2069
  $et->Warn('Incorrect RIFF chunk size' . " $pos vs. $riffEnd") if $validate and $pos != $riffEnd;
2030
2070
  last;
@@ -2035,7 +2075,7 @@ sub ProcessRIFF($$)
2035
2075
  $et->OverrideFileType('Extended WEBP',undef,'webp') if $tag eq 'VP8X' and $type eq 'WEBP';
2036
2076
  # special case: construct new tag name from specific LIST type
2037
2077
  if ($tag eq 'LIST') {
2038
- $raf->Read($buff, 4) == 4 or $err=1, last;
2078
+ $raf->Read($buff, 4) == 4 or $err=1, next;
2039
2079
  $pos += 4;
2040
2080
  $tag .= "_$buff";
2041
2081
  $len -= 4; # already read 4 bytes (the LIST type)
@@ -2044,6 +2084,7 @@ sub ProcessRIFF($$)
2044
2084
  }
2045
2085
  $et->VPrint(0, "RIFF '${tag}' chunk ($len bytes of data):\n");
2046
2086
  if ($len <= 0) {
2087
+ $moviEnd and $err = 1, next;
2047
2088
  if ($len < 0) {
2048
2089
  $et->Warn('Invalid chunk length');
2049
2090
  } elsif ($tag eq "\0\0\0\0") {
@@ -2074,7 +2115,7 @@ sub ProcessRIFF($$)
2074
2115
  my $tagInfo = $$tagTbl{$tag};
2075
2116
  # (in LIST_movi chunk: ##db = uncompressed DIB, ##dc = compressed DIB, ##wb = audio data)
2076
2117
  if ($tagInfo or (($verbose or $unknown) and $tag !~ /^(data|idx1|LIST_movi|RIFF|\d{2}(db|dc|wb))$/)) {
2077
- $raf->Read($buff, $len2) == $len2 or $err=1, last;
2118
+ $raf->Read($buff, $len2) == $len2 or $err=1, next;
2078
2119
  if ($hash and $isImageData{$tag}) {
2079
2120
  $hash->add($buff);
2080
2121
  $et->VPrint(0, "$$et{INDENT}(ImageDataHash: '${tag}' chunk, $len2 bytes)\n");
@@ -2100,7 +2141,7 @@ sub ProcessRIFF($$)
2100
2141
  $et->Warn('Incorrect RIFF chunk size') if $validate and $pos - 8 != $riffEnd;
2101
2142
  $riffEnd += $len2 + 8;
2102
2143
  # don't read into RIFF chunk (eg. concatenated video file)
2103
- $raf->Read($buff, 4) == 4 or $err=1, last; # (skip RIFF type word)
2144
+ $raf->Read($buff, 4) == 4 or $err=1, next; # (skip RIFF type word)
2104
2145
  $pos += 4;
2105
2146
  # extract information from remaining file as an embedded file
2106
2147
  $$et{DOC_NUM} = ++$$et{DOC_COUNT};
@@ -2113,18 +2154,21 @@ sub ProcessRIFF($$)
2113
2154
  $et->ImageDataHash($raf, $len2, "'${tag}' chunk");
2114
2155
  }
2115
2156
  if ($tag eq 'LIST_movi' and $ee) {
2116
- $raf->Seek($rewind, 0) or $err = 1, last if $rewind;
2157
+ $raf->Seek($rewind, 0) or $err = 1, next if $rewind;
2158
+ # save end-of-movie offset so we can seek there if we get errors parsing the movie data
2159
+ $moviEnd = $raf->Tell() + $len2;
2117
2160
  next; # parse into movi chunk
2118
2161
  } elsif (not $rewind) {
2119
2162
  if ($len > 0x7fffffff and not $et->Options('LargeFileSupport')) {
2163
+ $tag =~ s/([\0-\x1f\x7f-\xff])/sprintf('\\x%.2x',ord $1)/eg;
2120
2164
  $et->Warn("Stopped parsing at large $tag chunk (LargeFileSupport not set)");
2121
2165
  last;
2122
2166
  }
2123
2167
  if ($validate and $len2) {
2124
2168
  # (must actually try to read something after seeking to detect error)
2125
- $raf->Seek($len2-1, 1) and $raf->Read($buff, 1) == 1 or $err = 1, last;
2169
+ $raf->Seek($len2-1, 1) and $raf->Read($buff, 1) == 1 or $err = 1, next;
2126
2170
  } else {
2127
- $raf->Seek($len2, 1) or $err=1, last;
2171
+ $raf->Seek($len2, 1) or $err=1, next;
2128
2172
  }
2129
2173
  }
2130
2174
  }