exiftool_vendored 12.16.0 → 12.25.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +137 -1
  3. data/bin/MANIFEST +12 -0
  4. data/bin/META.json +1 -1
  5. data/bin/META.yml +1 -1
  6. data/bin/README +44 -43
  7. data/bin/config_files/acdsee.config +193 -6
  8. data/bin/config_files/cuepointlist.config +70 -0
  9. data/bin/config_files/example.config +1 -8
  10. data/bin/exiftool +139 -98
  11. data/bin/fmt_files/gpx.fmt +1 -1
  12. data/bin/fmt_files/gpx_wpt.fmt +1 -1
  13. data/bin/fmt_files/kml.fmt +1 -1
  14. data/bin/fmt_files/kml_track.fmt +1 -1
  15. data/bin/lib/Image/ExifTool.pm +158 -49
  16. data/bin/lib/Image/ExifTool.pod +94 -75
  17. data/bin/lib/Image/ExifTool/Apple.pm +3 -2
  18. data/bin/lib/Image/ExifTool/BuildTagLookup.pm +25 -14
  19. data/bin/lib/Image/ExifTool/Canon.pm +28 -3
  20. data/bin/lib/Image/ExifTool/CanonCustom.pm +19 -1
  21. data/bin/lib/Image/ExifTool/DJI.pm +6 -6
  22. data/bin/lib/Image/ExifTool/DjVu.pm +6 -5
  23. data/bin/lib/Image/ExifTool/Exif.pm +50 -22
  24. data/bin/lib/Image/ExifTool/FITS.pm +13 -2
  25. data/bin/lib/Image/ExifTool/FujiFilm.pm +19 -8
  26. data/bin/lib/Image/ExifTool/GPS.pm +24 -13
  27. data/bin/lib/Image/ExifTool/H264.pm +20 -5
  28. data/bin/lib/Image/ExifTool/ICC_Profile.pm +2 -2
  29. data/bin/lib/Image/ExifTool/JPEG.pm +6 -2
  30. data/bin/lib/Image/ExifTool/JSON.pm +24 -3
  31. data/bin/lib/Image/ExifTool/Jpeg2000.pm +361 -16
  32. data/bin/lib/Image/ExifTool/M2TS.pm +40 -4
  33. data/bin/lib/Image/ExifTool/MIE.pm +2 -2
  34. data/bin/lib/Image/ExifTool/MRC.pm +341 -0
  35. data/bin/lib/Image/ExifTool/MWG.pm +3 -3
  36. data/bin/lib/Image/ExifTool/MXF.pm +1 -1
  37. data/bin/lib/Image/ExifTool/MacOS.pm +1 -1
  38. data/bin/lib/Image/ExifTool/Microsoft.pm +298 -82
  39. data/bin/lib/Image/ExifTool/Nikon.pm +5 -5
  40. data/bin/lib/Image/ExifTool/NikonSettings.pm +25 -16
  41. data/bin/lib/Image/ExifTool/Olympus.pm +2 -2
  42. data/bin/lib/Image/ExifTool/PNG.pm +2 -2
  43. data/bin/lib/Image/ExifTool/Panasonic.pm +14 -1
  44. data/bin/lib/Image/ExifTool/PhaseOne.pm +4 -3
  45. data/bin/lib/Image/ExifTool/QuickTime.pm +148 -68
  46. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +94 -34
  47. data/bin/lib/Image/ExifTool/README +5 -4
  48. data/bin/lib/Image/ExifTool/RIFF.pm +84 -12
  49. data/bin/lib/Image/ExifTool/Samsung.pm +2 -1
  50. data/bin/lib/Image/ExifTool/Shortcuts.pm +9 -0
  51. data/bin/lib/Image/ExifTool/Sony.pm +157 -49
  52. data/bin/lib/Image/ExifTool/TagInfoXML.pm +1 -0
  53. data/bin/lib/Image/ExifTool/TagLookup.pm +4079 -3987
  54. data/bin/lib/Image/ExifTool/TagNames.pod +642 -273
  55. data/bin/lib/Image/ExifTool/WriteExif.pl +1 -1
  56. data/bin/lib/Image/ExifTool/WritePostScript.pl +1 -0
  57. data/bin/lib/Image/ExifTool/WriteQuickTime.pl +44 -17
  58. data/bin/lib/Image/ExifTool/WriteXMP.pl +15 -8
  59. data/bin/lib/Image/ExifTool/Writer.pl +50 -14
  60. data/bin/lib/Image/ExifTool/XMP.pm +50 -11
  61. data/bin/perl-Image-ExifTool.spec +42 -42
  62. data/lib/exiftool_vendored/version.rb +1 -1
  63. metadata +52 -12
@@ -62,7 +62,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
62
62
  use Image::ExifTool::Exif;
63
63
  use Image::ExifTool::GPS;
64
64
 
65
- $VERSION = '3.92';
65
+ $VERSION = '3.95';
66
66
 
67
67
  sub LensIDConv($$$);
68
68
  sub ProcessNikonAVI($$$);
@@ -563,7 +563,7 @@ sub GetAFPointGrid($$;$);
563
563
  'F0 3F 2D 8A 2C 40 DF 0E' => 'Tamron AF 18-270mm f/3.5-6.3 Di II VC PZD (B008)',
564
564
  'E0 40 2D 98 2C 41 DF 4E' => 'Tamron 18-400mm f/3.5-6.3 Di II VC HLD (B028)', # (removed AF designation, ref 37)
565
565
  '07 40 2F 44 2C 34 03 02' => 'Tamron AF 19-35mm f/3.5-4.5 (A10)',
566
- '07 40 30 45 2D 35 03 02' => 'Tamron AF 19-35mm f/3.5-4.5 (A10)',
566
+ '07 40 30 45 2D 35 03 02.1' => 'Tamron AF 19-35mm f/3.5-4.5 (A10)',
567
567
  '00 49 30 48 22 2B 00 02' => 'Tamron SP AF 20-40mm f/2.7-3.5 (166D)',
568
568
  '0E 4A 31 48 23 2D 0E 02' => 'Tamron SP AF 20-40mm f/2.7-3.5 (166D)',
569
569
  'FE 48 37 5C 24 24 DF 0E' => 'Tamron SP 24-70mm f/2.8 Di VC USD (A007)', #24
@@ -640,6 +640,7 @@ sub GetAFPointGrid($$;$);
640
640
  '24 44 60 98 34 3C 1A 02' => 'Tokina AT-X 840 AF-II (AF 80-400mm f/4.5-5.6)',
641
641
  '00 44 60 98 34 3C 00 02' => 'Tokina AT-X 840 D (AF 80-400mm f/4.5-5.6)',
642
642
  '14 48 68 8E 30 30 0B 00' => 'Tokina AT-X 340 AF (AF 100-300mm f/4)',
643
+ '8C 48 29 3C 24 24 86 06' => 'Tokina opera 16-28mm F2.8 FF', #30
643
644
  #
644
645
  '06 3F 68 68 2C 2C 06 00' => 'Cosina AF 100mm F3.5 Macro',
645
646
  '07 36 3D 5F 2C 3C 03 00' => 'Cosina AF Zoom 28-80mm F3.5-5.6 MC Macro',
@@ -655,6 +656,7 @@ sub GetAFPointGrid($$;$);
655
656
  '00 54 48 48 18 18 00 00' => 'Voigtlander Ultron 40mm F2 SLII Aspherical',
656
657
  '00 54 55 55 0C 0C 00 00' => 'Voigtlander Nokton 58mm F1.4 SLII',
657
658
  '00 40 64 64 2C 2C 00 00' => 'Voigtlander APO-Lanthar 90mm F3.5 SLII Close Focus',
659
+ '07 40 30 45 2D 35 03 02.2' => 'Voigtlander Ultragon 19-35mm F3.5-4.5 VMV', #NJ
658
660
  #
659
661
  '00 40 2D 2D 2C 2C 00 00' => 'Carl Zeiss Distagon T* 3.5/18 ZF.2',
660
662
  '00 48 27 27 24 24 00 00' => 'Carl Zeiss Distagon T* 2.8/15 ZF.2', #MykytaKozlov
@@ -9945,12 +9947,10 @@ sub PrescanExif($$$)
9945
9947
  $dataLen = length $data;
9946
9948
  $dirStart = 0;
9947
9949
  }
9948
- # loop through necessary IFD entries
9949
- my ($lastTag) = sort { $b <=> $a } keys %$tagHash; # (reverse sort)
9950
+ # loop through Nikon MakerNote IFD entries
9950
9951
  for ($index=0; $index<$numEntries; ++$index) {
9951
9952
  my $entry = $dirStart + 2 + 12 * $index;
9952
9953
  my $tagID = Get16u($dataPt, $entry);
9953
- last if $tagID > $lastTag; # (assuming tags are in order)
9954
9954
  next unless exists $$tagHash{$tagID}; # only extract required tags
9955
9955
  my $format = Get16u($dataPt, $entry+2);
9956
9956
  next if $format < 1 or $format > 13;
@@ -17,7 +17,7 @@ use strict;
17
17
  use vars qw($VERSION);
18
18
  use Image::ExifTool qw(:DataAccess :Utils);
19
19
 
20
- $VERSION = '1.00';
20
+ $VERSION = '1.03';
21
21
 
22
22
  sub ProcessNikonSettings($$$);
23
23
 
@@ -911,14 +911,14 @@ my %infoD6 = (
911
911
  },
912
912
  0x05a => [{ # CSf6-b-1 and CSf6-b-2 (D6), CSf5-b-1 and CSf5-b-2 (Z7_2), (continued from above)
913
913
  Name => 'CmdDialsChangeMainSub',
914
- Condition => '$$self{CmdDialsChangeMainSubExposure} == 1',
914
+ Condition => '$$self{CmdDialsChangeMainSubExposure} and $$self{CmdDialsChangeMainSubExposure} == 1',
915
915
  PrintConv => {
916
916
  1 => 'Autofocus On, Exposure On',
917
917
  2 => 'Autofocus Off, Exposure On',
918
918
  },
919
919
  },{
920
920
  Name => 'CmdDialsChangeMainSub',
921
- Condition => '$$self{CmdDialsChangeMainSubExposure} == 2',
921
+ Condition => '$$self{CmdDialsChangeMainSubExposure} and $$self{CmdDialsChangeMainSubExposure} == 2',
922
922
  PrintConv => {
923
923
  1 => 'Autofocus On, Exposure On (Mode A)',
924
924
  2 => 'Autofocus Off, Exposure On (Mode A)',
@@ -1014,7 +1014,7 @@ my %infoD6 = (
1014
1014
  }],
1015
1015
  0x08b => [{ # CSf6-a-1 and CSf6-a-2 (D6), CSf5-a-1 and CSf5-a-2 (Z7_2), (continued from above)
1016
1016
  Name => 'CmdDialsReverseRotation',
1017
- Condition => '$$self{CmdDialsReverseRotExposureComp} == 1',
1017
+ Condition => '$$self{CmdDialsReverseRotExposureComp} and $$self{CmdDialsReverseRotExposureComp} == 1',
1018
1018
  PrintConv => {
1019
1019
  1 => 'No',
1020
1020
  2 => 'Shutter Speed & Aperture',
@@ -1283,7 +1283,7 @@ my %infoD6 = (
1283
1283
  PrintConv => {
1284
1284
  1 => 'Enable',
1285
1285
  2 => 'Enable (Standby Timer Active)',
1286
- 3 => 'Diaable',
1286
+ 3 => 'Disable',
1287
1287
  },
1288
1288
  },
1289
1289
  0x0ab => { # CSf11 (D6)
@@ -1313,7 +1313,7 @@ my %infoD6 = (
1313
1313
  1 => 'Power Aperture (Open)',
1314
1314
  2 => 'Exposure Compensation',
1315
1315
  3 => 'Subject Tracking',
1316
- 4 => 'LiveView Info Display On/Off)',
1316
+ 4 => 'LiveView Info Display On/Off',
1317
1317
  5 => 'Grid Display',
1318
1318
  6 => 'Zoom (Low)',
1319
1319
  7 => 'Zoom (1:1)',
@@ -1357,7 +1357,7 @@ my %infoD6 = (
1357
1357
  1 => 'Power Aperture (Close)',
1358
1358
  2 => 'Exposure Compensation',
1359
1359
  3 => 'Subject Tracking',
1360
- 4 => 'LiveView Info Display On/Off)',
1360
+ 4 => 'LiveView Info Display On/Off',
1361
1361
  5 => 'Grid Display',
1362
1362
  6 => 'Zoom (Low)',
1363
1363
  7 => 'Zoom (1:1)',
@@ -1545,10 +1545,10 @@ my %infoD6 = (
1545
1545
  12 => 'None',
1546
1546
  },
1547
1547
  },
1548
- 0x0fb => { Name => 'SecondarySlotFunction', PrintConv => \%tagSecondarySlotFunction }, # tag name selected to maintain compatibility with older cameras # (Z7_2)
1549
- 0x0fb => { Name => 'SecondarySlotFunction', PrintConv => \%tagSecondarySlotFunction }, # (D6)
1550
- 0x0fc => { Name => 'SilentPhotography', PrintConv => \%onOff }, # (D6,Z7_2) # tag is associated with Silent LiveView Photography (as distinguisehed from Silent Interval or Silent Focus Shift)
1551
- 0x0fd => { Name => 'ExtendedShuttterSpeeds', PrintConv => \%onOff }, # CSd7 (D6), CSd6 (Z7_2)
1548
+ 0x0fb => { Name => 'SecondarySlotFunction', PrintConv => \%tagSecondarySlotFunction }, # tag name selected to maintain compatibility with older cameras # (Z7_2)
1549
+ 0x0fb => { Name => 'SecondarySlotFunction', PrintConv => \%tagSecondarySlotFunction }, # (D6)
1550
+ 0x0fc => { Name => 'SilentPhotography', PrintConv => \%onOff }, # (D6,Z7_2) # tag is associated with Silent LiveView Photography (as distinguisehed from Silent Interval or Silent Focus Shift)
1551
+ 0x0fd => { Name => 'ExtendedShutterSpeeds', PrintConv => \%onOff }, # CSd7 (D6), CSd6 (Z7_2)
1552
1552
  0x109 => { # (D6,Z7_2)
1553
1553
  Name => 'BracketSet',
1554
1554
  RawConv => '$$self{BracketSet} = $val',
@@ -1578,7 +1578,7 @@ my %infoD6 = (
1578
1578
  },
1579
1579
  },{
1580
1580
  Name => 'BracketProgram',
1581
- Condition => '$$self{BracketSet} == 4',
1581
+ Condition => '$$self{BracketSet} and $$self{BracketSet} == 4',
1582
1582
  Notes => 'White Balance Bracketing',
1583
1583
  RawConv => '$$self{BracketProgram} = $val',
1584
1584
  PrintConv => {
@@ -1595,7 +1595,7 @@ my %infoD6 = (
1595
1595
  },
1596
1596
  },{
1597
1597
  Name => 'BracketProgram',
1598
- Condition => '$$self{BracketSet} == 5',
1598
+ Condition => '$$self{BracketSet} and $$self{BracketSet} == 5',
1599
1599
  Notes => 'Active-D Bracketing',
1600
1600
  RawConv => '$$self{BracketProgram} = $val',
1601
1601
  Mask => 0x0f,
@@ -1802,9 +1802,9 @@ my %infoD6 = (
1802
1802
  },
1803
1803
  },
1804
1804
  0x139 => { Name => 'PlaybackFlickUp', RawConv => '$$self{PlaybackFlickUp} = $val', PrintConv => \%flickUpDownD6 }, # CSf12-1-a # (D6)
1805
- 0x13a => { Name => 'PlaybackFlickUpRating', Condition => '$$self{PlaybackFlickUp} == 1', Notes => 'Meaningful only when PlaybackFlickUp is Rating', PrintConv => \%flickUpDownRatingD6 }, # CSf12-1-b # (D6)
1805
+ 0x13a => { Name => 'PlaybackFlickUpRating', Condition => '$$self{PlaybackFlickUp} and $$self{PlaybackFlickUp} == 1', Notes => 'Meaningful only when PlaybackFlickUp is Rating', PrintConv => \%flickUpDownRatingD6 }, # CSf12-1-b # (D6)
1806
1806
  0x13b => { Name => 'PlaybackFlickDown', RawConv => '$$self{PlaybackFlickDown} = $val', PrintConv => \%flickUpDownD6 }, # CSf12-2-a # (D6)
1807
- 0x13c => { Name => 'PlaybackFlickDownRating', Condition => '$$self{PlaybackFlickDown} == 1', Notes => 'Meaningful only when PlaybackFlickDown is Rating', PrintConv => \%flickUpDownRatingD6 }, # CSf12-2-b # (D6)
1807
+ 0x13c => { Name => 'PlaybackFlickDownRating', Condition => '$$self{PlaybackFlickDown} and $$self{PlaybackFlickDown} == 1', Notes => 'Meaningful only when PlaybackFlickDown is Rating', PrintConv => \%flickUpDownRatingD6 }, # CSf12-2-b # (D6)
1808
1808
  0x13d => { # CSg2-d (D6)
1809
1809
  Name => 'MovieFunc3Button',
1810
1810
  PrintConv => {
@@ -1875,7 +1875,7 @@ my %infoD6 = (
1875
1875
  0x164 => { # CSg7-a (Z7_2)
1876
1876
  Name => 'VerticalMovieFuncButton',
1877
1877
  PrintConv => {
1878
- 1 => 'LiveView Info Display On/Off)',
1878
+ 1 => 'LiveView Info Display On/Off',
1879
1879
  2 => 'Record Movies',
1880
1880
  3 => 'Exposure Compensation',
1881
1881
  4 => 'ISO',
@@ -1919,6 +1919,15 @@ my %infoD6 = (
1919
1919
  10 => 'Auto (Animals)',
1920
1920
  },
1921
1921
  },
1922
+ 0x170 => { Name => 'PreferSubSelectorCenter', PrintConv => \%offOn }, # CSf13 (D6 firmware v1.2.0)
1923
+ 0x174 => { # CSa17-d (D6 firmware v1.2.0)
1924
+ Name => 'FocusPointSelectionSpeed',
1925
+ PrintConv => {
1926
+ 1 => 'Normal',
1927
+ 2 => 'High',
1928
+ 3 => 'Very High',
1929
+ },
1930
+ },
1922
1931
  );
1923
1932
 
1924
1933
  #------------------------------------------------------------------------------
@@ -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.70';
43
+ $VERSION = '2.71';
44
44
 
45
45
  sub PrintLensInfo($$$);
46
46
 
@@ -3952,7 +3952,7 @@ my %indexInfo = (
3952
3952
  1 => 'LensTypeModel',
3953
3953
  },
3954
3954
  Notes => 'based on tags found in some Panasonic RW2 images',
3955
- SeparateTable => 'LensType',
3955
+ SeparateTable => 'Olympus LensType',
3956
3956
  ValueConv => '"$val[0] $val[1]"',
3957
3957
  PrintConv => \%olympusLensTypes,
3958
3958
  },
@@ -36,7 +36,7 @@ use strict;
36
36
  use vars qw($VERSION $AUTOLOAD %stdCase);
37
37
  use Image::ExifTool qw(:DataAccess :Utils);
38
38
 
39
- $VERSION = '1.56';
39
+ $VERSION = '1.57';
40
40
 
41
41
  sub ProcessPNG_tEXt($$$);
42
42
  sub ProcessPNG_iTXt($$$);
@@ -975,7 +975,7 @@ sub FoundPNG($$$$;$$$$)
975
975
  $$tagInfo{LangCode} = $lang if $lang;
976
976
  # make unknown profiles binary data type
977
977
  $$tagInfo{Binary} = 1 if $tag =~ /^Raw profile type /;
978
- $verbose and $et->VPrint(0, " | [adding $tag]\n");
978
+ $verbose and $et->VPrint(0, " [adding $tag]\n");
979
979
  AddTagToTable($tagTablePtr, $tag, $tagInfo);
980
980
  }
981
981
  #
@@ -2118,6 +2118,7 @@ my %shootingMode = (
2118
2118
  Name => 'UserProfile',
2119
2119
  Writable => 'string',
2120
2120
  },
2121
+ # 0x357 int32u - 0=DNG, 3162=JPG (ref 23)
2121
2122
  0x359 => { #23
2122
2123
  Name => 'ISOSelected',
2123
2124
  Writable => 'int32s',
@@ -2134,7 +2135,19 @@ my %shootingMode = (
2134
2135
  PrintConv => 'sprintf("%.1f", $val)',
2135
2136
  PrintConvInv => '$val',
2136
2137
  },
2137
- # 0x357 int32u - 0=DNG, 3162=JPG (ref 23)
2138
+ 0x035b => { #IB
2139
+ Name => 'CorrelatedColorTemp', # (in Kelvin)
2140
+ Writable => 'int16u',
2141
+ },
2142
+ 0x035c => { #IB
2143
+ Name => 'ColorTint', # (same units as Adobe is using)
2144
+ Writable => 'int16s',
2145
+ },
2146
+ 0x035d => { #IB
2147
+ Name => 'WhitePoint', # (x/y)
2148
+ Writable => 'rational64u',
2149
+ Count => 2,
2150
+ },
2138
2151
  );
2139
2152
 
2140
2153
  # Type 2 tags (ref PH)
@@ -15,7 +15,7 @@ use vars qw($VERSION);
15
15
  use Image::ExifTool qw(:DataAccess :Utils);
16
16
  use Image::ExifTool::Exif;
17
17
 
18
- $VERSION = '1.06';
18
+ $VERSION = '1.07';
19
19
 
20
20
  sub WritePhaseOne($$$);
21
21
  sub ProcessPhaseOne($$$);
@@ -73,10 +73,11 @@ my @formatName = ( undef, 'string', 'int16s', undef, 'int32s' );
73
73
  PrintConv => { #PH
74
74
  1 => 'RAW 1', #? (encrypted)
75
75
  2 => 'RAW 2', #? (encrypted)
76
- 3 => 'IIQ L',
76
+ 3 => 'IIQ L', # (now "L14", ref IB)
77
77
  # 4?
78
78
  5 => 'IIQ S',
79
- 6 => 'IIQ Sv2',
79
+ 6 => 'IIQ Sv2', # (now "S14" for "IIQ 14 Smart" and "IIQ 14 Sensor+", ref IB)
80
+ 8 => 'IIQ L16', #IB ("IIQ 16 Extended" and "IIQ 16 Large")
80
81
  },
81
82
  },
82
83
  0x010f => {
@@ -47,7 +47,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
47
47
  use Image::ExifTool::Exif;
48
48
  use Image::ExifTool::GPS;
49
49
 
50
- $VERSION = '2.57';
50
+ $VERSION = '2.63';
51
51
 
52
52
  sub ProcessMOV($$;$);
53
53
  sub ProcessKeys($$$);
@@ -65,6 +65,7 @@ sub Process_gsen($$$);
65
65
  sub ProcessRIFFTrailer($$$);
66
66
  sub ProcessTTAD($$$);
67
67
  sub ProcessNMEA($$$);
68
+ sub ProcessGPSLog($$$);
68
69
  sub SaveMetaKeys($$$);
69
70
  # ++^^^^^^^^^^^^++
70
71
  sub ParseItemLocation($$);
@@ -160,8 +161,15 @@ my %ftypLookup = (
160
161
  'F4P ' => 'Protected Video for Adobe Flash Player 9+ (.F4P)', # video/mp4
161
162
  'F4V ' => 'Video for Adobe Flash Player 9+ (.F4V)', # video/mp4
162
163
  'isc2' => 'ISMACryp 2.0 Encrypted File', # ?/enc-isoff-generic
163
- 'iso2' => 'MP4 Base Media v2 [ISO 14496-12:2005]', # video/mp4
164
- 'isom' => 'MP4 Base Media v1 [IS0 14496-12:2003]', # video/mp4
164
+ 'iso2' => 'MP4 Base Media v2 [ISO 14496-12:2005]', # video/mp4 (or audio)
165
+ 'iso3' => 'MP4 Base Media v3', # video/mp4 (or audio)
166
+ 'iso4' => 'MP4 Base Media v4', # video/mp4 (or audio)
167
+ 'iso5' => 'MP4 Base Media v5', # video/mp4 (or audio)
168
+ 'iso6' => 'MP4 Base Media v6', # video/mp4 (or audio)
169
+ 'iso7' => 'MP4 Base Media v7', # video/mp4 (or audio)
170
+ 'iso8' => 'MP4 Base Media v8', # video/mp4 (or audio)
171
+ 'iso9' => 'MP4 Base Media v9', # video/mp4 (or audio)
172
+ 'isom' => 'MP4 Base Media v1 [IS0 14496-12:2003]', # video/mp4 (or audio)
165
173
  'JP2 ' => 'JPEG 2000 Image (.JP2) [ISO 15444-1 ?]', # image/jp2
166
174
  'JP20' => 'Unknown, from GPAC samples (prob non-existent)',
167
175
  'jpm ' => 'JPEG 2000 Compound Image (.JPM) [ISO 15444-6]', # image/jpm
@@ -243,7 +251,11 @@ my %timeInfo = (
243
251
  },
244
252
  # (all CR3 files store UTC times - PH)
245
253
  ValueConv => 'ConvertUnixTime($val, $self->Options("QuickTimeUTC") || $$self{FileType} eq "CR3")',
246
- ValueConvInv => 'GetUnixTime($val, $self->Options("QuickTimeUTC")) + (66 * 365 + 17) * 24 * 3600',
254
+ ValueConvInv => q{
255
+ $val = GetUnixTime($val, $self->Options("QuickTimeUTC"));
256
+ return undef unless defined $val;
257
+ return $val + (66 * 365 + 17) * 24 * 3600;
258
+ },
247
259
  PrintConv => '$self->ConvertDateTime($val)',
248
260
  PrintConvInv => '$self->InverseDateTime($val)',
249
261
  # (can't put Groups here because they aren't constant!)
@@ -258,11 +270,15 @@ my %unknownInfo = (
258
270
  Unknown => 1,
259
271
  ValueConv => '$val =~ /^([\x20-\x7e]*)\0*$/ ? $1 : \$val',
260
272
  );
273
+
274
+ # multi-language text with 6-byte header
275
+ my %langText = ( IText => 6 );
276
+
261
277
  # parsing for most of the 3gp udta language text boxes
262
- my %langText = (
278
+ my %langText3gp = (
263
279
  Notes => 'used in 3gp videos',
264
- IText => 6,
265
280
  Avoid => 1,
281
+ IText => 6,
266
282
  );
267
283
 
268
284
  # 4-character Vendor ID codes (ref PH)
@@ -670,6 +686,15 @@ my %eeBox2 = (
670
686
  udat => { #PH (GPS NMEA-format log written by Datakam Player software)
671
687
  Name => 'GPSLog',
672
688
  Binary => 1, # (actually ASCII, but very lengthy)
689
+ Notes => 'parsed to extract GPS separately when ExtractEmbedded is used',
690
+ RawConv => q{
691
+ $val =~ s/\0+$//; # remove trailing nulls
692
+ if (length $val and $$self{OPTIONS}{ExtractEmbedded}) {
693
+ my $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream');
694
+ Image::ExifTool::QuickTime::ProcessGPSLog($self, { DataPt => \$val }, $tagTbl);
695
+ }
696
+ return $val;
697
+ },
673
698
  },
674
699
  # meta - proprietary XML information written by some Flip cameras - PH
675
700
  # beam - 16 bytes found in an iPhone video
@@ -1545,47 +1570,43 @@ my %eeBox2 = (
1545
1570
  # the following are 3gp tags, references:
1546
1571
  # http://atomicparsley.sourceforge.net
1547
1572
  # http://www.3gpp.org/ftp/tsg_sa/WG4_CODEC/TSGS4_25/Docs/
1548
- # (note that all %langText tags are Avoid => 1)
1549
- cprt => { Name => 'Copyright', %langText, Groups => { 2 => 'Author' } },
1550
- auth => { Name => 'Author', %langText, Groups => { 2 => 'Author' } },
1551
- titl => { Name => 'Title', %langText },
1552
- dscp => { Name => 'Description',%langText },
1553
- perf => { Name => 'Performer', %langText },
1554
- gnre => { Name => 'Genre', %langText },
1555
- albm => { Name => 'Album', %langText },
1556
- coll => { Name => 'CollectionName', %langText }, #17
1573
+ # (note that all %langText3gp tags are Avoid => 1)
1574
+ cprt => { Name => 'Copyright', %langText3gp, Groups => { 2 => 'Author' } },
1575
+ auth => { Name => 'Author', %langText3gp, Groups => { 2 => 'Author' } },
1576
+ titl => { Name => 'Title', %langText3gp },
1577
+ dscp => { Name => 'Description',%langText3gp },
1578
+ perf => { Name => 'Performer', %langText3gp },
1579
+ gnre => { Name => 'Genre', %langText3gp },
1580
+ albm => { Name => 'Album', %langText3gp },
1581
+ coll => { Name => 'CollectionName', %langText3gp }, #17
1557
1582
  rtng => {
1558
1583
  Name => 'Rating',
1584
+ Writable => 'undef',
1585
+ Avoid => 1,
1559
1586
  # (4-byte flags, 4-char entity, 4-char criteria, 2-byte lang, string)
1560
- RawConv => q{
1561
- return '<err>' unless length $val >= 14;
1562
- my $str = 'Entity=' . substr($val,4,4) . ' Criteria=' . substr($val,8,4);
1563
- $str =~ tr/\0-\x1f\x7f-\xff//d; # remove unprintable characters
1564
- my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 12));
1565
- $lang = $lang ? "($lang) " : '';
1566
- $val = substr($val, 14);
1567
- $val = $self->Decode($val, 'UCS2') if $val =~ /^\xfe\xff/;
1568
- return $lang . $str . ' ' . $val;
1569
- },
1587
+ IText => 14, # (14 bytes before string)
1588
+ Notes => 'string in the form "Entity=XXXX Criteria=XXXX XXXXX", used in 3gp videos',
1589
+ ValueConv => '$val=~s/^(.{4})(.{4})/Entity=$1 Criteria=$2 /i; $val',
1590
+ ValueConvInv => '$val=~s/Entity=(.{4}) Criteria=(.{4}) ?/$1$2/i; $val',
1570
1591
  },
1571
1592
  clsf => {
1572
1593
  Name => 'Classification',
1594
+ Writable => 'undef',
1595
+ Avoid => 1,
1573
1596
  # (4-byte flags, 4-char entity, 2-byte index, 2-byte lang, string)
1574
- RawConv => q{
1575
- return '<err>' unless length $val >= 12;
1576
- my $str = 'Entity=' . substr($val,4,4) . ' Index=' . Get16u(\$val,8);
1577
- $str =~ tr/\0-\x1f\x7f-\xff//d; # remove unprintable characters
1578
- my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 10));
1579
- $lang = $lang ? "($lang) " : '';
1580
- $val = substr($val, 12);
1581
- $val = $self->Decode($val, 'UCS2') if $val =~ /^\xfe\xff/;
1582
- return $lang . $str . ' ' . $val;
1583
- },
1597
+ IText => 12,
1598
+ Notes => 'string in the form "Entity=XXXX Index=### XXXXX", used in 3gp videos',
1599
+ ValueConv => '$val=~s/^(.{4})(.{2})/"Entity=$1 Index=".unpack("n",$2)." "/ie; $val',
1600
+ ValueConvInv => '$val=~s/Entity=(.{4}) Index=(\d+) ?/$1.pack("n",$2)/ie; $val',
1584
1601
  },
1585
1602
  kywd => {
1586
1603
  Name => 'Keywords',
1587
- # (4 byte flags, 2-byte lang, 1-byte count, count x pascal strings)
1604
+ # (4 byte flags, 2-byte lang, 1-byte count, count x pascal strings, ref 17)
1605
+ # (but I have also seen a simple string written by iPhone, so don't make writable yet)
1606
+ Notes => "not writable because Apple doesn't follow the 3gp specification",
1588
1607
  RawConv => q{
1608
+ my $sep = $self->Options('ListSep');
1609
+ return join($sep, split /\0+/, $val) unless $val =~ /^\0/; # (iPhone)
1589
1610
  return '<err>' unless length $val >= 7;
1590
1611
  my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 4));
1591
1612
  $lang = $lang ? "($lang) " : '';
@@ -1601,27 +1622,30 @@ my %eeBox2 = (
1601
1622
  push @vals, $v;
1602
1623
  $pos += $len;
1603
1624
  }
1604
- my $sep = $self->Options('ListSep');
1605
1625
  return $lang . join($sep, @vals);
1606
1626
  },
1607
1627
  },
1608
1628
  loci => {
1609
1629
  Name => 'LocationInformation',
1610
1630
  Groups => { 2 => 'Location' },
1631
+ Writable => 'undef',
1632
+ IText => 6,
1633
+ Avoid => 1,
1634
+ NoDecode => 1, # (we'll decode the data ourself)
1635
+ Notes => q{
1636
+ string in the form "XXXXX Role=XXX Lat=XXX Lon=XXX Alt=XXX Body=XXX
1637
+ Notes=XXX", used in 3gp videos
1638
+ },
1611
1639
  # (4-byte flags, 2-byte lang, location string, 1-byte role, 4-byte fixed longitude,
1612
1640
  # 4-byte fixed latitude, 4-byte fixed altitude, body string, notes string)
1613
1641
  RawConv => q{
1614
- return '<err>' unless length $val >= 6;
1615
- my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 4));
1616
- $lang = $lang ? "($lang) " : '';
1617
- $val = substr($val, 6);
1618
1642
  my $str;
1619
1643
  if ($val =~ /^\xfe\xff/) {
1620
1644
  $val =~ s/^(\xfe\xff(.{2})*?)\0\0//s or return '<err>';
1621
1645
  $str = $self->Decode($1, 'UCS2');
1622
1646
  } else {
1623
1647
  $val =~ s/^(.*?)\0//s or return '<err>';
1624
- $str = $1;
1648
+ $str = $self->Decode($1, 'UTF8');
1625
1649
  }
1626
1650
  $str = '(none)' unless length $str;
1627
1651
  return '<err>' if length $val < 13;
@@ -1636,27 +1660,52 @@ my %eeBox2 = (
1636
1660
  if ($val =~ s/^(\xfe\xff(.{2})*?)\0\0//s) {
1637
1661
  $str .= ' Body=' . $self->Decode($1, 'UCS2');
1638
1662
  } elsif ($val =~ s/^(.*?)\0//s) {
1639
- $str .= " Body=$1";
1663
+ $str .= ' Body=' . $self->Decode($1, 'UTF8');
1640
1664
  }
1641
1665
  if ($val =~ s/^(\xfe\xff(.{2})*?)\0\0//s) {
1642
1666
  $str .= ' Notes=' . $self->Decode($1, 'UCS2');
1643
1667
  } elsif ($val =~ s/^(.*?)\0//s) {
1644
- $str .= " Notes=$1";
1668
+ $str .= ' Notes=' . $self->Decode($1, 'UTF8');
1645
1669
  }
1646
- return $lang . $str;
1670
+ return $str;
1671
+ },
1672
+ RawConvInv => q{
1673
+ my ($role, $lat, $lon, $alt, $body, $note);
1674
+ $lat = $1 if $val =~ s/ Lat=([-+]?[.\d]+)//i;
1675
+ $lon = $1 if $val =~ s/ Lon=([-+]?[.\d]+)//i;
1676
+ $alt = $1 if $val =~ s/ Alt=([-+]?[.\d]+)//i;
1677
+ $note = $val =~ s/ Notes=(.*)//i ? $1 : '';
1678
+ $body = $val =~ s/ Body=(.*)//i ? $1 : '';
1679
+ $role = $val =~ s/ Role=(.*)//i ? $1 : '';
1680
+ $val = '' if $val eq '(none)';
1681
+ $role = {shooting=>0,real=>1,fictional=>2}->{lc $role} || 0;
1682
+ return $self->Encode($val, 'UTF8') . "\0" . Set8u($role) .
1683
+ SetFixed32s(defined $lon ? $lon : 999) .
1684
+ SetFixed32s(defined $lat ? $lat : 999) .
1685
+ SetFixed32s(defined $alt ? $alt : 0) .
1686
+ $self->Encode($body) . "\0" .
1687
+ $self->Encode($note) . "\0";
1647
1688
  },
1648
1689
  },
1649
1690
  yrrc => {
1650
1691
  Name => 'Year',
1692
+ Writable => 'undef',
1651
1693
  Groups => { 2 => 'Time' },
1652
- RawConv => 'length($val) >= 6 ? Get16u(\$val,4) : "<err>"',
1694
+ Avoid => 1,
1695
+ Notes => 'used in 3gp videos',
1696
+ ValueConv => 'length($val) >= 6 ? unpack("x4n",$val) : "<err>"',
1697
+ ValueConvInv => 'pack("Nn",0,$val)',
1653
1698
  },
1654
1699
  urat => { #17
1655
1700
  Name => 'UserRating',
1656
- RawConv => q{
1701
+ Writable => 'undef',
1702
+ Notes => 'used in 3gp videos',
1703
+ Avoid => 1,
1704
+ ValueConv => q{
1657
1705
  return '<err>' unless length $val >= 8;
1658
- return Get8u(\$val, 7);
1706
+ unpack('x7C', $val);
1659
1707
  },
1708
+ ValueConvInv => 'pack("N2",0,$val)',
1660
1709
  },
1661
1710
  # tsel - TrackSelection (ref 17)
1662
1711
  # Apple tags (ref 16[dead] -- see ref 25 instead)
@@ -1988,7 +2037,11 @@ my %eeBox2 = (
1988
2037
  # ---- Microsoft ----
1989
2038
  Xtra => { #PH (microsoft)
1990
2039
  Name => 'MicrosoftXtra',
1991
- SubDirectory => { TagTable => 'Image::ExifTool::Microsoft::Xtra' },
2040
+ WriteGroup => 'Microsoft',
2041
+ SubDirectory => {
2042
+ DirName => 'Microsoft',
2043
+ TagTable => 'Image::ExifTool::Microsoft::Xtra',
2044
+ },
1992
2045
  },
1993
2046
  # ---- Minolta ----
1994
2047
  MMA0 => { #PH (DiMage 7Hi)
@@ -2037,7 +2090,7 @@ my %eeBox2 = (
2037
2090
  SubDirectory => { TagTable => 'Image::ExifTool::Olympus::thmb' },
2038
2091
  },{ #17 (format is in bytes 3-7)
2039
2092
  Name => 'ThumbnailImage',
2040
- Condition => '$$valPt =~ /^.{8}\xff\xd8\xff\xdb/s',
2093
+ Condition => '$$valPt =~ /^.{8}\xff\xd8\xff[\xdb\xe0]/s',
2041
2094
  Groups => { 2 => 'Preview' },
2042
2095
  RawConv => 'substr($val, 8)',
2043
2096
  Binary => 1,
@@ -2994,9 +3047,9 @@ my %eeBox2 = (
2994
3047
  3-character ISO 639-2 language code and an optional ISO 3166-1 alpha 2
2995
3048
  country code to the tag name (eg. "ItemList:Title-fra" or
2996
3049
  "ItemList::Title-fra-FR"). When creating a new Meta box to contain the
2997
- ItemList directory, by default ExifTool does not specify a
2998
- L<Handler|Image::ExifTool::TagNames/QuickTime Handler Tags>, but the
2999
- API L<QuickTimeHandler|../ExifTool.html#QuickTimeHandler> option may be used to include an 'mdir' Handler box.
3050
+ ItemList directory, by default ExifTool adds an 'mdir' (Metadata) Handler
3051
+ box because Apple software may ignore ItemList tags otherwise, but the API
3052
+ L<QuickTimeHandler|../ExifTool.html#QuickTimeHandler> option may be set to 0 to avoid this.
3000
3053
  },
3001
3054
  # in this table, binary 1 and 2-byte "data"-type tags are interpreted as
3002
3055
  # int8u and int16u. Multi-byte binary "data" tags are extracted as binary data.
@@ -6157,13 +6210,12 @@ my %eeBox2 = (
6157
6210
  PROCESS_PROC => \&ProcessKeys,
6158
6211
  WRITE_PROC => \&WriteKeys,
6159
6212
  CHECK_PROC => \&CheckQTValue,
6160
- VARS => { LONG_TAGS => 3 },
6213
+ VARS => { LONG_TAGS => 7 },
6161
6214
  WRITABLE => 1,
6162
6215
  # (not PREFERRED when writing)
6163
6216
  GROUPS => { 1 => 'Keys' },
6164
6217
  WRITE_GROUP => 'Keys',
6165
6218
  LANG_INFO => \&GetLangInfo,
6166
- FORMAT => 'string',
6167
6219
  NOTES => q{
6168
6220
  This directory contains a list of key names which are used to decode tags
6169
6221
  written by the "mdta" handler. Also in this table are a few tags found in
@@ -6265,6 +6317,11 @@ my %eeBox2 = (
6265
6317
  PrintConv => '$self->ConvertDateTime($val)',
6266
6318
  PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist)
6267
6319
  },
6320
+ 'location.accuracy.horizontal' => { Name => 'LocationAccuracyHorizontal' },
6321
+ 'live-photo.auto' => { Name => 'LivePhotoAuto', Writable => 'int8u' },
6322
+ 'live-photo.vitality-score' => { Name => 'LivePhotoVitalityScore', Writable => 'float' },
6323
+ 'live-photo.vitality-scoring-version' => { Name => 'LivePhotoVitalityScoringVersion', Writable => 'int64s' },
6324
+ 'apple.photos.variation-identifier' => { Name => 'ApplePhotosVariationIdentifier', Writable => 'int64s' },
6268
6325
  'direction.facing' => { Name => 'CameraDirection', Groups => { 2 => 'Location' } },
6269
6326
  'direction.motion' => { Name => 'CameraMotion', Groups => { 2 => 'Location' } },
6270
6327
  'location.body' => { Name => 'LocationBody', Groups => { 2 => 'Location' } },
@@ -6300,11 +6357,15 @@ my %eeBox2 = (
6300
6357
  # com.divergentmedia.clipwrap.manufacturer ('Sony')
6301
6358
  # com.divergentmedia.clipwrap.originalDateTime ('2013/2/6 10:30:40+0200')
6302
6359
  #
6303
- # seen in timed metadata (mebx), and added dynamically to the table
6304
- # via SaveMetaKeys(). NOTE: these tags are not writable!
6360
+ # seen in timed metadata (mebx), and added dynamically to the table via SaveMetaKeys()
6361
+ # NOTE: these tags are not writable! (timed metadata cannot yet be written)
6305
6362
  #
6306
6363
  # (mdta)com.apple.quicktime.video-orientation (dtyp=66, int16s)
6307
- 'video-orientation' => { Name => 'VideoOrientation', Writable => 0 },
6364
+ 'video-orientation' => {
6365
+ Name => 'VideoOrientation',
6366
+ Writable => 0,
6367
+ PrintConv => \%Image::ExifTool::Exif::orientation, #PH (NC)
6368
+ },
6308
6369
  # (mdta)com.apple.quicktime.live-photo-info (dtyp=com.apple.quicktime.com.apple.quicktime.live-photo-info)
6309
6370
  'live-photo-info' => {
6310
6371
  Name => 'LivePhotoInfo',
@@ -7589,7 +7650,11 @@ my %eeBox2 = (
7589
7650
  8 => {
7590
7651
  Name => 'HandlerType',
7591
7652
  Format => 'undef[4]',
7592
- RawConv => '$$self{HandlerType} = $val unless $val eq "alis" or $val eq "url "; $val',
7653
+ RawConv => q{
7654
+ $$self{HandlerType} = $val unless $val eq 'alis' or $val eq 'url ';
7655
+ $$self{HasHandler}{$val} = 1; # remember all our handlers
7656
+ return $val;
7657
+ },
7593
7658
  PrintConvColumns => 2,
7594
7659
  PrintConv => {
7595
7660
  alis => 'Alias Data', #PH
@@ -7694,7 +7759,7 @@ my %eeBox2 = (
7694
7759
  $val =~ s/\0+$//; # remove trailing nulls
7695
7760
  if (length $val and $$self{OPTIONS}{ExtractEmbedded}) {
7696
7761
  my $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream');
7697
- Image::ExifTool::QuickTime::ProcessNMEA($self, { DataPt => \$val }, $tagTbl);
7762
+ Image::ExifTool::QuickTime::ProcessGPSLog($self, { DataPt => \$val }, $tagTbl);
7698
7763
  }
7699
7764
  return $val;
7700
7765
  },
@@ -8574,7 +8639,7 @@ sub QuickTimeFormat($$)
8574
8639
  my ($flags, $len) = @_;
8575
8640
  my $format;
8576
8641
  if ($flags == 0x15 or $flags == 0x16) {
8577
- $format = { 1=>'int8', 2=>'int16', 4=>'int32' }->{$len};
8642
+ $format = { 1=>'int8', 2=>'int16', 4=>'int32', 8=>'int64' }->{$len};
8578
8643
  $format .= $flags == 0x15 ? 's' : 'u' if $format;
8579
8644
  } elsif ($flags == 0x17) {
8580
8645
  $format = 'float';
@@ -8927,6 +8992,7 @@ sub ProcessMOV($$;$)
8927
8992
  if ($raf->Read($buff, $size-8) == $size-8) {
8928
8993
  $raf->Seek(-($size-8), 1);
8929
8994
  my $type = substr($buff, 0, 4);
8995
+ $$et{save_ftyp} = $type;
8930
8996
  # see if we know the extension for this file type
8931
8997
  if ($ftypLookup{$type} and $ftypLookup{$type} =~ /\(\.(\w+)/) {
8932
8998
  $fileType = $1;
@@ -9350,9 +9416,9 @@ ItemID: foreach $id (keys %$items) {
9350
9416
  }
9351
9417
  for (;;) {
9352
9418
  my ($len, $lang);
9353
- if ($$tagInfo{IText} and $$tagInfo{IText} == 6) {
9354
- last if $pos + 6 > $size;
9355
- $pos += 4;
9419
+ if ($$tagInfo{IText} and $$tagInfo{IText} >= 6) {
9420
+ last if $pos + $$tagInfo{IText} > $size;
9421
+ $pos += $$tagInfo{IText} - 2;
9356
9422
  $lang = unpack("x${pos}n", $val);
9357
9423
  $pos += 2;
9358
9424
  $len = $size - $pos;
@@ -9372,7 +9438,7 @@ ItemID: foreach $id (keys %$items) {
9372
9438
  # ignore any empty entries (or null padding) after the first
9373
9439
  next if not $len and $pos;
9374
9440
  my $str = substr($val, $pos, $len);
9375
- my $langInfo;
9441
+ my ($langInfo, $enc);
9376
9442
  if (($lang < 0x400 or $lang == 0x7fff) and $str !~ /^\xfe\xff/) {
9377
9443
  # this is a Macintosh language code
9378
9444
  # a language code of 0 is Macintosh english, so treat as default
@@ -9389,15 +9455,22 @@ ItemID: foreach $id (keys %$items) {
9389
9455
  }
9390
9456
  # the spec says only "Macintosh text encoding", but
9391
9457
  # allow this to be configured by the user
9392
- $str = $et->Decode($str, $charsetQuickTime);
9458
+ $enc = $charsetQuickTime;
9393
9459
  } else {
9394
9460
  # convert language code to ASCII (ignore read-only bit)
9395
9461
  $lang = UnpackLang($lang);
9396
9462
  # may be either UTF-8 or UTF-16BE
9397
- my $enc = $str=~s/^\xfe\xff// ? 'UTF16' : 'UTF8';
9463
+ $enc = $str=~s/^\xfe\xff// ? 'UTF16' : 'UTF8';
9464
+ }
9465
+ unless ($$tagInfo{NoDecode}) {
9398
9466
  $str = $et->Decode($str, $enc);
9467
+ $str =~ s/\0+$//; # remove any trailing nulls (eg. 3gp tags)
9468
+ }
9469
+ if ($$tagInfo{IText} and $$tagInfo{IText} > 6) {
9470
+ my $n = $$tagInfo{IText} - 6;
9471
+ # add back extra bytes (eg. 'rtng' box)
9472
+ $str = substr($val, $pos-$n-2, $n) . $str;
9399
9473
  }
9400
- $str =~ s/\0+$//; # remove any trailing nulls (eg. 3gp tags)
9401
9474
  $langInfo = GetLangInfoQT($et, $tagInfo, $lang) if $lang;
9402
9475
  $et->FoundTag($langInfo || $tagInfo, $str);
9403
9476
  $pos += $len;
@@ -9447,6 +9520,13 @@ ItemID: foreach $id (keys %$items) {
9447
9520
  ($size, $tag) = unpack('Na4', $buff);
9448
9521
  ++$index if defined $index;
9449
9522
  }
9523
+ # tweak file type based on track content ("iso*" ftyp only)
9524
+ if ($$et{VALUE}{FileType} and $$et{VALUE}{FileType} eq 'MP4' and
9525
+ $$et{save_ftyp} and $$et{HasHandler} and $$et{save_ftyp} =~ /^iso/ and
9526
+ $$et{HasHandler}{soun} and not $$et{HasHandler}{vide})
9527
+ {
9528
+ $et->OverrideFileType('M4A', 'audio/mp4');
9529
+ }
9450
9530
  # fill in missing defaults for alternate language tags
9451
9531
  # (the first language is taken as the default)
9452
9532
  if ($doDefaultLang and $$et{QTLang}) {