exiftool_vendored 12.16.0 → 12.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/Changes +137 -1
- data/bin/MANIFEST +12 -0
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +44 -43
- data/bin/config_files/acdsee.config +193 -6
- data/bin/config_files/cuepointlist.config +70 -0
- data/bin/config_files/example.config +1 -8
- data/bin/exiftool +139 -98
- data/bin/fmt_files/gpx.fmt +1 -1
- data/bin/fmt_files/gpx_wpt.fmt +1 -1
- data/bin/fmt_files/kml.fmt +1 -1
- data/bin/fmt_files/kml_track.fmt +1 -1
- data/bin/lib/Image/ExifTool.pm +158 -49
- data/bin/lib/Image/ExifTool.pod +94 -75
- data/bin/lib/Image/ExifTool/Apple.pm +3 -2
- data/bin/lib/Image/ExifTool/BuildTagLookup.pm +25 -14
- data/bin/lib/Image/ExifTool/Canon.pm +28 -3
- data/bin/lib/Image/ExifTool/CanonCustom.pm +19 -1
- data/bin/lib/Image/ExifTool/DJI.pm +6 -6
- data/bin/lib/Image/ExifTool/DjVu.pm +6 -5
- data/bin/lib/Image/ExifTool/Exif.pm +50 -22
- data/bin/lib/Image/ExifTool/FITS.pm +13 -2
- data/bin/lib/Image/ExifTool/FujiFilm.pm +19 -8
- data/bin/lib/Image/ExifTool/GPS.pm +24 -13
- data/bin/lib/Image/ExifTool/H264.pm +20 -5
- data/bin/lib/Image/ExifTool/ICC_Profile.pm +2 -2
- data/bin/lib/Image/ExifTool/JPEG.pm +6 -2
- data/bin/lib/Image/ExifTool/JSON.pm +24 -3
- data/bin/lib/Image/ExifTool/Jpeg2000.pm +361 -16
- data/bin/lib/Image/ExifTool/M2TS.pm +40 -4
- data/bin/lib/Image/ExifTool/MIE.pm +2 -2
- data/bin/lib/Image/ExifTool/MRC.pm +341 -0
- data/bin/lib/Image/ExifTool/MWG.pm +3 -3
- data/bin/lib/Image/ExifTool/MXF.pm +1 -1
- data/bin/lib/Image/ExifTool/MacOS.pm +1 -1
- data/bin/lib/Image/ExifTool/Microsoft.pm +298 -82
- data/bin/lib/Image/ExifTool/Nikon.pm +5 -5
- data/bin/lib/Image/ExifTool/NikonSettings.pm +25 -16
- data/bin/lib/Image/ExifTool/Olympus.pm +2 -2
- data/bin/lib/Image/ExifTool/PNG.pm +2 -2
- data/bin/lib/Image/ExifTool/Panasonic.pm +14 -1
- data/bin/lib/Image/ExifTool/PhaseOne.pm +4 -3
- data/bin/lib/Image/ExifTool/QuickTime.pm +148 -68
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +94 -34
- data/bin/lib/Image/ExifTool/README +5 -4
- data/bin/lib/Image/ExifTool/RIFF.pm +84 -12
- data/bin/lib/Image/ExifTool/Samsung.pm +2 -1
- data/bin/lib/Image/ExifTool/Shortcuts.pm +9 -0
- data/bin/lib/Image/ExifTool/Sony.pm +157 -49
- data/bin/lib/Image/ExifTool/TagInfoXML.pm +1 -0
- data/bin/lib/Image/ExifTool/TagLookup.pm +4079 -3987
- data/bin/lib/Image/ExifTool/TagNames.pod +642 -273
- data/bin/lib/Image/ExifTool/WriteExif.pl +1 -1
- data/bin/lib/Image/ExifTool/WritePostScript.pl +1 -0
- data/bin/lib/Image/ExifTool/WriteQuickTime.pl +44 -17
- data/bin/lib/Image/ExifTool/WriteXMP.pl +15 -8
- data/bin/lib/Image/ExifTool/Writer.pl +50 -14
- data/bin/lib/Image/ExifTool/XMP.pm +50 -11
- data/bin/perl-Image-ExifTool.spec +42 -42
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +52 -12
|
@@ -1066,7 +1066,7 @@ my %componentDataDef = (
|
|
|
1066
1066
|
'060e2b34.0101.0102.04010503.08000000' => { Name => 'Palette', Type => 'DataValue', Unknown => 1 },
|
|
1067
1067
|
'060e2b34.0101.0102.04010503.09000000' => { Name => 'PaletteLayout', Type => 'RGBALayout', Unknown => 1 },
|
|
1068
1068
|
'060e2b34.0101.0102.04010503.0a000000' => { Name => 'ComponentDepth', Format => 'int32u' },
|
|
1069
|
-
'060e2b34.0101.0102.04010601.00000000' => { Name => 'VideoCodingSchemeID', Type => 'AUID'
|
|
1069
|
+
'060e2b34.0101.0102.04010601.00000000' => { Name => 'VideoCodingSchemeID', Type => 'AUID' },
|
|
1070
1070
|
'060e2b34.0101.0102.04010802.03000000' => { Name => 'RoundedCaptureFilmFrameRate', Format => 'int32u' },
|
|
1071
1071
|
'060e2b34.0101.0102.04020301.02000000' => { Name => 'AudioAverageBitrate', Format => 'float', PrintConv => 'ConvertBitrate($val)', Groups => { 2 => 'Audio' } },
|
|
1072
1072
|
'060e2b34.0101.0102.04020301.03000000' => { Name => 'AudioFixedBitrateFlag', Type => 'Boolean', Groups => { 2 => 'Audio' } },
|
|
@@ -245,7 +245,7 @@ my %mdDateInfo = (
|
|
|
245
245
|
XAttr tags are extracted using the "xattr" utility. They are extracted if
|
|
246
246
|
any "XAttr*" tag or the MacOS group is specifically requested, or by setting
|
|
247
247
|
the L<XAttrTags|../ExifTool.html#XAttrTags> API option to 1 or the L<RequestAll|../ExifTool.html#RequestAll> API option to 2 or higher.
|
|
248
|
-
And they extracted by default from MacOS "._" files when reading
|
|
248
|
+
And they are extracted by default from MacOS "._" files when reading
|
|
249
249
|
these files directly.
|
|
250
250
|
},
|
|
251
251
|
'com.apple.FinderInfo' => {
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
#
|
|
6
6
|
# Revisions: 2010/10/01 - P. Harvey Created
|
|
7
7
|
# 2011/10/05 - PH Added ProcessXtra()
|
|
8
|
+
# 2021/02/23 - PH Added abiltity to write Xtra tags
|
|
8
9
|
#
|
|
9
10
|
# References: 1) http://research.microsoft.com/en-us/um/redmond/groups/ivm/hdview/hdmetadataspec.htm
|
|
10
11
|
#------------------------------------------------------------------------------
|
|
@@ -16,9 +17,11 @@ use vars qw($VERSION);
|
|
|
16
17
|
use Image::ExifTool qw(:DataAccess :Utils);
|
|
17
18
|
use Image::ExifTool::XMP;
|
|
18
19
|
|
|
19
|
-
$VERSION = '1.
|
|
20
|
+
$VERSION = '1.23';
|
|
20
21
|
|
|
21
22
|
sub ProcessXtra($$$);
|
|
23
|
+
sub WriteXtra($$$);
|
|
24
|
+
sub CheckXtra($$$);
|
|
22
25
|
|
|
23
26
|
# tags written by Microsoft HDView (ref 1)
|
|
24
27
|
%Image::ExifTool::Microsoft::Stitch = (
|
|
@@ -196,11 +199,20 @@ my %sRegions = (
|
|
|
196
199
|
# and Image::ExifTool::WTV::Metadata
|
|
197
200
|
%Image::ExifTool::Microsoft::Xtra = (
|
|
198
201
|
PROCESS_PROC => \&ProcessXtra,
|
|
202
|
+
WRITE_PROC => \&WriteXtra,
|
|
203
|
+
CHECK_PROC => \&CheckXtra,
|
|
204
|
+
WRITE_GROUP => 'Microsoft',
|
|
205
|
+
AVOID => 1,
|
|
199
206
|
GROUPS => { 0 => 'QuickTime', 2 => 'Video' },
|
|
200
207
|
VARS => { NO_ID => 1 },
|
|
201
208
|
NOTES => q{
|
|
202
|
-
Tags
|
|
203
|
-
|
|
209
|
+
Tags found in the Microsoft "Xtra" atom of QuickTime videos. Tag ID's are
|
|
210
|
+
not shown because some are unruly GUID's. Currently most of these tags are
|
|
211
|
+
not writable because the Microsoft documentation is poor and samples were
|
|
212
|
+
not available, but more tags may be made writable in the future if samples
|
|
213
|
+
are provided. Note that writable tags in this table are are flagged to
|
|
214
|
+
"Avoid", which means that other more common tags will be written instead if
|
|
215
|
+
possible unless the Microsoft group is specified explicitly.
|
|
204
216
|
},
|
|
205
217
|
Abstract => { },
|
|
206
218
|
AcquisitionTime => { Groups => { 2 => 'Time' } },
|
|
@@ -327,30 +339,34 @@ my %sRegions = (
|
|
|
327
339
|
UserServiceRating => { },
|
|
328
340
|
VideoBitrate => { },
|
|
329
341
|
VideoFormat => { },
|
|
330
|
-
'WM/AlbumArtist' => 'AlbumArtist',
|
|
331
|
-
'WM/AlbumCoverURL' => 'AlbumCoverURL',
|
|
332
|
-
'WM/AlbumTitle' => 'AlbumTitle',
|
|
342
|
+
'WM/AlbumArtist' => { Name => 'AlbumArtist', Writable => 'Unicode' }, # (NC)
|
|
343
|
+
'WM/AlbumCoverURL' => { Name => 'AlbumCoverURL', Writable => 'Unicode' }, # (NC)
|
|
344
|
+
'WM/AlbumTitle' => { Name => 'AlbumTitle', Writable => 'Unicode' }, # (NC)
|
|
333
345
|
'WM/BeatsPerMinute' => 'BeatsPerMinute',
|
|
334
|
-
'WM/Category' => 'Category',
|
|
335
|
-
'WM/Composer' => 'Composer',
|
|
336
|
-
'WM/Conductor' => 'Conductor',
|
|
337
|
-
'WM/ContentDistributor' => 'ContentDistributor',
|
|
346
|
+
'WM/Category' => { Name => 'Category', Writable => 'Unicode', List => 1 },
|
|
347
|
+
'WM/Composer' => { Name => 'Composer', Writable => 'Unicode' }, # (NC)
|
|
348
|
+
'WM/Conductor' => { Name => 'Conductor', Writable => 'Unicode', List => 1 },
|
|
349
|
+
'WM/ContentDistributor' => { Name => 'ContentDistributor', Writable => 'Unicode' },
|
|
338
350
|
'WM/ContentDistributorType' => 'ContentDistributorType',
|
|
339
351
|
'WM/ContentGroupDescription'=> 'ContentGroupDescription',
|
|
340
|
-
'WM/Director' => 'Director',
|
|
352
|
+
'WM/Director' => { Name => 'Director', Writable => 'Unicode', List => 1 },
|
|
341
353
|
'WM/EncodingTime' => {
|
|
342
354
|
Name => 'EncodingTime',
|
|
343
355
|
Groups => { 2 => 'Time' },
|
|
356
|
+
Shift => 'Time',
|
|
357
|
+
Writable => 'date',
|
|
344
358
|
PrintConv => '$self->ConvertDateTime($val)',
|
|
359
|
+
PrintConvInv => '$self->InverseDateTime($val)',
|
|
345
360
|
},
|
|
346
361
|
'WM/Genre' => 'Genre',
|
|
347
362
|
'WM/GenreID' => 'GenreID',
|
|
348
|
-
'WM/InitialKey' => 'InitialKey',
|
|
363
|
+
'WM/InitialKey' => { Name => 'InitialKey', Writable => 'Unicode' },
|
|
349
364
|
'WM/Language' => 'Language',
|
|
350
365
|
'WM/Lyrics' => 'Lyrics',
|
|
351
366
|
'WM/MCDI' => 'MCDI',
|
|
352
367
|
'WM/MediaClassPrimaryID' => {
|
|
353
368
|
Name => 'MediaClassPrimaryID',
|
|
369
|
+
Writable => 'GUID',
|
|
354
370
|
PrintConv => { #http://msdn.microsoft.com/en-us/library/windows/desktop/dd757960(v=vs.85).aspx
|
|
355
371
|
'D1607DBC-E323-4BE2-86A1-48A42A28441E' => 'Music',
|
|
356
372
|
'DB9830BD-3AB3-4FAB-8A37-1A995F7FF74B' => 'Video',
|
|
@@ -360,6 +376,7 @@ my %sRegions = (
|
|
|
360
376
|
},
|
|
361
377
|
'WM/MediaClassSecondaryID' => {
|
|
362
378
|
Name => 'MediaClassSecondaryID',
|
|
379
|
+
Writable => 'GUID',
|
|
363
380
|
PrintConv => { #http://msdn.microsoft.com/en-us/library/windows/desktop/dd757960(v=vs.85).aspx
|
|
364
381
|
'E0236BEB-C281-4EDE-A36D-7AF76A3D45B5' => 'Audio Book',
|
|
365
382
|
'3A172A13-2BD9-4831-835B-114F6A95943F' => 'Spoken Word',
|
|
@@ -385,22 +402,22 @@ my %sRegions = (
|
|
|
385
402
|
},
|
|
386
403
|
'WM/MediaOriginalChannel' => 'MediaOriginalChannel',
|
|
387
404
|
'WM/MediaStationName' => 'MediaStationName',
|
|
388
|
-
'WM/Mood' => 'Mood',
|
|
389
|
-
'WM/OriginalAlbumTitle' => 'OriginalAlbumTitle',
|
|
390
|
-
'WM/OriginalArtist' => 'OriginalArtist',
|
|
391
|
-
'WM/OriginalLyricist' => 'OriginalLyricist',
|
|
392
|
-
'WM/ParentalRating' => 'ParentalRating',
|
|
405
|
+
'WM/Mood' => { Name => 'Mood', Writable => 'Unicode' },
|
|
406
|
+
'WM/OriginalAlbumTitle' => { Name => 'OriginalAlbumTitle', Writable => 'Unicode' }, # (NC)
|
|
407
|
+
'WM/OriginalArtist' => { Name => 'OriginalArtist', Writable => 'Unicode' }, # (NC)
|
|
408
|
+
'WM/OriginalLyricist' => { Name => 'OriginalLyricist', Writable => 'Unicode' }, # (NC)
|
|
409
|
+
'WM/ParentalRating' => { Name => 'ParentalRating', Writable => 'Unicode' },
|
|
393
410
|
'WM/PartOfSet' => 'PartOfSet',
|
|
394
|
-
'WM/Period' => 'Period',
|
|
395
|
-
'WM/Producer' => 'Producer',
|
|
411
|
+
'WM/Period' => { Name => 'Period', Writable => 'Unicode' },
|
|
412
|
+
'WM/Producer' => { Name => 'Producer', Writable => 'Unicode', List => 1 },
|
|
396
413
|
'WM/ProtectionType' => 'ProtectionType',
|
|
397
|
-
'WM/Provider' => 'Provider',
|
|
414
|
+
'WM/Provider' => { Name => 'Provider', Writable => 'Unicode' }, # (NC)
|
|
398
415
|
'WM/ProviderRating' => 'ProviderRating',
|
|
399
416
|
'WM/ProviderStyle' => 'ProviderStyle',
|
|
400
|
-
'WM/Publisher' => 'Publisher',
|
|
401
|
-
'WM/SharedUserRating' => 'SharedUserRating',
|
|
417
|
+
'WM/Publisher' => { Name => 'Publisher', Writable => 'Unicode' }, # (multiple entries separated by semicolon)
|
|
418
|
+
'WM/SharedUserRating' => { Name => 'SharedUserRating', Writable => 'int64u' },
|
|
402
419
|
'WM/SubscriptionContentID' => 'SubscriptionContentID',
|
|
403
|
-
'WM/SubTitle' => 'Subtitle',
|
|
420
|
+
'WM/SubTitle' => { Name => 'Subtitle', Writable => 'Unicode' },
|
|
404
421
|
'WM/SubTitleDescription' => 'SubtitleDescription',
|
|
405
422
|
'WM/TrackNumber' => 'TrackNumber',
|
|
406
423
|
'WM/UniqueFileIdentifier' => 'UniqueFileIdentifier',
|
|
@@ -412,8 +429,11 @@ my %sRegions = (
|
|
|
412
429
|
'WM/WMContentID' => 'WMContentID',
|
|
413
430
|
'WM/WMShadowFileSourceDRMType' => 'WMShadowFileSourceDRMType',
|
|
414
431
|
'WM/WMShadowFileSourceFileType' => 'WMShadowFileSourceFileType',
|
|
415
|
-
'WM/Writer' => 'Writer',
|
|
416
|
-
'WM/Year' => { Name => 'Year',
|
|
432
|
+
'WM/Writer' => { Name => 'Writer', Groups => { 2 => 'Author' }, Writable => 'Unicode' }, # (NC)
|
|
433
|
+
'WM/Year' => { Name => 'Year', Groups => { 2 => 'Time' } },
|
|
434
|
+
'WM/PromotionURL' => { Name => 'PromotionURL',Writable => 'Unicode' },
|
|
435
|
+
'WM/AuthorURL' => { Name => 'AuthorURL', Groups => { 2 => 'Author' }, Writable => 'Unicode' },
|
|
436
|
+
'WM/EncodedBy', => { Name => 'EncodedBy', Writable => 'Unicode' },
|
|
417
437
|
|
|
418
438
|
# I can't find documentation for the following tags in videos,
|
|
419
439
|
# but the tag ID's correspond to Microsoft property GUID+ID's
|
|
@@ -422,9 +442,12 @@ my %sRegions = (
|
|
|
422
442
|
# http://multi-rename-script.googlecode.com/svn-history/r4/trunk/plugins/ShellDetails/ShellDetails.ini
|
|
423
443
|
# I have observed only 1 so far:
|
|
424
444
|
'{2CBAA8F5-D81F-47CA-B17A-F8D822300131} 100' => {
|
|
425
|
-
Name => 'DateAcquired',
|
|
445
|
+
Name => 'DateAcquired', # (seems to be when videos are downloaded from the camera)
|
|
426
446
|
Groups => { 2 => 'Time' },
|
|
447
|
+
Shift => 'Time',
|
|
448
|
+
Writable => 'vt_filetime',
|
|
427
449
|
PrintConv => '$self->ConvertDateTime($val)',
|
|
450
|
+
PrintConvInv => '$self->InverseDateTime($val,undef)',
|
|
428
451
|
},
|
|
429
452
|
# the following have not yet been observed...
|
|
430
453
|
'{B725F130-47EF-101A-A5F1-02608C9EEBAC} 10' => 'Name',
|
|
@@ -764,6 +787,245 @@ my %sRegions = (
|
|
|
764
787
|
'{64440491-4C8B-11D1-8B70-080036B11A03} 43' => 'TotalBitrate',
|
|
765
788
|
);
|
|
766
789
|
|
|
790
|
+
#------------------------------------------------------------------------------
|
|
791
|
+
# check new value for Xtra tag
|
|
792
|
+
# Inputs: 0) ExifTool object ref, 1) tagInfo hash ref, 2) raw value ref
|
|
793
|
+
# Returns: error string, or undef on success
|
|
794
|
+
sub CheckXtra($$$)
|
|
795
|
+
{
|
|
796
|
+
my ($et, $tagInfo, $valPt) = @_;
|
|
797
|
+
my $format = $$tagInfo{Writable};
|
|
798
|
+
return 'Unknown format' unless $format;
|
|
799
|
+
if ($format =~ /^int/) {
|
|
800
|
+
return 'Not an integer' unless Image::ExifTool::IsInt($$valPt);
|
|
801
|
+
} elsif ($format ne 'Unicode') {
|
|
802
|
+
my @vals = ($$valPt);
|
|
803
|
+
return 'Invalid format' unless WriteXtraValue($et, $tagInfo, \@vals);
|
|
804
|
+
}
|
|
805
|
+
return undef;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
#------------------------------------------------------------------------------
|
|
809
|
+
# Decode value(s) in Microsoft Xtra tag
|
|
810
|
+
# Inputs: 0) ExifTool object ref, 1) value data
|
|
811
|
+
# Returns: Scalar context: decoded value, List context: 0) decoded value, 1) format string
|
|
812
|
+
sub ReadXtraValue($$)
|
|
813
|
+
{
|
|
814
|
+
my ($et, $data) = @_;
|
|
815
|
+
my ($format, $i, @vals);
|
|
816
|
+
|
|
817
|
+
return undef if length($data) < 10;
|
|
818
|
+
|
|
819
|
+
# (version flags according to the reference, but looks more like a count - PH)
|
|
820
|
+
my $count = Get32u(\$data, 0);
|
|
821
|
+
# point to start of first value (after 4-byte count, 4-byte length and 2-byte type)
|
|
822
|
+
my $valPos = 10;
|
|
823
|
+
for ($i=0; ;) {
|
|
824
|
+
# (stored value includes size of $valLen and $valType, so subtract 6)
|
|
825
|
+
my $valLen = Get32u(\$data, $valPos - 6) - 6;
|
|
826
|
+
last if $valPos + $valLen > length($data);
|
|
827
|
+
my $valType = Get16u(\$data, $valPos - 2);
|
|
828
|
+
my $val = substr($data, $valPos, $valLen);
|
|
829
|
+
# Note: all dumb Microsoft values are little-endian inside a big-endian-format file
|
|
830
|
+
SetByteOrder('II');
|
|
831
|
+
if ($valType == 8) {
|
|
832
|
+
$format = 'Unicode';
|
|
833
|
+
$val = $et->Decode($val, 'UCS2');
|
|
834
|
+
} elsif ($valType == 19 and $valLen == 8) {
|
|
835
|
+
$format = 'int64u';
|
|
836
|
+
$val = Get64u(\$val, 0);
|
|
837
|
+
} elsif ($valType == 21 and $valLen == 8) {
|
|
838
|
+
$format = 'date';
|
|
839
|
+
$val = Get64u(\$val, 0);
|
|
840
|
+
# convert time from 100 ns intervals since Jan 1, 1601
|
|
841
|
+
$val = $val * 1e-7 - 11644473600 if $val;
|
|
842
|
+
# (the Nikon S100 uses UTC timezone, same as ASF - PH)
|
|
843
|
+
$val = Image::ExifTool::ConvertUnixTime($val, 1);
|
|
844
|
+
} elsif ($valType == 72 and $valLen == 16) {
|
|
845
|
+
$format = 'GUID';
|
|
846
|
+
$val = uc unpack('H*',pack('NnnNN',unpack('VvvNN',$val)));
|
|
847
|
+
$val =~ s/(.{8})(.{4})(.{4})(.{4})/$1-$2-$3-$4-/;
|
|
848
|
+
} elsif ($valType == 65 and $valLen > 4) { #PH (empirical)
|
|
849
|
+
$format = 'variant';
|
|
850
|
+
require Image::ExifTool::FlashPix;
|
|
851
|
+
my $vPos = 0; # (necessary because ReadFPXValue updates this)
|
|
852
|
+
# read entry as a VT_VARIANT (use FlashPix module for this)
|
|
853
|
+
$val = Image::ExifTool::FlashPix::ReadFPXValue($et, \$val, $vPos,
|
|
854
|
+
Image::ExifTool::FlashPix::VT_VARIANT(), $valLen, 1);
|
|
855
|
+
} else {
|
|
856
|
+
$format = "Unknown($valType)";
|
|
857
|
+
}
|
|
858
|
+
SetByteOrder('MM'); # back to native QuickTime byte ordering
|
|
859
|
+
push @vals, $val;
|
|
860
|
+
last if ++$i >= $count;
|
|
861
|
+
$valPos += $valLen + 6; # step to next value
|
|
862
|
+
last if $valPos > length($data);
|
|
863
|
+
}
|
|
864
|
+
return wantarray ? (\@vals, $format) : \@vals;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
#------------------------------------------------------------------------------
|
|
868
|
+
# Write a Microsoft Xtra value
|
|
869
|
+
# Inputs: 0) ExifTool object ref, 1) tagInfo ref, 2) reference to list of values
|
|
870
|
+
# Returns: new value binary data (or empty string)
|
|
871
|
+
sub WriteXtraValue($$$)
|
|
872
|
+
{
|
|
873
|
+
my ($et, $tagInfo, $vals) = @_;
|
|
874
|
+
my $format = $$tagInfo{Writable};
|
|
875
|
+
my $buff = '';
|
|
876
|
+
my $count = 0;
|
|
877
|
+
my $val;
|
|
878
|
+
foreach $val (@$vals) {
|
|
879
|
+
SetByteOrder('II');
|
|
880
|
+
my ($type, $dat);
|
|
881
|
+
if ($format eq 'Unicode') {
|
|
882
|
+
$dat = $et->Encode($val,'UCS2','II') . "\0\0"; # (must be null terminated)
|
|
883
|
+
$type = 8;
|
|
884
|
+
} elsif ($format eq 'int64u') {
|
|
885
|
+
if (Image::ExifTool::IsInt($val)) {
|
|
886
|
+
$dat = Set64u($val);
|
|
887
|
+
$type = 19;
|
|
888
|
+
}
|
|
889
|
+
} elsif ($format eq 'date') {
|
|
890
|
+
$dat = Image::ExifTool::GetUnixTime($val, 1); # (convert to UTC, NC)
|
|
891
|
+
if ($dat) {
|
|
892
|
+
# 100ns intervals since Jan 1, 1601
|
|
893
|
+
$dat = Set64u(($dat + 11644473600) * 1e7);
|
|
894
|
+
$type = 21;
|
|
895
|
+
}
|
|
896
|
+
} elsif ($format eq 'vt_filetime') { # 'date' value inside a VT_VARIANT
|
|
897
|
+
$dat = Image::ExifTool::GetUnixTime($val); # (leave as local time, NC)
|
|
898
|
+
if ($dat) {
|
|
899
|
+
# 100ns intervals since Jan 1, 1601
|
|
900
|
+
$dat = Set32u(64) . Set64u(($dat + 11644473600) * 1e7);
|
|
901
|
+
$type = 65;
|
|
902
|
+
}
|
|
903
|
+
} elsif ($format eq 'GUID') {
|
|
904
|
+
($dat = $val) =~ tr/-//d;
|
|
905
|
+
if (length($dat) == 32) {
|
|
906
|
+
$dat = pack('VvvNN',unpack('NnnNN',pack('H*', $dat)));
|
|
907
|
+
$type = 72;
|
|
908
|
+
}
|
|
909
|
+
} else {
|
|
910
|
+
$et->WarnOnce("Error converting value for Microsoft:$$tagInfo{Name}");
|
|
911
|
+
}
|
|
912
|
+
SetByteOrder('MM');
|
|
913
|
+
if (defined $type) {
|
|
914
|
+
++$count;
|
|
915
|
+
$buff .= Set32u(length($dat)+6) . Set16u($type) . $dat;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
return $count ? Set32u($count) . $buff : '';
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
#------------------------------------------------------------------------------
|
|
922
|
+
# Add new values to list
|
|
923
|
+
# Inputs: 0) ExifTool ref, 1) new value list ref, 2) nvHash ref
|
|
924
|
+
# Returns: true if something was added
|
|
925
|
+
sub AddNewValues($$$)
|
|
926
|
+
{
|
|
927
|
+
my ($et, $vals, $nvHash) = @_;
|
|
928
|
+
my @newVals = $et->GetNewValue($nvHash) or return undef;
|
|
929
|
+
if ($$et{OPTIONS}{Verbose} > 1) {
|
|
930
|
+
$et->VPrint(1, " + Microsoft:$$nvHash{TagInfo}{Name} = $_\n") foreach @newVals;
|
|
931
|
+
}
|
|
932
|
+
push @$vals, @newVals;
|
|
933
|
+
return 1;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
#------------------------------------------------------------------------------
|
|
937
|
+
# Write tags to a Microsoft Xtra MP4 atom
|
|
938
|
+
# Inputs: 0) ExifTool object ref, 1) source dirInfo ref, 2) tag table ref
|
|
939
|
+
# Returns: Microsoft Xtra data block (may be empty if no Xtra data) or undef on error
|
|
940
|
+
sub WriteXtra($$$)
|
|
941
|
+
{
|
|
942
|
+
my ($et, $dirInfo, $tagTablePtr) = @_;
|
|
943
|
+
$et or return 1; # allow dummy access
|
|
944
|
+
|
|
945
|
+
my $delGroup = ($$et{DEL_GROUP} and $$et{DEL_GROUP}{Microsoft});
|
|
946
|
+
my $newTags = $et->GetNewTagInfoHash($tagTablePtr);
|
|
947
|
+
|
|
948
|
+
return undef unless $delGroup or %$newTags; # don't rewrite if nothing to do
|
|
949
|
+
|
|
950
|
+
my $dataPt = $$dirInfo{DataPt};
|
|
951
|
+
my $dataLen = length $$dataPt;
|
|
952
|
+
my $newData = '';
|
|
953
|
+
my $pos = 0;
|
|
954
|
+
my ($err, %done, $changed, $tag);
|
|
955
|
+
|
|
956
|
+
if ($delGroup) {
|
|
957
|
+
$changed = 1 if $dataLen;
|
|
958
|
+
my $empty = '';
|
|
959
|
+
$dataPt = $empty;
|
|
960
|
+
$dataLen = 0;
|
|
961
|
+
}
|
|
962
|
+
for (;;) {
|
|
963
|
+
last if $pos + 4 > $dataLen;
|
|
964
|
+
my $size = Get32u($dataPt, $pos); # (includes $size word)
|
|
965
|
+
($size < 8 or $pos + $size > $dataLen) and $err=1, last;
|
|
966
|
+
my $tagLen = Get32u($dataPt, $pos + 4);
|
|
967
|
+
$tagLen + 18 > $size and $err=1, last;
|
|
968
|
+
$tag = substr($$dataPt, $pos + 8, $tagLen);
|
|
969
|
+
my @newVals;
|
|
970
|
+
while ($$newTags{$tag}) {
|
|
971
|
+
my $nvHash = $et->GetNewValueHash($$newTags{$tag});
|
|
972
|
+
$$nvHash{CreateOnly} and delete($$newTags{$tag}), last; # don't edit this tag
|
|
973
|
+
my $valPos = $pos + 8 + $tagLen;
|
|
974
|
+
my $valLen = $size - 8 - $tagLen;
|
|
975
|
+
my $val = ReadXtraValue($et, substr($$dataPt, $valPos, $valLen));
|
|
976
|
+
foreach $val (@$val) {
|
|
977
|
+
my $overwrite = $et->IsOverwriting($nvHash, $val);
|
|
978
|
+
$overwrite or push(@newVals, $val), next;
|
|
979
|
+
$et->VPrint(1, " - Microsoft:$$newTags{$tag}{Name} = $val\n");
|
|
980
|
+
next if $done{$tag};
|
|
981
|
+
$done{$tag} = 1;
|
|
982
|
+
AddNewValues($et, \@newVals, $nvHash);
|
|
983
|
+
}
|
|
984
|
+
# add to the end of the list if this was a List-type tag and we didn't delete anything
|
|
985
|
+
if (not $done{$tag} and $$newTags{$tag}{List}) {
|
|
986
|
+
AddNewValues($et, \@newVals, $nvHash) or last;
|
|
987
|
+
$done{$tag} = 1;
|
|
988
|
+
}
|
|
989
|
+
last; # (it was a cheap goto)
|
|
990
|
+
}
|
|
991
|
+
if ($done{$tag}) {
|
|
992
|
+
$changed = 1;
|
|
993
|
+
# write changed values
|
|
994
|
+
my $buff = WriteXtraValue($et, $$newTags{$tag}, \@newVals);
|
|
995
|
+
if (length $buff) {
|
|
996
|
+
$newData .= Set32u(8+length($tag)+length($buff)) . Set32u(length($tag)) . $tag . $buff;
|
|
997
|
+
}
|
|
998
|
+
} else {
|
|
999
|
+
# nothing changed; just copy over
|
|
1000
|
+
$newData .= substr($$dataPt, $pos, $size);
|
|
1001
|
+
}
|
|
1002
|
+
$pos += $size; # step to next entry
|
|
1003
|
+
}
|
|
1004
|
+
if ($err) {
|
|
1005
|
+
$et->Warn('Microsoft Xtra format error');
|
|
1006
|
+
return undef;
|
|
1007
|
+
}
|
|
1008
|
+
# add any new tags
|
|
1009
|
+
foreach $tag (sort keys %$newTags) {
|
|
1010
|
+
next if $done{$tag};
|
|
1011
|
+
my $nvHash = $et->GetNewValueHash($$newTags{$tag});
|
|
1012
|
+
next unless $$nvHash{IsCreating} and not $$nvHash{EditOnly};
|
|
1013
|
+
my @newVals;
|
|
1014
|
+
AddNewValues($et, \@newVals, $nvHash) or next;
|
|
1015
|
+
my $buff = WriteXtraValue($et, $$newTags{$tag}, \@newVals);
|
|
1016
|
+
if (length $buff) {
|
|
1017
|
+
$newData .= Set32u(8+length($tag)+length($buff)) . Set32u(length($tag)) . $tag . $buff;
|
|
1018
|
+
$changed = 1;
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
if ($changed) {
|
|
1022
|
+
++$$et{CHANGED};
|
|
1023
|
+
} else {
|
|
1024
|
+
undef $newData;
|
|
1025
|
+
}
|
|
1026
|
+
return $newData;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
767
1029
|
#------------------------------------------------------------------------------
|
|
768
1030
|
# Extract information from Xtra MP4 atom
|
|
769
1031
|
# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
|
|
@@ -783,61 +1045,13 @@ sub ProcessXtra($$$)
|
|
|
783
1045
|
last if $size < 8 or $pos + $size > $dataLen;
|
|
784
1046
|
my $tagLen = Get32u($dataPt, $pos + 4);
|
|
785
1047
|
last if $tagLen + 18 > $size;
|
|
786
|
-
my $
|
|
787
|
-
# (version flags according to the reference, but looks more like a count - PH)
|
|
788
|
-
my $count = Get32u($dataPt, $pos + $tagLen + 8);
|
|
789
|
-
my ($i, $valPos, $valLen, $valType, $val, $format, @vals);
|
|
790
|
-
# point to start of first value (after 4-byte length and 2-byte type)
|
|
791
|
-
$valPos = $pos + $tagLen + 18;
|
|
792
|
-
for ($i=0; ;) {
|
|
793
|
-
# (stored value includes size of $valLen and $valType, so subtract 6)
|
|
794
|
-
$valLen = Get32u($dataPt, $valPos - 6) - 6;
|
|
795
|
-
my $more = $pos + $size - $valPos - $valLen;
|
|
796
|
-
last if $more < 0;
|
|
797
|
-
$valType = Get16u($dataPt, $valPos - 2);
|
|
798
|
-
$val = substr($$dataPt, $valPos, $valLen);
|
|
799
|
-
# Note: all dumb Microsoft values are little-endian inside a big-endian-format file
|
|
800
|
-
SetByteOrder('II');
|
|
801
|
-
if ($valType == 8) {
|
|
802
|
-
$format = 'Unicode';
|
|
803
|
-
$val = $et->Decode($val, 'UCS2');
|
|
804
|
-
} elsif ($valType == 19 and $valLen == 8) {
|
|
805
|
-
$format = 'int64u';
|
|
806
|
-
$val = Get64u(\$val, 0);
|
|
807
|
-
} elsif ($valType == 21 and $valLen == 8) {
|
|
808
|
-
$format = 'date';
|
|
809
|
-
$val = Get64u(\$val, 0);
|
|
810
|
-
# convert time from 100 ns intervals since Jan 1, 1601
|
|
811
|
-
$val = $val * 1e-7 - 11644473600 if $val;
|
|
812
|
-
# (the Nikon S100 uses UTC timezone, same as ASF - PH)
|
|
813
|
-
$val = Image::ExifTool::ConvertUnixTime($val) . 'Z';
|
|
814
|
-
} elsif ($valType == 72 and $valLen == 16) {
|
|
815
|
-
$format = 'GUID';
|
|
816
|
-
$val = uc unpack('H*',pack('NnnNN',unpack('VvvNN',$val)));
|
|
817
|
-
$val =~ s/(.{8})(.{4})(.{4})(.{4})/$1-$2-$3-$4-/;
|
|
818
|
-
} elsif ($valType == 65 && $valLen > 4) { #PH (empirical)
|
|
819
|
-
$format = 'variant';
|
|
820
|
-
require Image::ExifTool::FlashPix;
|
|
821
|
-
my $vPos = $valPos; # (necessary because ReadFPXValue updates this)
|
|
822
|
-
# read entry as a VT_VARIANT (use FlashPix module for this)
|
|
823
|
-
$val = Image::ExifTool::FlashPix::ReadFPXValue($et, $dataPt, $vPos,
|
|
824
|
-
Image::ExifTool::FlashPix::VT_VARIANT(), $valPos+$valLen, 1);
|
|
825
|
-
} else {
|
|
826
|
-
$format = "Unknown($valType)";
|
|
827
|
-
}
|
|
828
|
-
SetByteOrder('MM'); # back to native QuickTime byte ordering
|
|
829
|
-
last if ++$i >= $count or $more < 6;
|
|
830
|
-
push @vals, $val;
|
|
831
|
-
undef $val;
|
|
832
|
-
$valPos += $valLen + 6; # step to next value
|
|
833
|
-
}
|
|
834
|
-
if (@vals) {
|
|
835
|
-
push @vals, $val if defined $val;
|
|
836
|
-
$val = \@vals;
|
|
837
|
-
$valPos = $pos + $tagLen + 18;
|
|
838
|
-
$valLen = $size - 18 - $tagLen;
|
|
839
|
-
}
|
|
1048
|
+
my $valLen = $size - 8 - $tagLen;
|
|
840
1049
|
if ($tagLen > 0 and $valLen > 0) {
|
|
1050
|
+
my $tag = substr($$dataPt, $pos + 8, $tagLen);
|
|
1051
|
+
my $valPos = $pos + 8 + $tagLen;
|
|
1052
|
+
my ($val, $format) = ReadXtraValue($et, substr($$dataPt, $valPos, $valLen));
|
|
1053
|
+
last unless defined $val;
|
|
1054
|
+
$val = $$val[0] if @$val == 1;
|
|
841
1055
|
my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
|
|
842
1056
|
unless ($tagInfo) {
|
|
843
1057
|
# generate tag information for unrecognized tags
|
|
@@ -850,6 +1064,7 @@ sub ProcessXtra($$$)
|
|
|
850
1064
|
$et->VPrint(0, $$et{INDENT}, "[adding Microsoft:$tag]\n");
|
|
851
1065
|
}
|
|
852
1066
|
}
|
|
1067
|
+
my $count = ref $val ? scalar @$val : 1;
|
|
853
1068
|
$et->HandleTag($tagTablePtr, $tag, $val,
|
|
854
1069
|
TagInfo => $tagInfo,
|
|
855
1070
|
DataPt => $dataPt,
|
|
@@ -857,7 +1072,7 @@ sub ProcessXtra($$$)
|
|
|
857
1072
|
Start => $valPos,
|
|
858
1073
|
Size => $valLen,
|
|
859
1074
|
Format => $format,
|
|
860
|
-
Extra => " count=$count
|
|
1075
|
+
Extra => " count=$count",
|
|
861
1076
|
);
|
|
862
1077
|
}
|
|
863
1078
|
$pos += $size; # step to next entry
|
|
@@ -880,7 +1095,8 @@ This module is used by Image::ExifTool
|
|
|
880
1095
|
=head1 DESCRIPTION
|
|
881
1096
|
|
|
882
1097
|
This module contains definitions required by Image::ExifTool to interpret
|
|
883
|
-
Microsoft-specific EXIF and XMP tags
|
|
1098
|
+
Microsoft-specific EXIF and XMP tags, and routines to read/write Microsoft
|
|
1099
|
+
Xtra tags in videos.
|
|
884
1100
|
|
|
885
1101
|
=head1 AUTHOR
|
|
886
1102
|
|