exiftool_vendored 13.12.0 → 13.14.0
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|