exiftool_vendored 11.96.0 → 12.08.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of exiftool_vendored might be problematic. Click here for more details.

Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +172 -2
  3. data/bin/MANIFEST +8 -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 +148 -69
  8. data/bin/lib/Image/ExifTool.pm +159 -110
  9. data/bin/lib/Image/ExifTool.pod +114 -87
  10. data/bin/lib/Image/ExifTool/AIFF.pm +2 -2
  11. data/bin/lib/Image/ExifTool/APE.pm +2 -2
  12. data/bin/lib/Image/ExifTool/BuildTagLookup.pm +13 -7
  13. data/bin/lib/Image/ExifTool/Canon.pm +37 -11
  14. data/bin/lib/Image/ExifTool/CanonCustom.pm +82 -16
  15. data/bin/lib/Image/ExifTool/DPX.pm +56 -2
  16. data/bin/lib/Image/ExifTool/DarwinCore.pm +20 -3
  17. data/bin/lib/Image/ExifTool/EXE.pm +8 -5
  18. data/bin/lib/Image/ExifTool/Exif.pm +15 -6
  19. data/bin/lib/Image/ExifTool/Font.pm +9 -2
  20. data/bin/lib/Image/ExifTool/GIF.pm +5 -0
  21. data/bin/lib/Image/ExifTool/GeoTiff.pm +2 -0
  22. data/bin/lib/Image/ExifTool/Geotag.pm +2 -2
  23. data/bin/lib/Image/ExifTool/GoPro.pm +56 -22
  24. data/bin/lib/Image/ExifTool/H264.pm +1 -1
  25. data/bin/lib/Image/ExifTool/HtmlDump.pm +2 -2
  26. data/bin/lib/Image/ExifTool/ID3.pm +91 -12
  27. data/bin/lib/Image/ExifTool/IPTC.pm +1 -0
  28. data/bin/lib/Image/ExifTool/Lang/de.pm +3 -1
  29. data/bin/lib/Image/ExifTool/Lang/es.pm +1 -1
  30. data/bin/lib/Image/ExifTool/M2TS.pm +44 -24
  31. data/bin/lib/Image/ExifTool/MacOS.pm +152 -38
  32. data/bin/lib/Image/ExifTool/Minolta.pm +6 -2
  33. data/bin/lib/Image/ExifTool/MinoltaRaw.pm +11 -10
  34. data/bin/lib/Image/ExifTool/Nikon.pm +162 -18
  35. data/bin/lib/Image/ExifTool/Olympus.pm +39 -17
  36. data/bin/lib/Image/ExifTool/PNG.pm +14 -3
  37. data/bin/lib/Image/ExifTool/PPM.pm +5 -5
  38. data/bin/lib/Image/ExifTool/Panasonic.pm +148 -14
  39. data/bin/lib/Image/ExifTool/PanasonicRaw.pm +33 -0
  40. data/bin/lib/Image/ExifTool/Parrot.pm +2 -1
  41. data/bin/lib/Image/ExifTool/Pentax.pm +3 -1
  42. data/bin/lib/Image/ExifTool/Photoshop.pm +2 -1
  43. data/bin/lib/Image/ExifTool/QuickTime.pm +269 -29
  44. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +463 -75
  45. data/bin/lib/Image/ExifTool/README +21 -20
  46. data/bin/lib/Image/ExifTool/RIFF.pm +15 -3
  47. data/bin/lib/Image/ExifTool/RSRC.pm +17 -11
  48. data/bin/lib/Image/ExifTool/RTF.pm +12 -7
  49. data/bin/lib/Image/ExifTool/Ricoh.pm +19 -1
  50. data/bin/lib/Image/ExifTool/Shift.pl +1 -0
  51. data/bin/lib/Image/ExifTool/SigmaRaw.pm +40 -33
  52. data/bin/lib/Image/ExifTool/Sony.pm +425 -34
  53. data/bin/lib/Image/ExifTool/TagLookup.pm +1961 -1874
  54. data/bin/lib/Image/ExifTool/TagNames.pod +394 -86
  55. data/bin/lib/Image/ExifTool/Validate.pm +4 -4
  56. data/bin/lib/Image/ExifTool/WriteExif.pl +3 -2
  57. data/bin/lib/Image/ExifTool/WriteQuickTime.pl +23 -15
  58. data/bin/lib/Image/ExifTool/Writer.pl +44 -21
  59. data/bin/lib/Image/ExifTool/XMP.pm +42 -5
  60. data/bin/lib/Image/ExifTool/XMPStruct.pl +3 -1
  61. data/bin/lib/Image/ExifTool/ZISRAW.pm +123 -0
  62. data/bin/perl-Image-ExifTool.spec +42 -41
  63. data/lib/exiftool_vendored/version.rb +1 -1
  64. metadata +8 -7
@@ -13,7 +13,7 @@ package Image::ExifTool::Parrot;
13
13
  use strict;
14
14
  use vars qw($VERSION);
15
15
 
16
- $VERSION = '1.00';
16
+ $VERSION = '1.01';
17
17
 
18
18
  sub Process_mett($$$);
19
19
 
@@ -703,6 +703,7 @@ sub Process_mett($$$)
703
703
  $et->HandleTag($tagTbl, $id, undef,
704
704
  DataPt => $dataPt,
705
705
  DataPos => $dataPos,
706
+ Base => $$dirInfo{Base},
706
707
  Start => $pos,
707
708
  Size => $size,
708
709
  );
@@ -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.31';
61
+ $VERSION = '3.34';
62
62
 
63
63
  sub CryptShutterCount($$);
64
64
  sub PrintFilter($$$);
@@ -338,6 +338,7 @@ sub DecodeAFPoints($$$$;$);
338
338
  '8 63' => 'HD PENTAX-D FA 15-30mm F2.8 ED SDM WR', #PH
339
339
  '8 64' => 'HD PENTAX-D FA* 50mm F1.4 SDM AW', #27
340
340
  '8 65' => 'HD PENTAX-D FA 70-210mm F4 ED SDM WR', #PH
341
+ '8 66' => 'HD PENTAX-D FA 85mm F1.4 ED SDM AW', #James O'Neill
341
342
  '8 196' => 'HD PENTAX-DA* 11-18mm F2.8 ED DC AW', #29
342
343
  '8 197' => 'HD PENTAX-DA 55-300mm F4.5-6.3 ED PLM WR RE', #29
343
344
  '8 198' => 'smc PENTAX-DA L 18-50mm F4-5.6 DC WR RE', #29
@@ -546,6 +547,7 @@ my %pentaxModelID = (
546
547
  0x13222 => 'K-70', #29 (Ricoh)
547
548
  0x1322c => 'KP', #29 (Ricoh)
548
549
  0x13240 => 'K-1 Mark II', # (Ricoh)
550
+ 0x13290 => 'WG-70', # (Ricoh)
549
551
  );
550
552
 
551
553
  # Pentax city codes - (PH, Optio WP)
@@ -28,7 +28,7 @@ use strict;
28
28
  use vars qw($VERSION $AUTOLOAD $iptcDigestInfo);
29
29
  use Image::ExifTool qw(:DataAccess :Utils);
30
30
 
31
- $VERSION = '1.64';
31
+ $VERSION = '1.65';
32
32
 
33
33
  sub ProcessPhotoshop($$$);
34
34
  sub WritePhotoshop($$$);
@@ -982,6 +982,7 @@ sub ProcessPhotoshop($$$)
982
982
  DataPos => $$dirInfo{DataPos},
983
983
  Size => $size,
984
984
  Start => $pos,
985
+ Base => $$dirInfo{Base},
985
986
  Parent => $$dirInfo{DirName},
986
987
  );
987
988
  $size += 1 if $size & 0x01; # size is padded to an even # bytes
@@ -36,6 +36,7 @@
36
36
  # 24) https://github.com/sergiomb2/libmp4v2/wiki/iTunesMetadata
37
37
  # 25) https://cconcolato.github.io/mp4ra/atoms.html
38
38
  # 26) https://github.com/SamsungVR/android_upload_sdk/blob/master/SDKLib/src/main/java/com/samsung/msca/samsungvr/sdk/UserVideo.java
39
+ # 27) https://exiftool.org/forum/index.php?topic=11517.0
39
40
  #------------------------------------------------------------------------------
40
41
 
41
42
  package Image::ExifTool::QuickTime;
@@ -46,7 +47,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
46
47
  use Image::ExifTool::Exif;
47
48
  use Image::ExifTool::GPS;
48
49
 
49
- $VERSION = '2.47';
50
+ $VERSION = '2.53';
50
51
 
51
52
  sub ProcessMOV($$;$);
52
53
  sub ProcessKeys($$$);
@@ -105,7 +106,9 @@ my %mimeLookup = (
105
106
  MQV => 'video/quicktime',
106
107
  HEIC => 'image/heic',
107
108
  HEVC => 'image/heic-sequence',
109
+ HEICS=> 'image/heic-sequence',
108
110
  HEIF => 'image/heif',
111
+ HEIFS=> 'image/heif-sequence',
109
112
  AVIF => 'image/avif', #PH (NC)
110
113
  CRX => 'video/x-canon-crx', # (will get overridden)
111
114
  );
@@ -418,7 +421,8 @@ my %eeBox = (
418
421
  sbtl => { %eeStd },
419
422
  data => { %eeStd },
420
423
  camm => { %eeStd }, # (Insta360)
421
- '' => { 'gps ' => 'moov' }, # (no handler -- in top level 'moov' box)
424
+ ctbx => { %eeStd }, # (GM cars)
425
+ '' => { 'gps ' => 'moov', 'GPS ' => 'main' }, # (no handler -- in top level 'moov' box, and main)
422
426
  );
423
427
 
424
428
  # QuickTime atoms
@@ -555,6 +559,20 @@ my %eeBox = (
555
559
  Start => 16,
556
560
  },
557
561
  },
562
+ { # (ref https://github.com/JamesHeinrich/getID3/blob/master/getid3/module.audio-video.quicktime.php)
563
+ Name => 'SensorData', # sensor data for the 360Fly
564
+ Condition => '$$valPt=~/^\xef\xe1\x58\x9a\xbb\x77\x49\xef\x80\x95\x27\x75\x9e\xb1\xdc\x6f/ and $$self{OPTIONS}{ExtractEmbedded}',
565
+ SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Tags360Fly' },
566
+ },
567
+ {
568
+ Name => 'SensorData',
569
+ Condition => '$$valPt=~/^\xef\xe1\x58\x9a\xbb\x77\x49\xef\x80\x95\x27\x75\x9e\xb1\xdc\x6f/',
570
+ Notes => 'raw 360Fly sensor data without ExtractEmbedded option',
571
+ RawConv => q{
572
+ $self->WarnOnce('Use the ExtractEmbedded option to decode timed SensorData',3);
573
+ return \$val;
574
+ },
575
+ },
558
576
  { #PH (Canon CR3)
559
577
  Name => 'PreviewImage',
560
578
  Condition => '$$valPt=~/^\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16/',
@@ -589,6 +607,11 @@ my %eeBox = (
589
607
  Groups => { 2 => 'Preview' },
590
608
  Binary => 1,
591
609
  },
610
+ 'thm ' => { #PH (70mai A800)
611
+ Name => 'ThumbnailImage',
612
+ Groups => { 2 => 'Preview' },
613
+ Binary => 1,
614
+ },
592
615
  ardt => { #PH
593
616
  Name => 'ARDroneFile',
594
617
  ValueConv => 'length($val) > 4 ? substr($val,4) : $val', # remove length
@@ -667,6 +690,11 @@ my %eeBox = (
667
690
  },
668
691
  # gpsa - seen hex "01 20 00 00" (DuDuBell M1, VSYS M6L)
669
692
  # gsea - 20 bytes hex "05 00's..." (DuDuBell M1) "05 08 02 01 ..." (VSYS M6L)
693
+ 'GPS ' => { # GPS data written by 70mai dashcam (parsed in QuickTimeStream.pl)
694
+ Name => 'GPSDataList2',
695
+ Unknown => 1,
696
+ Binary => 1,
697
+ },
670
698
  );
671
699
 
672
700
  # MPEG-4 'ftyp' atom
@@ -962,7 +990,7 @@ my %eeBox = (
962
990
  %Image::ExifTool::QuickTime::CleanAperture = (
963
991
  PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
964
992
  GROUPS => { 2 => 'Video' },
965
- FORMAT => 'rational64u',
993
+ FORMAT => 'rational64s',
966
994
  0 => 'CleanApertureWidth',
967
995
  1 => 'CleanApertureHeight',
968
996
  2 => 'CleanApertureOffsetX',
@@ -1307,6 +1335,7 @@ my %eeBox = (
1307
1335
  Format => 'fixed32s[9]',
1308
1336
  Notes => 'writable for the video track via the Composite Rotation tag',
1309
1337
  Writable => 1,
1338
+ Protected => 1,
1310
1339
  Permanent => 1,
1311
1340
  # only set rotation if image size is non-zero
1312
1341
  RawConvInv => \&GetMatrixStructure,
@@ -1371,8 +1400,8 @@ my %eeBox = (
1371
1400
  },
1372
1401
  ValueConvInv => q{
1373
1402
  require Image::ExifTool::XMP;
1374
- $val = Image::ExifTool::XMP::FormatXMPDate($val);
1375
- $val =~ s/([-+]\d{2}):(\d{2})$/$1$2/; # remove time zone colon
1403
+ my $tmp = Image::ExifTool::XMP::FormatXMPDate($val);
1404
+ ($val = $tmp) =~ s/([-+]\d{2}):(\d{2})$/$1$2/ if defined $tmp; # remove time zone colon
1376
1405
  return $val;
1377
1406
  },
1378
1407
  PrintConv => '$self->ConvertDateTime($val)',
@@ -1628,10 +1657,14 @@ my %eeBox = (
1628
1657
  Avoid => 1,
1629
1658
  Format => 'string', # (necessary to remove the trailing NULL)
1630
1659
  },
1631
- date => { # (NC)
1660
+ date => {
1632
1661
  Name => 'DateTimeOriginal',
1633
1662
  Description => 'Date/Time Original',
1634
1663
  Groups => { 2 => 'Time' },
1664
+ Notes => q{
1665
+ Apple Photos has been reported to show a crazy date/time for some MP4 files
1666
+ containing this tag, but perhaps only if it is missing a time zone
1667
+ }, #forum10690/11125
1635
1668
  Shift => 'Time',
1636
1669
  ValueConv => q{
1637
1670
  require Image::ExifTool::XMP;
@@ -1853,6 +1886,25 @@ my %eeBox = (
1853
1886
  ByteOrder => 'LittleEndian',
1854
1887
  },
1855
1888
  },
1889
+ # ---- Garmin ---- (ref PH)
1890
+ uuid => [{
1891
+ Name => 'GarminSoftware', # (NC)
1892
+ Condition => '$$valPt =~ /^VIRBactioncamera/',
1893
+ RawConv => 'substr($val, 16)',
1894
+ RawConvInv => '"VIRBactioncamera$val"',
1895
+ },{
1896
+ # have seen "28 f3 11 e2 b7 91 4f 6f 94 e2 4f 5d ea cb 3c 01" for RicohThetaZ1 accelerometer RADT data (not yet decoded)
1897
+ Name => 'UUID-Unknown',
1898
+ Writable => 0,
1899
+ %unknownInfo,
1900
+ }],
1901
+ pmcc => {
1902
+ Name => 'GarminSettings',
1903
+ ValueConv => 'substr($val, 4)',
1904
+ ValueConvInv => '"\0\0\0\x01$val"',
1905
+ },
1906
+ # hmtp - "\0\0\0\x01" followed by 408 bytes of zero
1907
+ # vrin - "\0\0\0\x01" followed by 8 bytes of zero
1856
1908
  # ---- GoPro ---- (ref PH)
1857
1909
  GoPr => 'GoProType', # (Hero3+)
1858
1910
  FIRM => { Name => 'FirmwareVersion', Avoid => 1 }, # (Hero4)
@@ -1866,7 +1918,7 @@ my %eeBox = (
1866
1918
  # SETT? 12 bytes (Hero4)
1867
1919
  # MUID? 32 bytes (Hero4, starts with serial number hash)
1868
1920
  # HMMT? 404 bytes (Hero4, all zero)
1869
- # BCID? 26 bytes (Hero5, all zero)
1921
+ # BCID? 26 bytes (Hero5, all zero), 36 bytes GoPro Max
1870
1922
  # GUMI? 16 bytes (Hero5)
1871
1923
  "FOV\0" => 'FieldOfView', #forum8938 (Hero2) seen: "Wide"
1872
1924
  GPMF => {
@@ -2036,6 +2088,63 @@ my %eeBox = (
2036
2088
  ProcessProc => \&Image::ExifTool::ProcessTIFF, # (because ProcessMOV is default)
2037
2089
  },
2038
2090
  },
2091
+ '@mak' => { Name => 'Make', Avoid => 1 },
2092
+ '@mod' => { Name => 'Model', Avoid => 1 },
2093
+ '@swr' => { Name => 'SoftwareVersion', Avoid => 1 },
2094
+ '@day' => {
2095
+ Name => 'ContentCreateDate',
2096
+ Notes => q{
2097
+ some stupid Ricoh programmer used the '@' symbol instead of the copyright
2098
+ symbol in these tag ID's for the Ricoh Theta Z1 and maybe other models
2099
+ },
2100
+ Groups => { 2 => 'Time' },
2101
+ Shift => 'Time',
2102
+ Avoid => 1,
2103
+ # handle values in the form "2010-02-12T13:27:14-0800"
2104
+ ValueConv => q{
2105
+ require Image::ExifTool::XMP;
2106
+ $val = Image::ExifTool::XMP::ConvertXMPDate($val);
2107
+ $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary
2108
+ return $val;
2109
+ },
2110
+ ValueConvInv => q{
2111
+ require Image::ExifTool::XMP;
2112
+ my $tmp = Image::ExifTool::XMP::FormatXMPDate($val);
2113
+ ($val = $tmp) =~ s/([-+]\d{2}):(\d{2})$/$1$2/ if defined $tmp; # remove time zone colon
2114
+ return $val;
2115
+ },
2116
+ PrintConv => '$self->ConvertDateTime($val)',
2117
+ PrintConvInv => '$self->InverseDateTime($val)',
2118
+ },
2119
+ '@xyz' => { #PH (iPhone 3GS)
2120
+ Name => 'GPSCoordinates',
2121
+ Groups => { 2 => 'Location' },
2122
+ Avoid => 1,
2123
+ ValueConv => \&ConvertISO6709,
2124
+ ValueConvInv => \&ConvInvISO6709,
2125
+ PrintConv => \&PrintGPSCoordinates,
2126
+ PrintConvInv => \&PrintInvGPSCoordinates,
2127
+ },
2128
+ # RDT1 - pairs of int32u_BE, starting at byte 8: "458275 471846"
2129
+ # RDT2 - pairs of int32u_BE, starting at byte 8: "472276 468526"
2130
+ # RDT3 - pairs of int32u_BE, starting at byte 8: "876603 482191"
2131
+ # RDT4 - pairs of int32u_BE, starting at byte 8: "1955 484612"
2132
+ # RDT6 - empty
2133
+ # RDT7 - empty
2134
+ # RDT8 - empty
2135
+ # RDT9 - only 16-byte header?
2136
+ # the boxes below all have a similar header (little-endian):
2137
+ # 0 int32u - number of records
2138
+ # 4 ? - "1e 00"
2139
+ # 6 int16u - record length in bytes
2140
+ # 8 ? - "23 01 00 00 00 00 00 00"
2141
+ # 16 - start of records (each record ends in an int64u timestamp in ns)
2142
+ # RDTA - float[4],ts: "-0.31289672 -0.2245330 11.303817 0 775.780"
2143
+ # RDTB - float[4],ts: "-0.04841613 -0.2166595 0.0724792 0 775.780"
2144
+ # RDTC - float[4],ts: "27.60925 -27.10037 -13.27285 0 775.829"
2145
+ # RDTD - int16s[3],ts: "353 -914 16354 0 775.829"
2146
+ # RDTG - ts: "775.825"
2147
+ # RDTI - float[4],ts: "0.00165951 0.005770059 0.06838259 0.1744695 775.862"
2039
2148
  # ---- Samsung ----
2040
2149
  vndr => 'Vendor', #PH (Samsung PL70)
2041
2150
  SDLN => 'PlayMode', #PH (NC, Samsung ST80 "SEQ_PLAY")
@@ -2512,6 +2621,7 @@ my %eeBox = (
2512
2621
  Name => 'Rotation',
2513
2622
  Format => 'int8u',
2514
2623
  Writable => 'int8u',
2624
+ Protected => 1,
2515
2625
  ValueConv => '$val * 90',
2516
2626
  ValueConvInv => 'int($val / 90 + 0.5)',
2517
2627
  },
@@ -2543,6 +2653,7 @@ my %eeBox = (
2543
2653
  Name => 'PixelAspectRatio',
2544
2654
  Format => 'int32u',
2545
2655
  Writable => 'int32u',
2656
+ Protected => 1,
2546
2657
  },
2547
2658
  rloc => {
2548
2659
  Name => 'RelativeLocation',
@@ -2551,7 +2662,7 @@ my %eeBox = (
2551
2662
  },
2552
2663
  clap => {
2553
2664
  Name => 'CleanAperture',
2554
- Format => 'rational64u',
2665
+ Format => 'rational64s',
2555
2666
  Notes => '4 numbers: width, height, left and top',
2556
2667
  },
2557
2668
  hvcC => {
@@ -2889,10 +3000,25 @@ my %eeBox = (
2889
3000
  "\xa9grp" => 'Grouping',
2890
3001
  "\xa9lyr" => 'Lyrics',
2891
3002
  "\xa9nam" => 'Title',
2892
- # "\xa9st3" ? #10
2893
3003
  "\xa9too" => 'Encoder',
2894
3004
  "\xa9trk" => 'Track',
2895
3005
  "\xa9wrt" => 'Composer',
3006
+ #
3007
+ # the following tags written by AtomicParsley 0.9.6
3008
+ # (ref https://exiftool.org/forum/index.php?topic=11455.0)
3009
+ #
3010
+ "\xa9st3" => 'Subtitle',
3011
+ "\xa9con" => 'Conductor',
3012
+ "\xa9sol" => 'Soloist',
3013
+ "\xa9arg" => 'Arranger',
3014
+ "\xa9ope" => 'OriginalArtist',
3015
+ "\xa9dir" => 'Director',
3016
+ "\xa9ard" => 'ArtDirector',
3017
+ "\xa9sne" => 'SoundEngineer',
3018
+ "\xa9prd" => 'Producer',
3019
+ "\xa9xpd" => 'ExecutiveProducer',
3020
+ sdes => 'StoreDescription',
3021
+ #
2896
3022
  '----' => {
2897
3023
  Name => 'iTunesInfo',
2898
3024
  SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::iTunesInfo' },
@@ -2901,18 +3027,29 @@ my %eeBox = (
2901
3027
  covr => { Name => 'CoverArt', Groups => { 2 => 'Preview' } },
2902
3028
  cpil => { #10
2903
3029
  Name => 'Compilation',
2904
- Format => 'int8u', #23
3030
+ Format => 'int8u', #27 (ref 23 contradicts what AtomicParsley actually writes, which is int8s)
3031
+ Writable => 'int8s',
2905
3032
  PrintConv => { 0 => 'No', 1 => 'Yes' },
2906
3033
  },
2907
3034
  disk => {
2908
3035
  Name => 'DiskNumber',
2909
3036
  Format => 'undef', # (necessary to prevent decoding as string!)
2910
- ValueConv => 'length($val) >= 6 ? join(" of ",unpack("x2nn",$val)) : \$val',
2911
- ValueConvInv => 'my @a = split / of /, $val; @a==2 ? pack("n3",0,@a) : undef',
3037
+ ValueConv => q{
3038
+ return \$val unless length($val) >= 6;
3039
+ my @a = unpack 'x2nn', $val;
3040
+ return $a[1] ? join(' of ', @a) : $a[0];
3041
+ },
3042
+ ValueConvInv => q{
3043
+ my @a = $val =~ /\d+/g;
3044
+ return undef if @a == 0 or @a > 2;
3045
+ push @a, 0 if @a == 1;
3046
+ return pack('n3', 0, @a);
3047
+ },
2912
3048
  },
2913
3049
  pgap => { #10
2914
3050
  Name => 'PlayGap',
2915
3051
  Format => 'int8u', #23
3052
+ Writable => 'int8s', #27
2916
3053
  PrintConv => {
2917
3054
  0 => 'Insert Gap',
2918
3055
  1 => 'No Gap',
@@ -2920,13 +3057,26 @@ my %eeBox = (
2920
3057
  },
2921
3058
  tmpo => {
2922
3059
  Name => 'BeatsPerMinute',
2923
- Format => 'int16u', # marked as boolean but really int16u in my sample
3060
+ # marked as boolean but really int16u in my sample
3061
+ # (but written as int16s by iTunes and AtomicParsley, ref forum11506)
3062
+ Format => 'int16u',
3063
+ Writable => 'int16s',
2924
3064
  },
2925
3065
  trkn => {
2926
3066
  Name => 'TrackNumber',
2927
3067
  Format => 'undef', # (necessary to prevent decoding as string!)
2928
- ValueConv => 'length($val) >= 6 ? join(" of ",unpack("x2nn",$val)) : \$val',
2929
- ValueConvInv => 'my @a = split / of /, $val; @a==2 ? pack("n3",0,@a) : undef',
3068
+ ValueConv => q{
3069
+ return \$val unless length($val) >= 6;
3070
+ my @a = unpack 'x2nn', $val;
3071
+ return $a[1] ? join(' of ', @a) : $a[0];
3072
+ },
3073
+ # (see forum11501 for discussion about the format used)
3074
+ ValueConvInv => q{
3075
+ my @a = $val =~ /\d+/g;
3076
+ return undef if @a == 0 or @a > 2;
3077
+ push @a, 0 if @a == 1;
3078
+ return pack('n4', 0, @a, 0);
3079
+ },
2930
3080
  },
2931
3081
  #
2932
3082
  # Note: it is possible that the tags below are not being decoded properly
@@ -2935,6 +3085,7 @@ my %eeBox = (
2935
3085
  akID => { #10
2936
3086
  Name => 'AppleStoreAccountType',
2937
3087
  Format => 'int8u', #24
3088
+ Writable => 'int8s', #27
2938
3089
  PrintConv => {
2939
3090
  0 => 'iTunes',
2940
3091
  1 => 'AOL',
@@ -2945,12 +3096,14 @@ my %eeBox = (
2945
3096
  atID => { #10 (or TV series)
2946
3097
  Name => 'AlbumTitleID',
2947
3098
  Format => 'int32u',
3099
+ Writable => 'int32s', #27
2948
3100
  },
2949
3101
  auth => { Name => 'Author', Groups => { 2 => 'Author' } },
2950
3102
  catg => 'Category', #7
2951
3103
  cnID => { #10
2952
3104
  Name => 'AppleStoreCatalogID',
2953
3105
  Format => 'int32u',
3106
+ Writable => 'int32s', #27
2954
3107
  },
2955
3108
  cprt => { Name => 'Copyright', Groups => { 2 => 'Author' } },
2956
3109
  dscp => { Name => 'Description', Avoid => 1 },
@@ -2958,22 +3111,28 @@ my %eeBox = (
2958
3111
  gnre => { #10
2959
3112
  Name => 'Genre',
2960
3113
  Avoid => 1,
2961
- # (Note: not written as int16u if numerical, although it should be)
3114
+ # (Note: see https://exiftool.org/forum/index.php?topic=11537.0)
3115
+ Format => 'undef',
3116
+ ValueConv => 'unpack("n",$val)',
3117
+ ValueConvInv => '$val =~ /^\d+$/ ? pack("n",$val) : undef',
2962
3118
  PrintConv => q{
2963
3119
  return $val unless $val =~ /^\d+$/;
2964
3120
  require Image::ExifTool::ID3;
2965
3121
  Image::ExifTool::ID3::PrintGenre($val - 1); # note the "- 1"
2966
3122
  },
2967
3123
  PrintConvInv => q{
3124
+ return $val if $val =~ /^[0-9]+$/;
2968
3125
  require Image::ExifTool::ID3;
2969
3126
  my $id = Image::ExifTool::ID3::GetGenreID($val);
2970
- return defined $id ? $id : $val;
2971
- },
3127
+ return unless defined $id and $id =~ /^\d+$/;
3128
+ return $id + 1;
3129
+ },
2972
3130
  },
2973
3131
  egid => 'EpisodeGlobalUniqueID', #7
2974
3132
  geID => { #10
2975
3133
  Name => 'GenreID',
2976
3134
  Format => 'int32u',
3135
+ Writable => 'int32s', #27
2977
3136
  SeparateTable => 1,
2978
3137
  # the following lookup is based on http://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/genres
2979
3138
  # (see scripts/parse_genre to parse genre JSON file from above)
@@ -5626,6 +5785,7 @@ my %eeBox = (
5626
5785
  hdvd => { #10
5627
5786
  Name => 'HDVideo',
5628
5787
  Format => 'int8u', #24
5788
+ Writable => 'int8s', #27
5629
5789
  PrintConv => { 0 => 'No', 1 => 'Yes' },
5630
5790
  },
5631
5791
  keyw => 'Keyword', #7
@@ -5633,18 +5793,21 @@ my %eeBox = (
5633
5793
  pcst => { #7
5634
5794
  Name => 'Podcast',
5635
5795
  Format => 'int8u', #23
5796
+ Writable => 'int8s', #27
5636
5797
  PrintConv => { 0 => 'No', 1 => 'Yes' },
5637
5798
  },
5638
5799
  perf => 'Performer',
5639
5800
  plID => { #10 (or TV season)
5640
5801
  Name => 'PlayListID',
5641
5802
  Format => 'int8u', # actually int64u, but split it up
5803
+ Writable => 'int32s', #27
5642
5804
  },
5643
5805
  purd => 'PurchaseDate', #7
5644
5806
  purl => 'PodcastURL', #7
5645
5807
  rtng => { #10
5646
5808
  Name => 'Rating',
5647
5809
  Format => 'int8u', #23
5810
+ Writable => 'int8s', #27
5648
5811
  PrintConv => {
5649
5812
  0 => 'none',
5650
5813
  1 => 'Explicit',
@@ -5655,6 +5818,7 @@ my %eeBox = (
5655
5818
  sfID => { #10
5656
5819
  Name => 'AppleStoreCountry',
5657
5820
  Format => 'int32u',
5821
+ Writable => 'int32s', #27
5658
5822
  SeparateTable => 1,
5659
5823
  PrintConv => { #21
5660
5824
  143441 => 'United States', # US
@@ -5823,6 +5987,7 @@ my %eeBox = (
5823
5987
  stik => { #10
5824
5988
  Name => 'MediaType',
5825
5989
  Format => 'int8u', #23
5990
+ Writable => 'int8s', #27
5826
5991
  PrintConvColumns => 2,
5827
5992
  PrintConv => { #(http://weblog.xanga.com/gryphondwb/615474010/iphone-ringtones---what-did-itunes-741-really-do.html)
5828
5993
  0 => 'Movie (old)', #forum9059 (was Movie)
@@ -5844,6 +6009,7 @@ my %eeBox = (
5844
6009
  tves => { #7/10
5845
6010
  Name => 'TVEpisode',
5846
6011
  Format => 'int32u',
6012
+ Writable => 'int32s', #27
5847
6013
  },
5848
6014
  tvnn => 'TVNetworkName', #7
5849
6015
  tvsh => 'TVShow', #10
@@ -5854,7 +6020,8 @@ my %eeBox = (
5854
6020
  yrrc => 'Year', #(ffmpeg source)
5855
6021
  itnu => { #PH (iTunes 10.5)
5856
6022
  Name => 'iTunesU',
5857
- Format => 'int8s',
6023
+ Format => 'int8u', #27
6024
+ Writable => 'int8s', #27
5858
6025
  Description => 'iTunes U',
5859
6026
  PrintConv => { 0 => 'No', 1 => 'Yes' },
5860
6027
  },
@@ -5904,6 +6071,27 @@ my %eeBox = (
5904
6071
  PrintConv => \&PrintGPSCoordinates,
5905
6072
  PrintConvInv => \&PrintInvGPSCoordinates,
5906
6073
  },
6074
+ # the following tags written by iTunes 12.5.1.21
6075
+ # (ref https://www.ventismedia.com/mantis/view.php?id=14963
6076
+ # https://community.mp3tag.de/t/x-mp4-new-tag-problems/19488)
6077
+ "\xa9wrk" => 'Work', #PH
6078
+ "\xa9mvn" => 'MovementName', #PH
6079
+ "\xa9mvi" => { #PH
6080
+ Name => 'MovementNumber',
6081
+ Format => 'int16u', #27
6082
+ Writable => 'int16s', #27
6083
+ },
6084
+ "\xa9mvc" => { #PH
6085
+ Name => 'MovementCount',
6086
+ Format => 'int16u', #27
6087
+ Writable => 'int16s', #27
6088
+ },
6089
+ shwm => { #PH
6090
+ Name => 'ShowMovement',
6091
+ Format => 'int8u', #27
6092
+ Writable => 'int8s', #27
6093
+ PrintConv => { 0 => 'No', 1 => 'Yes' },
6094
+ },
5907
6095
  );
5908
6096
 
5909
6097
  # tag decoded from timed face records
@@ -6123,6 +6311,21 @@ my %eeBox = (
6123
6311
  'detected-face.roll-angle' => { Name => 'DetectedFaceRollAngle', Writable => 0 },
6124
6312
  # (fiel)com.apple.quicktime.detected-face.yaw-angle (dtyp=23, float)
6125
6313
  'detected-face.yaw-angle' => { Name => 'DetectedFaceYawAngle', Writable => 0 },
6314
+ #
6315
+ # seen in Apple ProRes RAW file
6316
+ #
6317
+ # (mdta)com.apple.proapps.manufacturer (eg. "Sony")
6318
+ # (mdta)com.apple.proapps.exif.{Exif}.FNumber (float, eg. 1.0)
6319
+ # (mdta)org.smpte.rdd18.lens.irisfnumber (eg. "F1.0")
6320
+ # (mdta)com.apple.proapps.exif.{Exif}.ShutterSpeedValue (float, eg. 1.006)
6321
+ # (mdta)org.smpte.rdd18.camera.shutterspeed_angle (eg. "179.2deg")
6322
+ # (mdta)org.smpte.rdd18.camera.neutraldensityfilterwheelsetting (eg. "ND1")
6323
+ # (mdta)org.smpte.rdd18.camera.whitebalance (eg. "4300K")
6324
+ # (mdta)com.apple.proapps.exif.{Exif}.ExposureIndex (float, eg. 4000)
6325
+ # (mdta)org.smpte.rdd18.camera.isosensitivity (eg. "4000")
6326
+ # (mdta)com.apple.proapps.image.{TIFF}.Make (eg. "Atmos")
6327
+ # (mdta)com.apple.proapps.image.{TIFF}.Model (eg. "ShogunInferno")
6328
+ # (mdta)com.apple.proapps.image.{TIFF}.Software (eg. "9.0")
6126
6329
  );
6127
6330
 
6128
6331
  # iTunes info ('----') atoms
@@ -6663,7 +6866,7 @@ my %eeBox = (
6663
6866
  #
6664
6867
  # AudioFormat Offset Child atoms
6665
6868
  # ----------- ------ ----------------
6666
- # mp4a 52 * wave, chan, esds, SA3D(Insta360 spherical video params?)
6869
+ # mp4a 52 * wave, chan, esds, SA3D(Insta360 spherical video params?,also GoPro Max)
6667
6870
  # in24 52 wave, chan
6668
6871
  # "ms\0\x11" 52 wave
6669
6872
  # sowt 52 chan
@@ -6700,6 +6903,7 @@ my %eeBox = (
6700
6903
  # alac - 28 bytes
6701
6904
  # adrm - AAX DRM atom? 148 bytes
6702
6905
  # aabd - AAX unknown 17kB (contains 'aavd' strings)
6906
+ # SA3D - written by Garmin VIRB360
6703
6907
  );
6704
6908
 
6705
6909
  # AMR decode config box (ref 3)
@@ -6730,13 +6934,28 @@ my %eeBox = (
6730
6934
  Name => 'SchemeInfo',
6731
6935
  SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::SchemeInfo' },
6732
6936
  },
6937
+ enda => {
6938
+ Name => 'Endianness',
6939
+ Format => 'int16u',
6940
+ PrintConv => {
6941
+ 0 => 'Big-endian (Motorola, MM)',
6942
+ 1 => 'Little-endian (Intel, II)',
6943
+ },
6944
+ },
6733
6945
  # skcr
6734
- # enda
6735
6946
  );
6736
6947
 
6737
6948
  %Image::ExifTool::QuickTime::Wave = (
6738
6949
  PROCESS_PROC => \&ProcessMOV,
6739
6950
  frma => 'PurchaseFileFormat',
6951
+ enda => {
6952
+ Name => 'Endianness',
6953
+ Format => 'int16u',
6954
+ PrintConv => {
6955
+ 0 => 'Big-endian (Motorola, MM)',
6956
+ 1 => 'Little-endian (Intel, II)',
6957
+ },
6958
+ },
6740
6959
  # "ms\0\x11" - 20 bytes
6741
6960
  );
6742
6961
 
@@ -7171,6 +7390,20 @@ my %eeBox = (
7171
7390
  #
7172
7391
  ftab => { Name => 'FontTable', Format => 'undef', ValueConv => 'substr($val, 5)' },
7173
7392
  name => { Name => 'OtherName', Format => 'undef', ValueConv => 'substr($val, 4)' },
7393
+ # mrlh = GM header?
7394
+ # mrlv = GM data
7395
+ # mrld = GM data (448-byte records):
7396
+ # 0 - int32u count
7397
+ # 4 - int32u ? (related to units) 0=none,1=m/km,2=L,3=kph,4=C,7=deg,8=rpm,9=kPa,10=G,11=V,15=Nm,16=%
7398
+ # 8 - int32u ? (0,1,3,4,5)
7399
+ # 12 - string[64] units
7400
+ # 76 - int32u ? (1,3,7,15)
7401
+ # 80 - int32u 0
7402
+ # 84 - undef[4] ?
7403
+ # 88 - int16u[6] ?
7404
+ # 100 - undef[32] ?
7405
+ # 132 - string[64] measurement name
7406
+ # 196 - string[64] measurement name
7174
7407
  );
7175
7408
 
7176
7409
  # MP4 data information box (ref 5)
@@ -7467,6 +7700,7 @@ my %eeBox = (
7467
7700
  1 => 'QuickTime:HandlerType',
7468
7701
  },
7469
7702
  Writable => 1,
7703
+ Protected => 1,
7470
7704
  WriteAlso => {
7471
7705
  MatrixStructure => 'Image::ExifTool::QuickTime::GetRotationMatrix($val)',
7472
7706
  },
@@ -8232,6 +8466,11 @@ sub HandleItemInfo($)
8232
8466
  if ($buff =~ /^(MM\0\x2a|II\x2a\0)/) {
8233
8467
  $et->Warn('Missing Exif header');
8234
8468
  $start = 0;
8469
+ } elsif ($buff =~ /^Exif\0\0/) {
8470
+ # (haven't seen this yet, but it is just a matter of time
8471
+ # until someone screws it up like this)
8472
+ $et->Warn('Missing Exif header size');
8473
+ $start = 6;
8235
8474
  } else {
8236
8475
  my $n = unpack('N', $buff);
8237
8476
  $start = 4 + $n; # skip "Exif\0\0" header if it exists
@@ -8296,7 +8535,7 @@ sub EEWarn($)
8296
8535
  #------------------------------------------------------------------------------
8297
8536
  # Get quicktime format from flags word
8298
8537
  # Inputs: 0) quicktime atom flags, 1) data length
8299
- # Returns: Exiftool format string
8538
+ # Returns: ExifTool format string
8300
8539
  sub QuickTimeFormat($$)
8301
8540
  {
8302
8541
  my ($flags, $len) = @_;
@@ -8523,7 +8762,7 @@ sub ProcessKeys($$$)
8523
8762
  my $ns = substr($$dataPt, $pos + 4, 4);
8524
8763
  my $tag = substr($$dataPt, $pos + 8, $len - 8);
8525
8764
  $tag =~ s/\0.*//s; # truncate at null
8526
- $tag =~ s/^com\.apple\.quicktime\.// if $ns eq 'mdta'; # remove apple quicktime domain
8765
+ $tag =~ s/^com\.(apple\.quicktime\.)?// if $ns eq 'mdta'; # remove apple quicktime domain
8527
8766
  $tag = "Tag_$ns" unless $tag;
8528
8767
  # (I have some samples where the tag is a reversed ItemList or UserData tag ID)
8529
8768
  my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
@@ -8555,9 +8794,10 @@ sub ProcessKeys($$$)
8555
8794
  $$newInfo{Groups} = $groups ? { %$groups } : { };
8556
8795
  $$newInfo{Groups}{$_} or $$newInfo{Groups}{$_} = $$tagTablePtr{GROUPS}{$_} foreach 0..2;
8557
8796
  $$newInfo{Groups}{1} = 'Keys';
8558
- } elsif ($tag =~ /^[-\w. ]+$/) {
8797
+ } elsif ($tag =~ /^[-\w. ]+$/ or $tag =~ /\w{4}/) {
8559
8798
  # create info for tags with reasonable id's
8560
8799
  my $name = ucfirst $tag;
8800
+ $name =~ tr/-0-9a-zA-Z_. //dc;
8561
8801
  $name =~ s/[. ]+(.?)/\U$1/g;
8562
8802
  $name =~ s/_([a-z])/_\U$1/g;
8563
8803
  $name =~ s/([a-z])_([A-Z])/$1$2/g;
@@ -8578,7 +8818,7 @@ sub ProcessKeys($$$)
8578
8818
  if ($newInfo) {
8579
8819
  AddTagToTable($itemList, $id, $newInfo);
8580
8820
  $msg or $msg = '';
8581
- $out and print $out "$$et{INDENT}Added ItemList Tag $id = $tag$msg\n";
8821
+ $out and print $out "$$et{INDENT}Added ItemList Tag $id = ($ns) $tag$msg\n";
8582
8822
  }
8583
8823
  $pos += $len;
8584
8824
  ++$index;
@@ -9033,10 +9273,10 @@ ItemID: foreach $id (keys %$items) {
9033
9273
  }
9034
9274
  }
9035
9275
  if ($ctry or $lang) {
9036
- $lang = GetLangCode($lang, $ctry);
9037
- if ($lang) {
9276
+ my $langCode = GetLangCode($lang, $ctry);
9277
+ if ($langCode) {
9038
9278
  # get tagInfo for other language
9039
- $langInfo = GetLangInfoQT($et, $tagInfo, $lang);
9279
+ $langInfo = GetLangInfoQT($et, $tagInfo, $langCode);
9040
9280
  # save other language tag ID's so we can delete later if necessary
9041
9281
  if ($langInfo) {
9042
9282
  $$tagInfo{OtherLang} or $$tagInfo{OtherLang} = [ ];
@@ -9053,7 +9293,7 @@ ItemID: foreach $id (keys %$items) {
9053
9293
  Size => $len,
9054
9294
  Format => $format,
9055
9295
  Index => $index,
9056
- Extra => sprintf(", Type='${type}', Flags=0x%x%s",$flags,($lang ? ", Lang=$lang" : '')),
9296
+ Extra => sprintf(", Type='${type}', Flags=0x%x, Lang=0x%.4x",$flags,$lang),
9057
9297
  ) if $verbose;
9058
9298
  # use "Keys" in path instead of ItemList if this was defined by a Keys tag
9059
9299
  my $isKey = $$tagInfo{Groups} && $$tagInfo{Groups}{1} && $$tagInfo{Groups}{1} eq 'Keys';