exiftool_vendored 13.12.0 → 13.14.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 +52 -22
- data/bin/MANIFEST +5 -0
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +2 -2
- data/bin/arg_files/exif2xmp.args +4 -0
- data/bin/arg_files/xmp2exif.args +2 -1
- data/bin/build_geolocation +1 -1
- data/bin/exiftool +5 -5
- data/bin/lib/Image/ExifTool/AFCP.pm +5 -5
- data/bin/lib/Image/ExifTool/BuildTagLookup.pm +24 -13
- data/bin/lib/Image/ExifTool/DJI.pm +64 -11
- data/bin/lib/Image/ExifTool/EXE.pm +2 -2
- data/bin/lib/Image/ExifTool/Geolocation.pm +16 -7
- data/bin/lib/Image/ExifTool/JPEG.pm +5 -1
- data/bin/lib/Image/ExifTool/LigoGPS.pm +1 -0
- data/bin/lib/Image/ExifTool/Nikon.pm +2 -0
- data/bin/lib/Image/ExifTool/Protobuf.pm +25 -7
- data/bin/lib/Image/ExifTool/QuickTime.pm +161 -50
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +2 -2
- data/bin/lib/Image/ExifTool/Samsung.pm +1 -1
- data/bin/lib/Image/ExifTool/TagLookup.pm +3438 -3430
- data/bin/lib/Image/ExifTool/TagNames.pod +89 -22
- data/bin/lib/Image/ExifTool/Torrent.pm +2 -2
- data/bin/lib/Image/ExifTool/Vivo.pm +124 -0
- data/bin/lib/Image/ExifTool/WriteQuickTime.pl +69 -40
- data/bin/lib/Image/ExifTool/Writer.pl +12 -8
- data/bin/lib/Image/ExifTool.pm +22 -6
- data/bin/lib/Image/ExifTool.pod +43 -41
- data/bin/perl-Image-ExifTool.spec +1 -1
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +3 -2
@@ -12,7 +12,7 @@ meta information extracted from or written to a file.
|
|
12
12
|
=head1 TAG TABLES
|
13
13
|
|
14
14
|
The tables listed below give the names of all tags recognized by ExifTool.
|
15
|
-
They contain a total of
|
15
|
+
They contain a total of 28258 tags, with 17524 unique tag names.
|
16
16
|
|
17
17
|
B<Tag ID>, B<Index#> or B<Sequence> is given in the first column of each
|
18
18
|
table. A B<Tag ID> is the computer-readable equivalent of a tag name, and
|
@@ -171,6 +171,7 @@ L<https://www.w3.org/Graphics/JPEG/jfif3.pdf> for the JPEG specification.
|
|
171
171
|
PhotoMechanic PhotoMechanic
|
172
172
|
MIE MIE
|
173
173
|
Samsung Samsung Trailer
|
174
|
+
Vivo Vivo
|
174
175
|
EmbeddedVideo no
|
175
176
|
Insta360 no
|
176
177
|
NikonApp no
|
@@ -12972,34 +12973,56 @@ Thermal parameters extracted from APP4 of some DJI RJPEG files.
|
|
12972
12973
|
|
12973
12974
|
=head3 DJI Protobuf Tags
|
12974
12975
|
|
12975
|
-
Tags found in protobuf-format DJI djmd and dbgi timed metadata.
|
12976
|
-
tags are
|
12977
|
-
the Unknown option to 1
|
12978
|
-
ID's are composed of the corresponding .proto
|
12979
|
-
hierarchical protobuf field numbers.
|
12976
|
+
Tags found in protobuf-format DJI djmd and dbgi timed metadata. The known
|
12977
|
+
tags listed below are extracted by default, but unknown djmd tags may be
|
12978
|
+
extracted as well by setting the Unknown option to 1, or 2 to also extract
|
12979
|
+
unknown dbgi debug tags. Tag ID's are composed of the corresponding .proto
|
12980
|
+
file name combined with the hierarchical protobuf field numbers.
|
12980
12981
|
|
12981
12982
|
ExifTool currently extracts timed GPS plus a few other tags from DJI devices
|
12982
12983
|
which use the following protocols: dvtm_AVATA2.proto (Avanta 2),
|
12983
|
-
dvtm_ac203.proto (Osmo Action 4),
|
12984
|
+
dvtm_ac203.proto (Osmo Action 4), dvtm_ac204.proto (Osmo Action 5) and
|
12985
|
+
dvtm_wm265e.proto (Mavic 3).
|
12986
|
+
|
12987
|
+
Note that with the protobuf format, numerical tags missing from the output
|
12988
|
+
for a given protocol should be considered to have the default value of 0.
|
12984
12989
|
|
12985
12990
|
Tag ID Tag Name Writable
|
12986
12991
|
------ -------- --------
|
12987
12992
|
'Protocol' Protocol no
|
12993
|
+
'dvtm_AVATA2_1-1-5' SerialNumber no
|
12988
12994
|
'dvtm_AVATA2_1-1-10' Model no
|
12989
|
-
'dvtm_AVATA2_2-2-3-1'
|
12995
|
+
'dvtm_AVATA2_2-2-3-1' SerialNumber2 no
|
12990
12996
|
'dvtm_AVATA2_2-3' FrameInfo DJI FrameInfo
|
12991
12997
|
'dvtm_AVATA2_3-1-2' TimeStamp no
|
12992
12998
|
'dvtm_AVATA2_3-4-4-1' GPSInfo DJI GPSInfo
|
12999
|
+
'dvtm_ac203_1-1-5' SerialNumber no
|
12993
13000
|
'dvtm_ac203_1-1-10' Model no
|
12994
13001
|
'dvtm_ac203_2-3' FrameInfo DJI FrameInfo
|
12995
13002
|
'dvtm_ac203_3-4-2-1' GPSInfo DJI GPSInfo
|
12996
13003
|
'dvtm_ac203_3-4-2-2' GPSAltitude no
|
12997
13004
|
'dvtm_ac203_3-4-2-6-1' GPSDateTime no
|
13005
|
+
'dvtm_ac204_1-1-5' SerialNumber no
|
12998
13006
|
'dvtm_ac204_1-1-10' Model no
|
12999
13007
|
'dvtm_ac204_2-3' FrameInfo DJI FrameInfo
|
13000
13008
|
'dvtm_ac204_3-4-2-1' GPSInfo DJI GPSInfo
|
13001
13009
|
'dvtm_ac204_3-4-2-2' GPSAltitude no
|
13002
13010
|
'dvtm_ac204_3-4-2-6-1' GPSDateTime no
|
13011
|
+
'dvtm_wm265e_1-1-5' SerialNumber no
|
13012
|
+
'dvtm_wm265e_1-1-10' Model no
|
13013
|
+
'dvtm_wm265e_2-2' FrameInfo DJI FrameInfo
|
13014
|
+
'dvtm_wm265e_3-2-2-1' ISO no
|
13015
|
+
'dvtm_wm265e_3-2-3-1' ShutterSpeed no
|
13016
|
+
'dvtm_wm265e_3-2-6-1' DigitalZoom no
|
13017
|
+
'dvtm_wm265e_3-3-3-1' DroneRoll no
|
13018
|
+
'dvtm_wm265e_3-3-3-2' DronePitch no
|
13019
|
+
'dvtm_wm265e_3-3-3-3' DroneYaw no
|
13020
|
+
'dvtm_wm265e_3-3-4-1' GPSInfo DJI GPSInfo
|
13021
|
+
'dvtm_wm265e_3-3-4-2' AbsoluteAltitude no
|
13022
|
+
'dvtm_wm265e_3-3-5-1' RelativeAltitude no
|
13023
|
+
'dvtm_wm265e_3-4-3-1' GimbalPitch no
|
13024
|
+
'dvtm_wm265e_3-4-3-2' GimbalRoll no
|
13025
|
+
'dvtm_wm265e_3-4-3-3' GimbalYaw no
|
13003
13026
|
|
13004
13027
|
=head3 DJI FrameInfo Tags
|
13005
13028
|
|
@@ -23679,6 +23702,16 @@ Tags written by the Sony Image Data Converter utility in ARW images.
|
|
23679
23702
|
0xd100 VersionCreateDate string
|
23680
23703
|
0xd101 VersionModifyDate string
|
23681
23704
|
|
23705
|
+
=head2 Vivo Tags
|
23706
|
+
|
23707
|
+
Proprietary information written by some Vivo phones.
|
23708
|
+
|
23709
|
+
Tag Name Writable
|
23710
|
+
-------- --------
|
23711
|
+
HDRImage no
|
23712
|
+
HiddenData no
|
23713
|
+
JSONInfo no
|
23714
|
+
|
23682
23715
|
=head2 Unknown Tags
|
23683
23716
|
|
23684
23717
|
The following tags are decoded in unsupported maker notes. Use the Unknown
|
@@ -29967,15 +30000,22 @@ appropriate table in the config file (see
|
|
29967
30000
|
example.config in the full distribution for an
|
29968
30001
|
example). Note that some tags with the same name but different ID's may
|
29969
30002
|
exist in the same location, but the family 7 group names may be used to
|
29970
|
-
differentiate these.
|
29971
|
-
QuickTime-based files; it extracts other track-specific and timed metadata,
|
29972
|
-
but can not yet edit tags in these locations (with the exception of
|
29973
|
-
track-level date/time tags).
|
30003
|
+
differentiate these.
|
29974
30004
|
|
29975
|
-
|
29976
|
-
|
29977
|
-
|
29978
|
-
|
30005
|
+
ExifTool currently writes
|
30006
|
+
L<ItemList|Image::ExifTool::TagNames/QuickTime ItemList Tags> and
|
30007
|
+
L<UserData|Image::ExifTool::TagNames/QuickTime UserData Tags> only as
|
30008
|
+
top-level metadata, but select Keys tags are may be written to the audio or
|
30009
|
+
video track. See the
|
30010
|
+
L<AudioKeys|Image::ExifTool::TagNames/QuickTime AudioKeys Tags> and
|
30011
|
+
L<VideoKeys|Image::ExifTool::TagNames/QuickTime VideoKeys Tags> tags for
|
30012
|
+
more information.
|
30013
|
+
|
30014
|
+
Beware that the values of the Keys tags are actually stored inside an
|
30015
|
+
ItemList atom in the file, so deleting the ItemList group as a block (ie.
|
30016
|
+
C<-ItemList:all=>) also deletes Keys tags. Instead, to preserve Keys tags
|
30017
|
+
the ItemList tags may be deleted individually with
|
30018
|
+
C<-QuickTime:ItemList:all=>.
|
29979
30019
|
|
29980
30020
|
Alternate language tags may be accessed for
|
29981
30021
|
L<ItemList|Image::ExifTool::TagNames/QuickTime ItemList Tags> and
|
@@ -30073,7 +30113,7 @@ for the official QuickTime specification.
|
|
30073
30113
|
The tags below are extracted from timed metadata in QuickTime and other
|
30074
30114
|
formats of video files when the ExtractEmbedded option is used. Although
|
30075
30115
|
most of these tags are combined into the single table below, ExifTool
|
30076
|
-
currently reads
|
30116
|
+
currently reads 100 different types of timed GPS metadata from video files.
|
30077
30117
|
|
30078
30118
|
Tag Name Writable
|
30079
30119
|
-------- --------
|
@@ -30276,15 +30316,11 @@ changed via the config file.
|
|
30276
30316
|
'artist' Artist yes
|
30277
30317
|
'artwork' Artwork yes
|
30278
30318
|
'author' Author yes
|
30279
|
-
'camera.framereadouttimeinmicroseconds'
|
30280
|
-
FrameReadoutTime yes
|
30281
|
-
'camera.identifier' CameraIdentifier yes
|
30282
30319
|
'collection.user' UserCollection yes
|
30283
30320
|
'com.android.capture.fps' AndroidCaptureFPS float
|
30284
30321
|
'com.android.manufacturer' AndroidMake yes
|
30285
30322
|
'com.android.model' AndroidModel yes
|
30286
30323
|
'com.android.version' AndroidVersion yes
|
30287
|
-
'com.apple.photos.captureMode' CaptureMode yes
|
30288
30324
|
'com.xiaomi.hdr10' XiaomiHDR10 int32s
|
30289
30325
|
'com.xiaomi.preview_video_cover'
|
30290
30326
|
XiaomiPreviewVideoCover int32s
|
@@ -30353,6 +30389,35 @@ changed via the config file.
|
|
30353
30389
|
'xiaomi.exifInfo.videoinfo' XiaomiExifInfo yes
|
30354
30390
|
'year' Year yes
|
30355
30391
|
|
30392
|
+
=head3 QuickTime AudioKeys Tags
|
30393
|
+
|
30394
|
+
Keys tags written in the audio track by some Apple devices. These tags
|
30395
|
+
belong to the ExifTool AudioKeys family 1 gorup.
|
30396
|
+
|
30397
|
+
Tag ID Tag Name Writable
|
30398
|
+
------ -------- --------
|
30399
|
+
'player.movie.audio.balance' Balance yes
|
30400
|
+
'player.movie.audio.bass' Bass yes
|
30401
|
+
'player.movie.audio.gain' AudioGain yes
|
30402
|
+
'player.movie.audio.mute' Mute int8u
|
30403
|
+
'player.movie.audio.pitchshift' PitchShift yes
|
30404
|
+
'player.movie.audio.treble' Treble yes
|
30405
|
+
|
30406
|
+
=head3 QuickTime VideoKeys Tags
|
30407
|
+
|
30408
|
+
Keys tags written in the video track. These tags belong to the ExifTool
|
30409
|
+
VideoKeys family 1 gorup.
|
30410
|
+
|
30411
|
+
Tag ID Tag Name Writable
|
30412
|
+
------ -------- --------
|
30413
|
+
'camera.focal_length.35mm_equivalent'
|
30414
|
+
FocalLengthIn35mmFormat yes
|
30415
|
+
'camera.framereadouttimeinmicroseconds'
|
30416
|
+
FrameReadoutTime yes
|
30417
|
+
'camera.identifier' CameraIdentifier yes
|
30418
|
+
'camera.lens_model' LensModel yes
|
30419
|
+
'com.apple.photos.captureMode' CaptureMode yes
|
30420
|
+
|
30356
30421
|
=head3 QuickTime FaceInfo Tags
|
30357
30422
|
|
30358
30423
|
Tag ID Tag Name Writable
|
@@ -30452,7 +30517,9 @@ Tags found in Pittasoft Blackvue dashcam "free" data.
|
|
30452
30517
|
'ipro' ItemProtection? no
|
30453
30518
|
'iprp' ItemProperties QuickTime ItemProp
|
30454
30519
|
'iref' ItemReference QuickTime ItemRef
|
30455
|
-
'keys'
|
30520
|
+
'keys' AudioKeys QuickTime AudioKeys
|
30521
|
+
VideoKeys QuickTime VideoKeys
|
30522
|
+
Keys QuickTime Keys
|
30456
30523
|
'pitm' PrimaryItemReference no
|
30457
30524
|
'uuid' MetaVersion no
|
30458
30525
|
UUID-Unknown? no
|
@@ -14,7 +14,7 @@ use strict;
|
|
14
14
|
use vars qw($VERSION);
|
15
15
|
use Image::ExifTool qw(:DataAccess :Utils);
|
16
16
|
|
17
|
-
$VERSION = '1.
|
17
|
+
$VERSION = '1.07';
|
18
18
|
|
19
19
|
sub ReadBencode($$$);
|
20
20
|
sub ExtractTags($$$;$$@);
|
@@ -282,7 +282,7 @@ sub ProcessTorrent($$)
|
|
282
282
|
my $dict = ReadBencode($et, $raf, \$buff);
|
283
283
|
my $err = $$raf{BencodeError};
|
284
284
|
$et->Warn("Bencode error: $err") if $err;
|
285
|
-
if (ref $dict eq 'HASH' and ($$dict{announce} or $$dict{'created by'})) {
|
285
|
+
if (ref $dict eq 'HASH' and ($$dict{announce} or $$dict{'created by'} or $$dict{info})) {
|
286
286
|
$et->SetFileType();
|
287
287
|
my $tagTablePtr = GetTagTable('Image::ExifTool::Torrent::Main');
|
288
288
|
ExtractTags($et, $dict, $tagTablePtr) and $success = 1;
|
@@ -0,0 +1,124 @@
|
|
1
|
+
#------------------------------------------------------------------------------
|
2
|
+
# File: Vivo.pm
|
3
|
+
#
|
4
|
+
# Description: Read trailer written by Vivo phones
|
5
|
+
#
|
6
|
+
# Revisions: 2025-01-13 - P. Harvey Created
|
7
|
+
#------------------------------------------------------------------------------
|
8
|
+
|
9
|
+
package Image::ExifTool::Vivo;
|
10
|
+
|
11
|
+
use strict;
|
12
|
+
use vars qw($VERSION);
|
13
|
+
use Image::ExifTool qw(:DataAccess :Utils);
|
14
|
+
use Image::ExifTool::XMP;
|
15
|
+
|
16
|
+
$VERSION = '1.00';
|
17
|
+
|
18
|
+
%Image::ExifTool::Vivo::Main = (
|
19
|
+
GROUPS => { 0 => 'Trailer', 1 => 'Vivo', 2 => 'Image' },
|
20
|
+
VARS => { NO_ID => 1 },
|
21
|
+
NOTES => 'Proprietary information written by some Vivo phones.',
|
22
|
+
# (don't know for sure what type of image this is, but it is in JPEG format)
|
23
|
+
HDRImage => {
|
24
|
+
Notes => 'highlights of HDR image',
|
25
|
+
Groups => { 2 => 'Preview' },
|
26
|
+
Binary => 1,
|
27
|
+
},
|
28
|
+
JSONInfo => { },
|
29
|
+
HiddenData => {
|
30
|
+
Notes => 'hidden in EXIF, not in trailer. This data is lost if the file is edited',
|
31
|
+
Groups => { 0 => 'EXIF' },
|
32
|
+
},
|
33
|
+
);
|
34
|
+
|
35
|
+
#------------------------------------------------------------------------------
|
36
|
+
# Process Vivo trailer
|
37
|
+
# Inputs: 0) ExifTool object reference, 1) dirInfo reference
|
38
|
+
# Returns: 1 on success, -1 if we must scan for the start of the trailer
|
39
|
+
# - takes Offset as positive offset from end of trailer to end of file,
|
40
|
+
# and returns DataPos and DirLen, and updates OutFile when writing
|
41
|
+
sub ProcessVivo($$)
|
42
|
+
{
|
43
|
+
my ($et, $dirInfo) = @_;
|
44
|
+
my $raf = $$dirInfo{RAF};
|
45
|
+
my $buff;
|
46
|
+
|
47
|
+
# return now unless we are at a position to scan for the trailer
|
48
|
+
# (must scan because the trailer footer doesn't indicate the trailer length)
|
49
|
+
return -1 unless $$dirInfo{ScanForTrailer};
|
50
|
+
|
51
|
+
my $pos = $raf->Tell();
|
52
|
+
$raf->Seek(0, 2) or return 0;
|
53
|
+
my $len = $raf->Tell() - $pos - $$dirInfo{Offset};
|
54
|
+
$raf->Seek($pos, 0) or return 0;
|
55
|
+
return 0 unless $len > 0 and $len < 1e7 and $raf->Read($buff, $len) == $len and
|
56
|
+
$buff =~ /\xff{4}\x1b\*9HWfu\x84\x93\xa2\xb1$/ and # validate footer
|
57
|
+
$buff =~ /(streamdata|vivo\{")/g; # find start
|
58
|
+
my $start = pos($buff) - length($1);
|
59
|
+
if ($start) {
|
60
|
+
$pos += $start;
|
61
|
+
$len -= $start;
|
62
|
+
$buff = substr($buff, $start);
|
63
|
+
}
|
64
|
+
# set trailer position and length
|
65
|
+
@$dirInfo{'DataPos','DirLen'} = ($pos, $len);
|
66
|
+
|
67
|
+
if ($$dirInfo{OutFile}) {
|
68
|
+
if ($$et{DEL_GROUP}{Vivo}) {
|
69
|
+
$et->VPrint(0, " Deleting Vivo trailer ($len bytes)\n");
|
70
|
+
++$$et{CHANGED};
|
71
|
+
} else {
|
72
|
+
$et->VPrint(0, " Copying Vivo trailer ($len bytes)\n");
|
73
|
+
Write($$dirInfo{OutFile}, $buff);
|
74
|
+
}
|
75
|
+
} else {
|
76
|
+
$et->DumpTrailer($dirInfo) if $$et{OPTIONS}{Verbose} or $$et{HTML_DUMP};
|
77
|
+
my $tbl = GetTagTable('Image::ExifTool::Vivo::Main');
|
78
|
+
pos($buff) = 0; # rewind search to start of buffer
|
79
|
+
if ($buff =~ /^streamdata\xff\xd8\xff/ and $buff =~ /\xff\xd9stream(info|coun)/g) {
|
80
|
+
$et->HandleTag($tbl, HDRImage => substr($buff, 10, pos($buff)-20));
|
81
|
+
}
|
82
|
+
# continue looking for Vivo JSON data
|
83
|
+
if ($buff =~ /vivo\{"/g) {
|
84
|
+
my $jsonStart = pos($buff) - 2;
|
85
|
+
if ($buff =~ /\}\0/g) {
|
86
|
+
my $jsonLen = pos($buff) - 1 - $jsonStart;
|
87
|
+
$et->HandleTag($tbl, JSONInfo => substr($buff, $jsonStart, $jsonLen));
|
88
|
+
}
|
89
|
+
}
|
90
|
+
}
|
91
|
+
return 1;
|
92
|
+
}
|
93
|
+
|
94
|
+
1; # end
|
95
|
+
|
96
|
+
__END__
|
97
|
+
|
98
|
+
=head1 NAME
|
99
|
+
|
100
|
+
Image::ExifTool::Vivo - Read trailer written by Vivo phones
|
101
|
+
|
102
|
+
=head1 SYNOPSIS
|
103
|
+
|
104
|
+
This module is used by Image::ExifTool
|
105
|
+
|
106
|
+
=head1 DESCRIPTION
|
107
|
+
|
108
|
+
This module contains definitions required by Image::ExifTool to read
|
109
|
+
metadata the trailer written by some Vivo phones.
|
110
|
+
|
111
|
+
=head1 AUTHOR
|
112
|
+
|
113
|
+
Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
|
114
|
+
|
115
|
+
This library is free software; you can redistribute it and/or modify it
|
116
|
+
under the same terms as Perl itself.
|
117
|
+
|
118
|
+
=head1 SEE ALSO
|
119
|
+
|
120
|
+
L<Image::ExifTool::TagNames/Vivo Tags>,
|
121
|
+
L<Image::ExifTool(3pm)|Image::ExifTool>
|
122
|
+
|
123
|
+
=cut
|
124
|
+
|
@@ -15,6 +15,8 @@ my %movMap = (
|
|
15
15
|
QuickTime => 'ItemList', # (default location for QuickTime tags)
|
16
16
|
ItemList => 'Meta', # MOV-Movie-UserData-Meta-ItemList
|
17
17
|
Keys => 'Movie', # MOV-Movie-Meta-Keys !! (hack due to different Meta location)
|
18
|
+
AudioKeys => 'Track', # MOV-Movie-Track-Meta-Keys !!
|
19
|
+
VideoKeys => 'Track', # MOV-Movie-Track-Meta-Keys !!
|
18
20
|
Meta => 'UserData',
|
19
21
|
XMP => 'UserData', # MOV-Movie-UserData-XMP
|
20
22
|
Microsoft => 'UserData', # MOV-Movie-UserData-Microsoft
|
@@ -29,6 +31,8 @@ my %mp4Map = (
|
|
29
31
|
QuickTime => 'ItemList', # (default location for QuickTime tags)
|
30
32
|
ItemList => 'Meta', # MOV-Movie-UserData-Meta-ItemList
|
31
33
|
Keys => 'Movie', # MOV-Movie-Meta-Keys !! (hack due to different Meta location)
|
34
|
+
AudioKeys => 'Track', # MOV-Movie-Track-Meta-Keys !!
|
35
|
+
VideoKeys => 'Track', # MOV-Movie-Track-Meta-Keys !!
|
32
36
|
Meta => 'UserData',
|
33
37
|
UserData => 'Movie', # MOV-Movie-UserData
|
34
38
|
Microsoft => 'UserData', # MOV-Movie-UserData-Microsoft
|
@@ -383,13 +387,14 @@ sub WriteKeys($$$)
|
|
383
387
|
my $outfile = $$dirInfo{OutFile};
|
384
388
|
my ($tag, %done, %remap, %info, %add, $i);
|
385
389
|
|
390
|
+
my $keysGrp = $avType{$$et{MediaType}} ? "$avType{$$et{MediaType}}Keys" : 'Keys';
|
386
391
|
$dirLen < 8 and $et->Warn('Short Keys box'), $dirLen = 8, $$dataPt = "\0" x 8;
|
387
|
-
if ($$et{DEL_GROUP}{
|
392
|
+
if ($$et{DEL_GROUP}{$keysGrp}) {
|
388
393
|
$dirLen = 8; # delete all existing keys
|
389
394
|
# deleted keys are identified by a zero entry in the Remap lookup
|
390
395
|
my $n = Get32u($dataPt, 4);
|
391
396
|
for ($i=1; $i<=$n; ++$i) { $remap{$i} = 0; }
|
392
|
-
$et->VPrint(0, " [deleting $n
|
397
|
+
$et->VPrint(0, " [deleting $n $keysGrp entr".($n==1 ? 'y' : 'ies')."]\n");
|
393
398
|
++$$et{CHANGED};
|
394
399
|
}
|
395
400
|
my $pos = 8;
|
@@ -425,7 +430,7 @@ sub WriteKeys($$$)
|
|
425
430
|
}
|
426
431
|
unless ($dontDelete) {
|
427
432
|
# delete this key
|
428
|
-
$et->VPrint(1, "$$et{INDENT}\[deleting
|
433
|
+
$et->VPrint(1, "$$et{INDENT}\[deleting $keysGrp entry $index '${tag}']\n");
|
429
434
|
$pos += $len;
|
430
435
|
$remap{$index++} = 0;
|
431
436
|
++$$et{CHANGED};
|
@@ -455,7 +460,7 @@ sub WriteKeys($$$)
|
|
455
460
|
# add new entry to 'keys' data
|
456
461
|
my $val = $id =~ /^com\./ ? $id : "com.apple.quicktime.$id";
|
457
462
|
$newData .= Set32u(8 + length($val)) . 'mdta' . $val;
|
458
|
-
$et->VPrint(1, "$$et{INDENT}\[adding
|
463
|
+
$et->VPrint(1, "$$et{INDENT}\[adding $keysGrp entry $newIndex '${id}']\n");
|
459
464
|
$add{$newIndex++} = $tagInfo;
|
460
465
|
++$$et{CHANGED};
|
461
466
|
}
|
@@ -470,7 +475,7 @@ sub WriteKeys($$$)
|
|
470
475
|
# Info - Keys tag information, based on old index value
|
471
476
|
# Add - Keys items deleted, based on old index value
|
472
477
|
# Num - Number of items in edited Keys box
|
473
|
-
$$et{
|
478
|
+
$$et{$keysGrp} = { Remap => \%remap, Info => \%info, Add => \%add, Num => $num };
|
474
479
|
|
475
480
|
return $newData; # return updated Keys box
|
476
481
|
}
|
@@ -883,7 +888,7 @@ sub WriteQuickTime($$$)
|
|
883
888
|
$et or return 1; # allow dummy access to autoload this package
|
884
889
|
my ($mdat, @mdat, @mdatEdit, $edit, $track, $outBuff, $co, $term, $delCount);
|
885
890
|
my (%langTags, $canCreate, $delGrp, %boxPos, %didDir, $writeLast, $err, $atomCount);
|
886
|
-
my ($tag, $lastTag, $lastPos, $errStr, $trailer, $buf2);
|
891
|
+
my ($tag, $lastTag, $lastPos, $errStr, $trailer, $buf2, $keysGrp, $keysPath);
|
887
892
|
my $outfile = $$dirInfo{OutFile} || return 0;
|
888
893
|
my $raf = $$dirInfo{RAF}; # (will be null for lower-level atoms)
|
889
894
|
my $dataPt = $$dirInfo{DataPt}; # (will be null for top-level atoms)
|
@@ -917,15 +922,26 @@ sub WriteQuickTime($$$)
|
|
917
922
|
|
918
923
|
$raf->Seek($dirStart, 1) if $dirStart; # skip header if it exists
|
919
924
|
|
925
|
+
if ($avType{$$et{MediaType}}) {
|
926
|
+
# (note: these won't be correct now if we haven't yet processed the Media box,
|
927
|
+
# but in this case they won't be needed until after we set them properly below)
|
928
|
+
($keysGrp, $keysPath) = ("$avType{$$et{MediaType}}Keys", 'MOV-Movie-Track');
|
929
|
+
} else {
|
930
|
+
($keysGrp, $keysPath) = ('Keys', 'MOV-Movie');
|
931
|
+
}
|
920
932
|
my $curPath = join '-', @{$$et{PATH}};
|
921
933
|
my ($dir, $writePath) = ($dirName, $dirName);
|
922
934
|
$writePath = "$dir-$writePath" while defined($dir = $$et{DirMap}{$dir});
|
923
935
|
# hack to create Keys directories if necessary (its containing Meta is in a different location)
|
924
|
-
if ($$addDirs{Keys} and $curPath =~ /^MOV-Movie(-Meta)?$/) {
|
936
|
+
if (($$addDirs{Keys} and $curPath =~ /^MOV-Movie(-Meta)?$/)) {
|
925
937
|
$createKeys = 1; # create new Keys directories
|
926
|
-
} elsif ($curPath
|
938
|
+
} elsif (($$addDirs{AudioKeys} or $$addDirs{VideoKeys}) and $curPath =~ /^MOV-Movie-Track(-Meta)?$/) {
|
939
|
+
$createKeys = -1; # (must wait until MediaType is known)
|
940
|
+
} elsif (($curPath eq 'MOV-Movie-Meta-ItemList') or
|
941
|
+
($curPath eq 'MOV-Movie-Track-Meta-ItemList' and $avType{$$et{MediaType}}))
|
942
|
+
{
|
927
943
|
$createKeys = 2; # create new Keys tags
|
928
|
-
my $keys = $$et{
|
944
|
+
my $keys = $$et{$keysGrp};
|
929
945
|
if ($keys) {
|
930
946
|
# add new tag entries for existing Keys tags, now that we know their ID's
|
931
947
|
# - first make lookup to convert Keys tagInfo ref to index number
|
@@ -933,7 +949,7 @@ sub WriteQuickTime($$$)
|
|
933
949
|
foreach $index (keys %{$$keys{Info}}) {
|
934
950
|
$keysInfo{$$keys{Info}{$index}} = $index if $$keys{Remap}{$index};
|
935
951
|
}
|
936
|
-
my $keysTable = GetTagTable(
|
952
|
+
my $keysTable = GetTagTable("Image::ExifTool::QuickTime::$keysGrp");
|
937
953
|
my $newKeysTags = $et->GetNewTagInfoHash($keysTable);
|
938
954
|
foreach (keys %$newKeysTags) {
|
939
955
|
my $tagInfo = $$newKeysTags{$_};
|
@@ -962,7 +978,8 @@ sub WriteQuickTime($$$)
|
|
962
978
|
}
|
963
979
|
if ($curPath eq $writePath or $createKeys) {
|
964
980
|
$canCreate = 1;
|
965
|
-
|
981
|
+
# (must check the appropriate Keys delete flag if this is a Keys ItemList)
|
982
|
+
$delGrp = $$et{DEL_GROUP}{$createKeys ? $keysGrp : $dirName};
|
966
983
|
}
|
967
984
|
$atomCount = $$tagTablePtr{VARS}{ATOM_COUNT} if $$tagTablePtr{VARS};
|
968
985
|
|
@@ -1080,12 +1097,12 @@ sub WriteQuickTime($$$)
|
|
1080
1097
|
last;
|
1081
1098
|
}
|
1082
1099
|
}
|
1083
|
-
# save the handler type
|
1084
|
-
if ($tag eq 'hdlr' and length $buff >= 12
|
1085
|
-
|
1086
|
-
|
1100
|
+
# save the handler type of the track media
|
1101
|
+
if ($tag eq 'hdlr' and length $buff >= 12 and
|
1102
|
+
@{$$et{PATH}} and $$et{PATH}[-1] eq 'Media')
|
1103
|
+
{
|
1104
|
+
$$et{MediaType} = substr($buff,8,4);
|
1087
1105
|
}
|
1088
|
-
|
1089
1106
|
# if this atom stores offsets, save its location so we can fix up offsets later
|
1090
1107
|
# (are there any other atoms that may store absolute file offsets?)
|
1091
1108
|
if ($tag =~ /^(stco|co64|iloc|mfra|moof|sidx|saio|gps |CTBO|uuid)$/) {
|
@@ -1130,11 +1147,11 @@ sub WriteQuickTime($$$)
|
|
1130
1147
|
&{$$tagInfo{WriteHook}}($buff,$et) if $tagInfo and $$tagInfo{WriteHook};
|
1131
1148
|
|
1132
1149
|
# allow numerical tag ID's (ItemList entries defined by Keys)
|
1133
|
-
if (not $tagInfo and $dirName eq 'ItemList' and $$et{
|
1150
|
+
if (not $tagInfo and $dirName eq 'ItemList' and $$et{$keysGrp}) {
|
1134
1151
|
$keysIndex = unpack('N', $tag);
|
1135
|
-
my $newIndex = $$et{
|
1152
|
+
my $newIndex = $$et{$keysGrp}{Remap}{$keysIndex};
|
1136
1153
|
if (defined $newIndex) {
|
1137
|
-
$tagInfo = $$et{
|
1154
|
+
$tagInfo = $$et{$keysGrp}{Info}{$keysIndex};
|
1138
1155
|
unless ($newIndex) {
|
1139
1156
|
if ($tagInfo) {
|
1140
1157
|
$et->VPrint(1," - Keys:$$tagInfo{Name}");
|
@@ -1174,7 +1191,7 @@ sub WriteQuickTime($$$)
|
|
1174
1191
|
if ($subdir) { # process atoms in this container from a buffer in memory
|
1175
1192
|
|
1176
1193
|
if ($tag eq 'trak') {
|
1177
|
-
|
1194
|
+
$$et{MediaType} = ''; # init media type for this track
|
1178
1195
|
delete $$et{AssumedDataRef};
|
1179
1196
|
}
|
1180
1197
|
my $subName = $$subdir{DirName} || $$tagInfo{Name};
|
@@ -1243,10 +1260,13 @@ sub WriteQuickTime($$$)
|
|
1243
1260
|
$$et{CHANGED} = $oldChanged;
|
1244
1261
|
undef $newData;
|
1245
1262
|
}
|
1246
|
-
if ($tag eq 'trak'
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1263
|
+
if ($tag eq 'trak') {
|
1264
|
+
$$et{MediaType} = ''; # reset media type at end of track
|
1265
|
+
if ($$et{AssumedDataRef}) {
|
1266
|
+
my $grp = $$et{CUR_WRITE_GROUP} || $dirName;
|
1267
|
+
$et->Error("Can't locate data reference to update offsets for $grp");
|
1268
|
+
delete $$et{AssumedDataRef};
|
1269
|
+
}
|
1250
1270
|
}
|
1251
1271
|
$$et{CUR_WRITE_GROUP} = $oldWriteGroup;
|
1252
1272
|
SetByteOrder('MM');
|
@@ -1542,7 +1562,7 @@ sub WriteQuickTime($$$)
|
|
1542
1562
|
}
|
1543
1563
|
if ($msg) {
|
1544
1564
|
# (allow empty sample description for non-audio/video handler types, eg. 'url ', 'meta')
|
1545
|
-
if ($$et{
|
1565
|
+
if ($$et{MediaType}) {
|
1546
1566
|
my $grp = $$et{CUR_WRITE_GROUP} || $parent;
|
1547
1567
|
$et->Error("$msg for $grp");
|
1548
1568
|
return $rtnErr;
|
@@ -1595,7 +1615,16 @@ sub WriteQuickTime($$$)
|
|
1595
1615
|
}
|
1596
1616
|
$et->VPrint(0, " [deleting $delCount $dirName tag".($delCount==1 ? '' : 's')."]\n") if $delCount;
|
1597
1617
|
|
1598
|
-
|
1618
|
+
# can finally set necessary variables for creating Video/AudioKeys tags
|
1619
|
+
if ($createKeys < 0) {
|
1620
|
+
if ($avType{$$et{MediaType}}) {
|
1621
|
+
$createKeys = 1;
|
1622
|
+
($keysGrp, $keysPath) = ("$avType{$$et{MediaType}}Keys", 'MOV-Movie-Track');
|
1623
|
+
} else {
|
1624
|
+
$canCreate = 0;
|
1625
|
+
}
|
1626
|
+
}
|
1627
|
+
$createKeys &= ~0x01 unless $$addDirs{$keysGrp}; # (Keys may have been written)
|
1599
1628
|
|
1600
1629
|
# add new directories/tags at this level if necessary
|
1601
1630
|
if ($canCreate and (exists $$et{EDIT_DIRS}{$dirName} or $createKeys)) {
|
@@ -1606,13 +1635,13 @@ sub WriteQuickTime($$$)
|
|
1606
1635
|
my ($tag, $index);
|
1607
1636
|
# add Keys tags if necessary
|
1608
1637
|
if ($createKeys) {
|
1609
|
-
if ($curPath eq
|
1638
|
+
if ($curPath eq $keysPath) {
|
1610
1639
|
# add Meta for Keys if necessary
|
1611
1640
|
unless ($didDir{meta}) {
|
1612
1641
|
$$dirs{meta} = $Image::ExifTool::QuickTime::Movie{meta};
|
1613
1642
|
push @addTags, 'meta';
|
1614
1643
|
}
|
1615
|
-
} elsif ($curPath eq
|
1644
|
+
} elsif ($curPath eq "$keysPath-Meta") {
|
1616
1645
|
# special case for Keys Meta -- reset directories and start again
|
1617
1646
|
undef @addTags;
|
1618
1647
|
$dirs = { };
|
@@ -1621,10 +1650,10 @@ sub WriteQuickTime($$$)
|
|
1621
1650
|
$$dirs{$_} = $Image::ExifTool::QuickTime::Meta{$_};
|
1622
1651
|
push @addTags, $_;
|
1623
1652
|
}
|
1624
|
-
} elsif ($curPath eq
|
1625
|
-
foreach $index (sort { $a <=> $b } keys %{$$et{
|
1653
|
+
} elsif ($curPath eq "$keysPath-Meta-ItemList" and $$et{$keysGrp}) {
|
1654
|
+
foreach $index (sort { $a <=> $b } keys %{$$et{$keysGrp}{Add}}) {
|
1626
1655
|
my $id = Set32u($index);
|
1627
|
-
$$newTags{$id} = $$et{
|
1656
|
+
$$newTags{$id} = $$et{$keysGrp}{Add}{$index};
|
1628
1657
|
push @addTags, $id;
|
1629
1658
|
}
|
1630
1659
|
} else {
|
@@ -1636,8 +1665,7 @@ sub WriteQuickTime($$$)
|
|
1636
1665
|
foreach $tag (@addTags) {
|
1637
1666
|
my $tagInfo = $$dirs{$tag} || $$newTags{$tag};
|
1638
1667
|
next if defined $$tagInfo{CanCreate} and not $$tagInfo{CanCreate};
|
1639
|
-
next if defined $$tagInfo{
|
1640
|
-
(not $$et{HandlerType} or $$et{HandlerType} ne $$tagInfo{HandlerType});
|
1668
|
+
next if defined $$tagInfo{MediaType} and $$et{MediaType} ne $$tagInfo{MediaType};
|
1641
1669
|
my $subdir = $$tagInfo{SubDirectory};
|
1642
1670
|
unless ($subdir) {
|
1643
1671
|
my $nvHash = $et->GetNewValueHash($tagInfo);
|
@@ -1699,13 +1727,13 @@ sub WriteQuickTime($$$)
|
|
1699
1727
|
}
|
1700
1728
|
my $subName = $$subdir{DirName} || $$tagInfo{Name};
|
1701
1729
|
# QuickTime hierarchy is complex, so check full directory path before adding
|
1702
|
-
if ($createKeys and $curPath eq
|
1730
|
+
if ($createKeys and $curPath eq $keysPath and $subName eq 'Meta') {
|
1703
1731
|
$et->VPrint(0, " Creating Meta with mdta Handler and Keys\n");
|
1704
1732
|
# init Meta box for Keys tags with mdta Handler and empty Keys+ItemList
|
1705
1733
|
$buf2 = "\0\0\0\x20hdlr\0\0\0\0\0\0\0\0mdta\0\0\0\0\0\0\0\0\0\0\0\0" .
|
1706
1734
|
"\0\0\0\x10keys\0\0\0\0\0\0\0\0" .
|
1707
1735
|
"\0\0\0\x08ilst";
|
1708
|
-
} elsif ($createKeys and $curPath eq
|
1736
|
+
} elsif ($createKeys and $curPath eq "$keysPath-Meta") {
|
1709
1737
|
$buf2 = ($subName eq 'Keys' ? "\0\0\0\0\0\0\0\0" : '');
|
1710
1738
|
} elsif ($subName eq 'Meta' and $$et{OPTIONS}{QuickTimeHandler}) {
|
1711
1739
|
$et->VPrint(0, " Creating Meta with mdir Handler\n");
|
@@ -1754,8 +1782,8 @@ sub WriteQuickTime($$$)
|
|
1754
1782
|
}
|
1755
1783
|
}
|
1756
1784
|
# add only once (must delete _after_ call to WriteDirectory())
|
1757
|
-
# (Keys
|
1758
|
-
delete $$addDirs{$subName} unless $
|
1785
|
+
# (Keys tags are a special case, and are handled separately)
|
1786
|
+
delete $$addDirs{$subName} unless $createKeys;
|
1759
1787
|
}
|
1760
1788
|
}
|
1761
1789
|
# write HEIC metadata after top-level 'meta' box has been processed if editing this information
|
@@ -1781,9 +1809,9 @@ sub WriteQuickTime($$$)
|
|
1781
1809
|
# (could report a file if editing nothing when it contained an empty Meta atom)
|
1782
1810
|
# ++$$et{CHANGED};
|
1783
1811
|
}
|
1784
|
-
if ($curPath eq
|
1785
|
-
delete $$addDirs{
|
1786
|
-
delete $$et{
|
1812
|
+
if ($curPath eq "$keysPath-Meta") {
|
1813
|
+
delete $$addDirs{$keysGrp}; # prevent creation of another Meta for Keys tags
|
1814
|
+
delete $$et{$keysGrp};
|
1787
1815
|
}
|
1788
1816
|
}
|
1789
1817
|
|
@@ -2111,6 +2139,7 @@ sub WriteMOV($$)
|
|
2111
2139
|
$raf->Seek(0,0);
|
2112
2140
|
|
2113
2141
|
# write the file
|
2142
|
+
$$et{MediaType} = '';
|
2114
2143
|
$$dirInfo{Parent} = '';
|
2115
2144
|
$$dirInfo{DirName} = 'MOV';
|
2116
2145
|
$$dirInfo{ChunkOffset} = [ ]; # (just to be safe)
|