exiftool_vendored 11.94.0 → 12.06.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 (62) hide show
  1. checksums.yaml +5 -5
  2. data/bin/Changes +163 -3
  3. data/bin/MANIFEST +5 -0
  4. data/bin/META.json +1 -1
  5. data/bin/META.yml +1 -1
  6. data/bin/README +32 -32
  7. data/bin/exiftool +152 -52
  8. data/bin/lib/Image/ExifTool.pm +166 -115
  9. data/bin/lib/Image/ExifTool.pod +108 -81
  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 +6 -3
  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 +16 -3
  17. data/bin/lib/Image/ExifTool/Exif.pm +15 -6
  18. data/bin/lib/Image/ExifTool/Font.pm +9 -2
  19. data/bin/lib/Image/ExifTool/GIF.pm +5 -0
  20. data/bin/lib/Image/ExifTool/GeoTiff.pm +2 -0
  21. data/bin/lib/Image/ExifTool/Geotag.pm +69 -21
  22. data/bin/lib/Image/ExifTool/GoPro.pm +10 -1
  23. data/bin/lib/Image/ExifTool/H264.pm +1 -1
  24. data/bin/lib/Image/ExifTool/HtmlDump.pm +2 -2
  25. data/bin/lib/Image/ExifTool/ID3.pm +91 -12
  26. data/bin/lib/Image/ExifTool/Lang/de.pm +3 -1
  27. data/bin/lib/Image/ExifTool/Lang/es.pm +1 -1
  28. data/bin/lib/Image/ExifTool/M2TS.pm +44 -24
  29. data/bin/lib/Image/ExifTool/MWG.pm +9 -1
  30. data/bin/lib/Image/ExifTool/MacOS.pm +1 -1
  31. data/bin/lib/Image/ExifTool/Minolta.pm +3 -2
  32. data/bin/lib/Image/ExifTool/MinoltaRaw.pm +11 -10
  33. data/bin/lib/Image/ExifTool/Nikon.pm +156 -18
  34. data/bin/lib/Image/ExifTool/Olympus.pm +34 -17
  35. data/bin/lib/Image/ExifTool/PNG.pm +14 -3
  36. data/bin/lib/Image/ExifTool/PPM.pm +5 -5
  37. data/bin/lib/Image/ExifTool/Panasonic.pm +147 -13
  38. data/bin/lib/Image/ExifTool/PanasonicRaw.pm +33 -0
  39. data/bin/lib/Image/ExifTool/Parrot.pm +2 -1
  40. data/bin/lib/Image/ExifTool/Pentax.pm +3 -1
  41. data/bin/lib/Image/ExifTool/Photoshop.pm +2 -1
  42. data/bin/lib/Image/ExifTool/QuickTime.pm +277 -33
  43. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +460 -67
  44. data/bin/lib/Image/ExifTool/README +21 -20
  45. data/bin/lib/Image/ExifTool/RIFF.pm +123 -3
  46. data/bin/lib/Image/ExifTool/RTF.pm +12 -7
  47. data/bin/lib/Image/ExifTool/Ricoh.pm +19 -1
  48. data/bin/lib/Image/ExifTool/Shift.pl +1 -0
  49. data/bin/lib/Image/ExifTool/SigmaRaw.pm +40 -33
  50. data/bin/lib/Image/ExifTool/Sony.pm +379 -12
  51. data/bin/lib/Image/ExifTool/TagLookup.pm +1959 -1874
  52. data/bin/lib/Image/ExifTool/TagNames.pod +346 -55
  53. data/bin/lib/Image/ExifTool/Validate.pm +4 -4
  54. data/bin/lib/Image/ExifTool/WriteExif.pl +3 -2
  55. data/bin/lib/Image/ExifTool/WriteQuickTime.pl +26 -15
  56. data/bin/lib/Image/ExifTool/Writer.pl +52 -23
  57. data/bin/lib/Image/ExifTool/XMP.pm +41 -4
  58. data/bin/lib/Image/ExifTool/XMPStruct.pl +3 -1
  59. data/bin/lib/Image/ExifTool/ZISRAW.pm +123 -0
  60. data/bin/perl-Image-ExifTool.spec +31 -31
  61. data/lib/exiftool_vendored/version.rb +1 -1
  62. metadata +4 -4
@@ -531,14 +531,45 @@ my %panasonicWhiteBalance = ( #forum9396
531
531
  PrintConv => '"$val mm"',
532
532
  PrintConvInv => '$val=~s/\s*mm$//;$val',
533
533
  },
534
+ # 0x1300 - incident light value? (ref forum11395)
535
+ 0x1301 => { #forum11395
536
+ Name => 'ApertureValue',
537
+ Writable => 'int16s',
538
+ Priority => 0,
539
+ ValueConv => '2 ** ($val / 512)',
540
+ ValueConvInv => '$val>0 ? 512*log($val)/log(2) : 0',
541
+ PrintConv => 'sprintf("%.1f",$val)',
542
+ PrintConvInv => '$val',
543
+ },
544
+ 0x1302 => { #forum11395
545
+ Name => 'ShutterSpeedValue',
546
+ Writable => 'int16s',
547
+ Priority => 0,
548
+ ValueConv => 'abs($val/256)<100 ? 2**(-$val/256) : 0',
549
+ ValueConvInv => '$val>0 ? -256*log($val)/log(2) : -25600',
550
+ PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
551
+ PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)',
552
+ },
553
+ 0x1303 => { #forum11395
554
+ Name => 'SensitivityValue',
555
+ Writable => 'int16s',
556
+ ValueConv => '$val / 256',
557
+ ValueConvInv => 'int($val * 256)',
558
+ },
534
559
  0x1305 => { #forum9384
535
560
  Name => 'HighISOMode',
536
561
  Writable => 'int16u',
537
562
  RawConv => '$val || undef',
538
563
  PrintConv => { 1 => 'On', 2 => 'Off' },
539
564
  },
565
+ # 0x1306 EV for some models like the GX8 (forum11395)
540
566
  # 0x140b - scaled overall black level? (ref forum9281)
541
567
  # 0x1411 - scaled black level per channel difference (ref forum9281)
568
+ 0x1412 => { #forum11397
569
+ Name => 'FacesDetected',
570
+ Writable => 'int8u',
571
+ PrintConv => { 0 => 'No', 1 => 'Yes' },
572
+ },
542
573
  # 0x2000 - WB tungsten=3, daylight=4 (ref forum9467)
543
574
  # 0x2009 - scaled black level per channel (ref forum9281)
544
575
  # 0x3000-0x310b - red/blue balances * 1024 (ref forum9467)
@@ -600,6 +631,8 @@ my %panasonicWhiteBalance = ( #forum9396
600
631
  Writable => 'int8u',
601
632
  PrintConv => \%Image::ExifTool::Exif::orientation,
602
633
  },
634
+ # 0x3504 = Tag 0x1301+0x1302-0x1303 (Bv = Av+Tv-Sv) (forum11395)
635
+ # 0x3505 - same as 0x1300 (forum11395)
603
636
  0x3600 => { #forum9396
604
637
  Name => 'WhiteBalanceDetected',
605
638
  Writable => 'int8u',
@@ -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.46';
50
+ $VERSION = '2.52';
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/',
@@ -667,6 +685,11 @@ my %eeBox = (
667
685
  },
668
686
  # gpsa - seen hex "01 20 00 00" (DuDuBell M1, VSYS M6L)
669
687
  # gsea - 20 bytes hex "05 00's..." (DuDuBell M1) "05 08 02 01 ..." (VSYS M6L)
688
+ 'GPS ' => { # GPS data written by 70mai dashcam (parsed in QuickTimeStream.pl)
689
+ Name => 'GPSDataList2',
690
+ Unknown => 1,
691
+ Binary => 1,
692
+ },
670
693
  );
671
694
 
672
695
  # MPEG-4 'ftyp' atom
@@ -962,7 +985,7 @@ my %eeBox = (
962
985
  %Image::ExifTool::QuickTime::CleanAperture = (
963
986
  PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
964
987
  GROUPS => { 2 => 'Video' },
965
- FORMAT => 'rational64u',
988
+ FORMAT => 'rational64s',
966
989
  0 => 'CleanApertureWidth',
967
990
  1 => 'CleanApertureHeight',
968
991
  2 => 'CleanApertureOffsetX',
@@ -1307,6 +1330,7 @@ my %eeBox = (
1307
1330
  Format => 'fixed32s[9]',
1308
1331
  Notes => 'writable for the video track via the Composite Rotation tag',
1309
1332
  Writable => 1,
1333
+ Protected => 1,
1310
1334
  Permanent => 1,
1311
1335
  # only set rotation if image size is non-zero
1312
1336
  RawConvInv => \&GetMatrixStructure,
@@ -1371,8 +1395,8 @@ my %eeBox = (
1371
1395
  },
1372
1396
  ValueConvInv => q{
1373
1397
  require Image::ExifTool::XMP;
1374
- $val = Image::ExifTool::XMP::FormatXMPDate($val);
1375
- $val =~ s/([-+]\d{2}):(\d{2})$/$1$2/; # remove time zone colon
1398
+ my $tmp = Image::ExifTool::XMP::FormatXMPDate($val);
1399
+ ($val = $tmp) =~ s/([-+]\d{2}):(\d{2})$/$1$2/ if defined $tmp; # remove time zone colon
1376
1400
  return $val;
1377
1401
  },
1378
1402
  PrintConv => '$self->ConvertDateTime($val)',
@@ -1628,10 +1652,14 @@ my %eeBox = (
1628
1652
  Avoid => 1,
1629
1653
  Format => 'string', # (necessary to remove the trailing NULL)
1630
1654
  },
1631
- date => { # (NC)
1655
+ date => {
1632
1656
  Name => 'DateTimeOriginal',
1633
1657
  Description => 'Date/Time Original',
1634
1658
  Groups => { 2 => 'Time' },
1659
+ Notes => q{
1660
+ Apple Photos has been reported to show a crazy date/time for some MP4 files
1661
+ containing this tag, but perhaps only if it is missing a time zone
1662
+ }, #forum10690/11125
1635
1663
  Shift => 'Time',
1636
1664
  ValueConv => q{
1637
1665
  require Image::ExifTool::XMP;
@@ -1853,6 +1881,25 @@ my %eeBox = (
1853
1881
  ByteOrder => 'LittleEndian',
1854
1882
  },
1855
1883
  },
1884
+ # ---- Garmin ---- (ref PH)
1885
+ uuid => [{
1886
+ Name => 'GarminSoftware', # (NC)
1887
+ Condition => '$$valPt =~ /^VIRBactioncamera/',
1888
+ RawConv => 'substr($val, 16)',
1889
+ RawConvInv => '"VIRBactioncamera$val"',
1890
+ },{
1891
+ # 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)
1892
+ Name => 'UUID-Unknown',
1893
+ Writable => 0,
1894
+ %unknownInfo,
1895
+ }],
1896
+ pmcc => {
1897
+ Name => 'GarminSettings',
1898
+ ValueConv => 'substr($val, 4)',
1899
+ ValueConvInv => '"\0\0\0\x01$val"',
1900
+ },
1901
+ # hmtp - "\0\0\0\x01" followed by 408 bytes of zero
1902
+ # vrin - "\0\0\0\x01" followed by 8 bytes of zero
1856
1903
  # ---- GoPro ---- (ref PH)
1857
1904
  GoPr => 'GoProType', # (Hero3+)
1858
1905
  FIRM => { Name => 'FirmwareVersion', Avoid => 1 }, # (Hero4)
@@ -2036,6 +2083,63 @@ my %eeBox = (
2036
2083
  ProcessProc => \&Image::ExifTool::ProcessTIFF, # (because ProcessMOV is default)
2037
2084
  },
2038
2085
  },
2086
+ '@mak' => { Name => 'Make', Avoid => 1 },
2087
+ '@mod' => { Name => 'Model', Avoid => 1 },
2088
+ '@swr' => { Name => 'SoftwareVersion', Avoid => 1 },
2089
+ '@day' => {
2090
+ Name => 'ContentCreateDate',
2091
+ Notes => q{
2092
+ some stupid Ricoh programmer used the '@' symbol instead of the copyright
2093
+ symbol in these tag ID's for the Ricoh Theta Z1 and maybe other models
2094
+ },
2095
+ Groups => { 2 => 'Time' },
2096
+ Shift => 'Time',
2097
+ Avoid => 1,
2098
+ # handle values in the form "2010-02-12T13:27:14-0800"
2099
+ ValueConv => q{
2100
+ require Image::ExifTool::XMP;
2101
+ $val = Image::ExifTool::XMP::ConvertXMPDate($val);
2102
+ $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary
2103
+ return $val;
2104
+ },
2105
+ ValueConvInv => q{
2106
+ require Image::ExifTool::XMP;
2107
+ my $tmp = Image::ExifTool::XMP::FormatXMPDate($val);
2108
+ ($val = $tmp) =~ s/([-+]\d{2}):(\d{2})$/$1$2/ if defined $tmp; # remove time zone colon
2109
+ return $val;
2110
+ },
2111
+ PrintConv => '$self->ConvertDateTime($val)',
2112
+ PrintConvInv => '$self->InverseDateTime($val)',
2113
+ },
2114
+ '@xyz' => { #PH (iPhone 3GS)
2115
+ Name => 'GPSCoordinates',
2116
+ Groups => { 2 => 'Location' },
2117
+ Avoid => 1,
2118
+ ValueConv => \&ConvertISO6709,
2119
+ ValueConvInv => \&ConvInvISO6709,
2120
+ PrintConv => \&PrintGPSCoordinates,
2121
+ PrintConvInv => \&PrintInvGPSCoordinates,
2122
+ },
2123
+ # RDT1 - pairs of int32u_BE, starting at byte 8: "458275 471846"
2124
+ # RDT2 - pairs of int32u_BE, starting at byte 8: "472276 468526"
2125
+ # RDT3 - pairs of int32u_BE, starting at byte 8: "876603 482191"
2126
+ # RDT4 - pairs of int32u_BE, starting at byte 8: "1955 484612"
2127
+ # RDT6 - empty
2128
+ # RDT7 - empty
2129
+ # RDT8 - empty
2130
+ # RDT9 - only 16-byte header?
2131
+ # the boxes below all have a similar header (little-endian):
2132
+ # 0 int32u - number of records
2133
+ # 4 ? - "1e 00"
2134
+ # 6 int16u - record length in bytes
2135
+ # 8 ? - "23 01 00 00 00 00 00 00"
2136
+ # 16 - start of records (each record ends in an int64u timestamp in ns)
2137
+ # RDTA - float[4],ts: "-0.31289672 -0.2245330 11.303817 0 775.780"
2138
+ # RDTB - float[4],ts: "-0.04841613 -0.2166595 0.0724792 0 775.780"
2139
+ # RDTC - float[4],ts: "27.60925 -27.10037 -13.27285 0 775.829"
2140
+ # RDTD - int16s[3],ts: "353 -914 16354 0 775.829"
2141
+ # RDTG - ts: "775.825"
2142
+ # RDTI - float[4],ts: "0.00165951 0.005770059 0.06838259 0.1744695 775.862"
2039
2143
  # ---- Samsung ----
2040
2144
  vndr => 'Vendor', #PH (Samsung PL70)
2041
2145
  SDLN => 'PlayMode', #PH (NC, Samsung ST80 "SEQ_PLAY")
@@ -2512,6 +2616,7 @@ my %eeBox = (
2512
2616
  Name => 'Rotation',
2513
2617
  Format => 'int8u',
2514
2618
  Writable => 'int8u',
2619
+ Protected => 1,
2515
2620
  ValueConv => '$val * 90',
2516
2621
  ValueConvInv => 'int($val / 90 + 0.5)',
2517
2622
  },
@@ -2543,6 +2648,7 @@ my %eeBox = (
2543
2648
  Name => 'PixelAspectRatio',
2544
2649
  Format => 'int32u',
2545
2650
  Writable => 'int32u',
2651
+ Protected => 1,
2546
2652
  },
2547
2653
  rloc => {
2548
2654
  Name => 'RelativeLocation',
@@ -2551,7 +2657,7 @@ my %eeBox = (
2551
2657
  },
2552
2658
  clap => {
2553
2659
  Name => 'CleanAperture',
2554
- Format => 'rational64u',
2660
+ Format => 'rational64s',
2555
2661
  Notes => '4 numbers: width, height, left and top',
2556
2662
  },
2557
2663
  hvcC => {
@@ -2889,10 +2995,25 @@ my %eeBox = (
2889
2995
  "\xa9grp" => 'Grouping',
2890
2996
  "\xa9lyr" => 'Lyrics',
2891
2997
  "\xa9nam" => 'Title',
2892
- # "\xa9st3" ? #10
2893
2998
  "\xa9too" => 'Encoder',
2894
2999
  "\xa9trk" => 'Track',
2895
3000
  "\xa9wrt" => 'Composer',
3001
+ #
3002
+ # the following tags written by AtomicParsley 0.9.6
3003
+ # (ref https://exiftool.org/forum/index.php?topic=11455.0)
3004
+ #
3005
+ "\xa9st3" => 'Subtitle',
3006
+ "\xa9con" => 'Conductor',
3007
+ "\xa9sol" => 'Soloist',
3008
+ "\xa9arg" => 'Arranger',
3009
+ "\xa9ope" => 'OriginalArtist',
3010
+ "\xa9dir" => 'Director',
3011
+ "\xa9ard" => 'ArtDirector',
3012
+ "\xa9sne" => 'SoundEngineer',
3013
+ "\xa9prd" => 'Producer',
3014
+ "\xa9xpd" => 'ExecutiveProducer',
3015
+ sdes => 'StoreDescription',
3016
+ #
2896
3017
  '----' => {
2897
3018
  Name => 'iTunesInfo',
2898
3019
  SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::iTunesInfo' },
@@ -2901,18 +3022,29 @@ my %eeBox = (
2901
3022
  covr => { Name => 'CoverArt', Groups => { 2 => 'Preview' } },
2902
3023
  cpil => { #10
2903
3024
  Name => 'Compilation',
2904
- Format => 'int8u', #23
3025
+ Format => 'int8u', #27 (ref 23 contradicts what AtomicParsley actually writes, which is int8s)
3026
+ Writable => 'int8s',
2905
3027
  PrintConv => { 0 => 'No', 1 => 'Yes' },
2906
3028
  },
2907
3029
  disk => {
2908
3030
  Name => 'DiskNumber',
2909
3031
  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',
3032
+ ValueConv => q{
3033
+ return \$val unless length($val) >= 6;
3034
+ my @a = unpack 'x2nn', $val;
3035
+ return $a[1] ? join(' of ', @a) : $a[0];
3036
+ },
3037
+ ValueConvInv => q{
3038
+ my @a = $val =~ /\d+/g;
3039
+ return undef if @a == 0 or @a > 2;
3040
+ push @a, 0 if @a == 1;
3041
+ return pack('n3', 0, @a);
3042
+ },
2912
3043
  },
2913
3044
  pgap => { #10
2914
3045
  Name => 'PlayGap',
2915
3046
  Format => 'int8u', #23
3047
+ Writable => 'int8s', #27
2916
3048
  PrintConv => {
2917
3049
  0 => 'Insert Gap',
2918
3050
  1 => 'No Gap',
@@ -2920,13 +3052,26 @@ my %eeBox = (
2920
3052
  },
2921
3053
  tmpo => {
2922
3054
  Name => 'BeatsPerMinute',
2923
- Format => 'int16u', # marked as boolean but really int16u in my sample
3055
+ # marked as boolean but really int16u in my sample
3056
+ # (but written as int16s by iTunes and AtomicParsley, ref forum11506)
3057
+ Format => 'int16u',
3058
+ Writable => 'int16s',
2924
3059
  },
2925
3060
  trkn => {
2926
3061
  Name => 'TrackNumber',
2927
3062
  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',
3063
+ ValueConv => q{
3064
+ return \$val unless length($val) >= 6;
3065
+ my @a = unpack 'x2nn', $val;
3066
+ return $a[1] ? join(' of ', @a) : $a[0];
3067
+ },
3068
+ # (see forum11501 for discussion about the format used)
3069
+ ValueConvInv => q{
3070
+ my @a = $val =~ /\d+/g;
3071
+ return undef if @a == 0 or @a > 2;
3072
+ push @a, 0 if @a == 1;
3073
+ return pack('n4', 0, @a, 0);
3074
+ },
2930
3075
  },
2931
3076
  #
2932
3077
  # Note: it is possible that the tags below are not being decoded properly
@@ -2935,6 +3080,7 @@ my %eeBox = (
2935
3080
  akID => { #10
2936
3081
  Name => 'AppleStoreAccountType',
2937
3082
  Format => 'int8u', #24
3083
+ Writable => 'int8s', #27
2938
3084
  PrintConv => {
2939
3085
  0 => 'iTunes',
2940
3086
  1 => 'AOL',
@@ -2945,12 +3091,14 @@ my %eeBox = (
2945
3091
  atID => { #10 (or TV series)
2946
3092
  Name => 'AlbumTitleID',
2947
3093
  Format => 'int32u',
3094
+ Writable => 'int32s', #27
2948
3095
  },
2949
3096
  auth => { Name => 'Author', Groups => { 2 => 'Author' } },
2950
3097
  catg => 'Category', #7
2951
3098
  cnID => { #10
2952
3099
  Name => 'AppleStoreCatalogID',
2953
3100
  Format => 'int32u',
3101
+ Writable => 'int32s', #27
2954
3102
  },
2955
3103
  cprt => { Name => 'Copyright', Groups => { 2 => 'Author' } },
2956
3104
  dscp => { Name => 'Description', Avoid => 1 },
@@ -2958,22 +3106,28 @@ my %eeBox = (
2958
3106
  gnre => { #10
2959
3107
  Name => 'Genre',
2960
3108
  Avoid => 1,
2961
- # (Note: not written as int16u if numerical, although it should be)
3109
+ # (Note: see https://exiftool.org/forum/index.php?topic=11537.0)
3110
+ Format => 'undef',
3111
+ ValueConv => 'unpack("n",$val)',
3112
+ ValueConvInv => '$val =~ /^\d+$/ ? pack("n",$val) : undef',
2962
3113
  PrintConv => q{
2963
3114
  return $val unless $val =~ /^\d+$/;
2964
3115
  require Image::ExifTool::ID3;
2965
3116
  Image::ExifTool::ID3::PrintGenre($val - 1); # note the "- 1"
2966
3117
  },
2967
3118
  PrintConvInv => q{
3119
+ return $val if $val =~ /^[0-9]+$/;
2968
3120
  require Image::ExifTool::ID3;
2969
3121
  my $id = Image::ExifTool::ID3::GetGenreID($val);
2970
- return defined $id ? $id : $val;
2971
- },
3122
+ return unless defined $id and $id =~ /^\d+$/;
3123
+ return $id + 1;
3124
+ },
2972
3125
  },
2973
3126
  egid => 'EpisodeGlobalUniqueID', #7
2974
3127
  geID => { #10
2975
3128
  Name => 'GenreID',
2976
3129
  Format => 'int32u',
3130
+ Writable => 'int32s', #27
2977
3131
  SeparateTable => 1,
2978
3132
  # the following lookup is based on http://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/genres
2979
3133
  # (see scripts/parse_genre to parse genre JSON file from above)
@@ -5626,6 +5780,7 @@ my %eeBox = (
5626
5780
  hdvd => { #10
5627
5781
  Name => 'HDVideo',
5628
5782
  Format => 'int8u', #24
5783
+ Writable => 'int8s', #27
5629
5784
  PrintConv => { 0 => 'No', 1 => 'Yes' },
5630
5785
  },
5631
5786
  keyw => 'Keyword', #7
@@ -5633,18 +5788,21 @@ my %eeBox = (
5633
5788
  pcst => { #7
5634
5789
  Name => 'Podcast',
5635
5790
  Format => 'int8u', #23
5791
+ Writable => 'int8s', #27
5636
5792
  PrintConv => { 0 => 'No', 1 => 'Yes' },
5637
5793
  },
5638
5794
  perf => 'Performer',
5639
5795
  plID => { #10 (or TV season)
5640
5796
  Name => 'PlayListID',
5641
5797
  Format => 'int8u', # actually int64u, but split it up
5798
+ Writable => 'int32s', #27
5642
5799
  },
5643
5800
  purd => 'PurchaseDate', #7
5644
5801
  purl => 'PodcastURL', #7
5645
5802
  rtng => { #10
5646
5803
  Name => 'Rating',
5647
5804
  Format => 'int8u', #23
5805
+ Writable => 'int8s', #27
5648
5806
  PrintConv => {
5649
5807
  0 => 'none',
5650
5808
  1 => 'Explicit',
@@ -5655,6 +5813,7 @@ my %eeBox = (
5655
5813
  sfID => { #10
5656
5814
  Name => 'AppleStoreCountry',
5657
5815
  Format => 'int32u',
5816
+ Writable => 'int32s', #27
5658
5817
  SeparateTable => 1,
5659
5818
  PrintConv => { #21
5660
5819
  143441 => 'United States', # US
@@ -5823,6 +5982,7 @@ my %eeBox = (
5823
5982
  stik => { #10
5824
5983
  Name => 'MediaType',
5825
5984
  Format => 'int8u', #23
5985
+ Writable => 'int8s', #27
5826
5986
  PrintConvColumns => 2,
5827
5987
  PrintConv => { #(http://weblog.xanga.com/gryphondwb/615474010/iphone-ringtones---what-did-itunes-741-really-do.html)
5828
5988
  0 => 'Movie (old)', #forum9059 (was Movie)
@@ -5844,6 +6004,7 @@ my %eeBox = (
5844
6004
  tves => { #7/10
5845
6005
  Name => 'TVEpisode',
5846
6006
  Format => 'int32u',
6007
+ Writable => 'int32s', #27
5847
6008
  },
5848
6009
  tvnn => 'TVNetworkName', #7
5849
6010
  tvsh => 'TVShow', #10
@@ -5854,7 +6015,8 @@ my %eeBox = (
5854
6015
  yrrc => 'Year', #(ffmpeg source)
5855
6016
  itnu => { #PH (iTunes 10.5)
5856
6017
  Name => 'iTunesU',
5857
- Format => 'int8s',
6018
+ Format => 'int8u', #27
6019
+ Writable => 'int8s', #27
5858
6020
  Description => 'iTunes U',
5859
6021
  PrintConv => { 0 => 'No', 1 => 'Yes' },
5860
6022
  },
@@ -5904,6 +6066,27 @@ my %eeBox = (
5904
6066
  PrintConv => \&PrintGPSCoordinates,
5905
6067
  PrintConvInv => \&PrintInvGPSCoordinates,
5906
6068
  },
6069
+ # the following tags written by iTunes 12.5.1.21
6070
+ # (ref https://www.ventismedia.com/mantis/view.php?id=14963
6071
+ # https://community.mp3tag.de/t/x-mp4-new-tag-problems/19488)
6072
+ "\xa9wrk" => 'Work', #PH
6073
+ "\xa9mvn" => 'MovementName', #PH
6074
+ "\xa9mvi" => { #PH
6075
+ Name => 'MovementNumber',
6076
+ Format => 'int16u', #27
6077
+ Writable => 'int16s', #27
6078
+ },
6079
+ "\xa9mvc" => { #PH
6080
+ Name => 'MovementCount',
6081
+ Format => 'int16u', #27
6082
+ Writable => 'int16s', #27
6083
+ },
6084
+ shwm => { #PH
6085
+ Name => 'ShowMovement',
6086
+ Format => 'int8u', #27
6087
+ Writable => 'int8s', #27
6088
+ PrintConv => { 0 => 'No', 1 => 'Yes' },
6089
+ },
5907
6090
  );
5908
6091
 
5909
6092
  # tag decoded from timed face records
@@ -6123,6 +6306,21 @@ my %eeBox = (
6123
6306
  'detected-face.roll-angle' => { Name => 'DetectedFaceRollAngle', Writable => 0 },
6124
6307
  # (fiel)com.apple.quicktime.detected-face.yaw-angle (dtyp=23, float)
6125
6308
  'detected-face.yaw-angle' => { Name => 'DetectedFaceYawAngle', Writable => 0 },
6309
+ #
6310
+ # seen in Apple ProRes RAW file
6311
+ #
6312
+ # (mdta)com.apple.proapps.manufacturer (eg. "Sony")
6313
+ # (mdta)com.apple.proapps.exif.{Exif}.FNumber (float, eg. 1.0)
6314
+ # (mdta)org.smpte.rdd18.lens.irisfnumber (eg. "F1.0")
6315
+ # (mdta)com.apple.proapps.exif.{Exif}.ShutterSpeedValue (float, eg. 1.006)
6316
+ # (mdta)org.smpte.rdd18.camera.shutterspeed_angle (eg. "179.2deg")
6317
+ # (mdta)org.smpte.rdd18.camera.neutraldensityfilterwheelsetting (eg. "ND1")
6318
+ # (mdta)org.smpte.rdd18.camera.whitebalance (eg. "4300K")
6319
+ # (mdta)com.apple.proapps.exif.{Exif}.ExposureIndex (float, eg. 4000)
6320
+ # (mdta)org.smpte.rdd18.camera.isosensitivity (eg. "4000")
6321
+ # (mdta)com.apple.proapps.image.{TIFF}.Make (eg. "Atmos")
6322
+ # (mdta)com.apple.proapps.image.{TIFF}.Model (eg. "ShogunInferno")
6323
+ # (mdta)com.apple.proapps.image.{TIFF}.Software (eg. "9.0")
6126
6324
  );
6127
6325
 
6128
6326
  # iTunes info ('----') atoms
@@ -6700,6 +6898,7 @@ my %eeBox = (
6700
6898
  # alac - 28 bytes
6701
6899
  # adrm - AAX DRM atom? 148 bytes
6702
6900
  # aabd - AAX unknown 17kB (contains 'aavd' strings)
6901
+ # SA3D - written by Garmin VIRB360
6703
6902
  );
6704
6903
 
6705
6904
  # AMR decode config box (ref 3)
@@ -6730,13 +6929,28 @@ my %eeBox = (
6730
6929
  Name => 'SchemeInfo',
6731
6930
  SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::SchemeInfo' },
6732
6931
  },
6932
+ enda => {
6933
+ Name => 'Endianness',
6934
+ Format => 'int16u',
6935
+ PrintConv => {
6936
+ 0 => 'Big-endian (Motorola, MM)',
6937
+ 1 => 'Little-endian (Intel, II)',
6938
+ },
6939
+ },
6733
6940
  # skcr
6734
- # enda
6735
6941
  );
6736
6942
 
6737
6943
  %Image::ExifTool::QuickTime::Wave = (
6738
6944
  PROCESS_PROC => \&ProcessMOV,
6739
6945
  frma => 'PurchaseFileFormat',
6946
+ enda => {
6947
+ Name => 'Endianness',
6948
+ Format => 'int16u',
6949
+ PrintConv => {
6950
+ 0 => 'Big-endian (Motorola, MM)',
6951
+ 1 => 'Little-endian (Intel, II)',
6952
+ },
6953
+ },
6740
6954
  # "ms\0\x11" - 20 bytes
6741
6955
  );
6742
6956
 
@@ -7171,6 +7385,20 @@ my %eeBox = (
7171
7385
  #
7172
7386
  ftab => { Name => 'FontTable', Format => 'undef', ValueConv => 'substr($val, 5)' },
7173
7387
  name => { Name => 'OtherName', Format => 'undef', ValueConv => 'substr($val, 4)' },
7388
+ # mrlh = GM header?
7389
+ # mrlv = GM data
7390
+ # mrld = GM data (448-byte records):
7391
+ # 0 - int32u count
7392
+ # 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=%
7393
+ # 8 - int32u ? (0,1,3,4,5)
7394
+ # 12 - string[64] units
7395
+ # 76 - int32u ? (1,3,7,15)
7396
+ # 80 - int32u 0
7397
+ # 84 - undef[4] ?
7398
+ # 88 - int16u[6] ?
7399
+ # 100 - undef[32] ?
7400
+ # 132 - string[64] measurement name
7401
+ # 196 - string[64] measurement name
7174
7402
  );
7175
7403
 
7176
7404
  # MP4 data information box (ref 5)
@@ -7467,6 +7695,7 @@ my %eeBox = (
7467
7695
  1 => 'QuickTime:HandlerType',
7468
7696
  },
7469
7697
  Writable => 1,
7698
+ Protected => 1,
7470
7699
  WriteAlso => {
7471
7700
  MatrixStructure => 'Image::ExifTool::QuickTime::GetRotationMatrix($val)',
7472
7701
  },
@@ -8229,13 +8458,27 @@ sub HandleItemInfo($)
8229
8458
  my ($start, $subTable, $proc);
8230
8459
  my $pos = $$item{Extents}[0][1] + $base;
8231
8460
  if ($name eq 'EXIF' and length $buff >= 4) {
8232
- my $n = unpack('N', $buff);
8233
- $start = 4 + $n; # skip "Exif\0\0" header if it exists
8234
- $subTable = GetTagTable('Image::ExifTool::Exif::Main');
8235
- if ($$et{HTML_DUMP}) {
8236
- $et->HDump($pos, 4, 'Exif header length', "Value: $n");
8237
- $et->HDump($pos+4, $start-4, 'Exif header') if $n;
8461
+ if ($buff =~ /^(MM\0\x2a|II\x2a\0)/) {
8462
+ $et->Warn('Missing Exif header');
8463
+ $start = 0;
8464
+ } elsif ($buff =~ /^Exif\0\0/) {
8465
+ # (haven't seen this yet, but it is just a matter of time
8466
+ # until someone screws it up like this)
8467
+ $et->Warn('Missing Exif header size');
8468
+ $start = 6;
8469
+ } else {
8470
+ my $n = unpack('N', $buff);
8471
+ $start = 4 + $n; # skip "Exif\0\0" header if it exists
8472
+ if ($start > length($buff)) {
8473
+ $et->Warn('Invalid EXIF header');
8474
+ next;
8475
+ }
8476
+ if ($$et{HTML_DUMP}) {
8477
+ $et->HDump($pos, 4, 'Exif header length', "Value: $n");
8478
+ $et->HDump($pos+4, $start-4, 'Exif header') if $n;
8479
+ }
8238
8480
  }
8481
+ $subTable = GetTagTable('Image::ExifTool::Exif::Main');
8239
8482
  $proc = \&Image::ExifTool::ProcessTIFF;
8240
8483
  } else {
8241
8484
  $start = 0;
@@ -8287,7 +8530,7 @@ sub EEWarn($)
8287
8530
  #------------------------------------------------------------------------------
8288
8531
  # Get quicktime format from flags word
8289
8532
  # Inputs: 0) quicktime atom flags, 1) data length
8290
- # Returns: Exiftool format string
8533
+ # Returns: ExifTool format string
8291
8534
  sub QuickTimeFormat($$)
8292
8535
  {
8293
8536
  my ($flags, $len) = @_;
@@ -8514,7 +8757,7 @@ sub ProcessKeys($$$)
8514
8757
  my $ns = substr($$dataPt, $pos + 4, 4);
8515
8758
  my $tag = substr($$dataPt, $pos + 8, $len - 8);
8516
8759
  $tag =~ s/\0.*//s; # truncate at null
8517
- $tag =~ s/^com\.apple\.quicktime\.// if $ns eq 'mdta'; # remove apple quicktime domain
8760
+ $tag =~ s/^com\.(apple\.quicktime\.)?// if $ns eq 'mdta'; # remove apple quicktime domain
8518
8761
  $tag = "Tag_$ns" unless $tag;
8519
8762
  # (I have some samples where the tag is a reversed ItemList or UserData tag ID)
8520
8763
  my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
@@ -8546,9 +8789,10 @@ sub ProcessKeys($$$)
8546
8789
  $$newInfo{Groups} = $groups ? { %$groups } : { };
8547
8790
  $$newInfo{Groups}{$_} or $$newInfo{Groups}{$_} = $$tagTablePtr{GROUPS}{$_} foreach 0..2;
8548
8791
  $$newInfo{Groups}{1} = 'Keys';
8549
- } elsif ($tag =~ /^[-\w. ]+$/) {
8792
+ } elsif ($tag =~ /^[-\w. ]+$/ or $tag =~ /\w{4}/) {
8550
8793
  # create info for tags with reasonable id's
8551
8794
  my $name = ucfirst $tag;
8795
+ $name =~ tr/-0-9a-zA-Z_. //dc;
8552
8796
  $name =~ s/[. ]+(.?)/\U$1/g;
8553
8797
  $name =~ s/_([a-z])/_\U$1/g;
8554
8798
  $name =~ s/([a-z])_([A-Z])/$1$2/g;
@@ -8569,7 +8813,7 @@ sub ProcessKeys($$$)
8569
8813
  if ($newInfo) {
8570
8814
  AddTagToTable($itemList, $id, $newInfo);
8571
8815
  $msg or $msg = '';
8572
- $out and print $out "$$et{INDENT}Added ItemList Tag $id = $tag$msg\n";
8816
+ $out and print $out "$$et{INDENT}Added ItemList Tag $id = ($ns) $tag$msg\n";
8573
8817
  }
8574
8818
  $pos += $len;
8575
8819
  ++$index;
@@ -9024,10 +9268,10 @@ ItemID: foreach $id (keys %$items) {
9024
9268
  }
9025
9269
  }
9026
9270
  if ($ctry or $lang) {
9027
- $lang = GetLangCode($lang, $ctry);
9028
- if ($lang) {
9271
+ my $langCode = GetLangCode($lang, $ctry);
9272
+ if ($langCode) {
9029
9273
  # get tagInfo for other language
9030
- $langInfo = GetLangInfoQT($et, $tagInfo, $lang);
9274
+ $langInfo = GetLangInfoQT($et, $tagInfo, $langCode);
9031
9275
  # save other language tag ID's so we can delete later if necessary
9032
9276
  if ($langInfo) {
9033
9277
  $$tagInfo{OtherLang} or $$tagInfo{OtherLang} = [ ];
@@ -9044,7 +9288,7 @@ ItemID: foreach $id (keys %$items) {
9044
9288
  Size => $len,
9045
9289
  Format => $format,
9046
9290
  Index => $index,
9047
- Extra => sprintf(", Type='${type}', Flags=0x%x%s",$flags,($lang ? ", Lang=$lang" : '')),
9291
+ Extra => sprintf(", Type='${type}', Flags=0x%x, Lang=0x%.4x",$flags,$lang),
9048
9292
  ) if $verbose;
9049
9293
  # use "Keys" in path instead of ItemList if this was defined by a Keys tag
9050
9294
  my $isKey = $$tagInfo{Groups} && $$tagInfo{Groups}{1} && $$tagInfo{Groups}{1} eq 'Keys';