exiftool_vendored 13.42.0 → 13.44.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 +30 -1
- data/bin/MANIFEST +2 -0
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +48 -48
- data/bin/exiftool +85 -80
- data/bin/lib/Image/ExifTool/Apple.pm +0 -1
- data/bin/lib/Image/ExifTool/BuildTagLookup.pm +2 -2
- data/bin/lib/Image/ExifTool/Canon.pm +23 -1
- data/bin/lib/Image/ExifTool/CanonCustom.pm +1 -1
- data/bin/lib/Image/ExifTool/DarwinCore.pm +2 -2
- data/bin/lib/Image/ExifTool/EXE.pm +1 -1
- data/bin/lib/Image/ExifTool/Exif.pm +1 -0
- data/bin/lib/Image/ExifTool/FLIR.pm +1 -1
- data/bin/lib/Image/ExifTool/FlashPix.pm +1 -1
- data/bin/lib/Image/ExifTool/FujiFilm.pm +2 -2
- data/bin/lib/Image/ExifTool/Geolocation.dat +0 -0
- data/bin/lib/Image/ExifTool/Geolocation.pm +1 -1
- data/bin/lib/Image/ExifTool/Geotag.pm +1 -1
- data/bin/lib/Image/ExifTool/Google.pm +2 -2
- data/bin/lib/Image/ExifTool/ICC_Profile.pm +0 -1
- data/bin/lib/Image/ExifTool/Import.pm +1 -1
- data/bin/lib/Image/ExifTool/Jpeg2000.pm +1 -1
- data/bin/lib/Image/ExifTool/Kandao.pm +399 -0
- data/bin/lib/Image/ExifTool/LNK.pm +1 -1
- data/bin/lib/Image/ExifTool/MRC.pm +4 -4
- data/bin/lib/Image/ExifTool/MWG.pm +1 -1
- data/bin/lib/Image/ExifTool/MacOS.pm +1 -2
- data/bin/lib/Image/ExifTool/Matroska.pm +56 -15
- data/bin/lib/Image/ExifTool/Microsoft.pm +1 -1
- data/bin/lib/Image/ExifTool/Nikon.pm +5 -5
- data/bin/lib/Image/ExifTool/NikonCustom.pm +5 -6
- data/bin/lib/Image/ExifTool/OpenEXR.pm +1 -1
- data/bin/lib/Image/ExifTool/PPM.pm +1 -1
- data/bin/lib/Image/ExifTool/Panasonic.pm +30 -6
- data/bin/lib/Image/ExifTool/PhaseOne.pm +17 -1
- data/bin/lib/Image/ExifTool/Plot.pm +2 -2
- data/bin/lib/Image/ExifTool/Protobuf.pm +2 -2
- data/bin/lib/Image/ExifTool/QuickTime.pm +48 -8
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +2 -2
- data/bin/lib/Image/ExifTool/README +5 -5
- data/bin/lib/Image/ExifTool/RIFF.pm +5 -4
- data/bin/lib/Image/ExifTool/Reconyx.pm +2 -2
- data/bin/lib/Image/ExifTool/Samsung.pm +11 -1
- data/bin/lib/Image/ExifTool/Sony.pm +13 -3
- data/bin/lib/Image/ExifTool/TNEF.pm +2 -2
- data/bin/lib/Image/ExifTool/TagLookup.pm +7129 -7108
- data/bin/lib/Image/ExifTool/TagNames.pod +257 -110
- data/bin/lib/Image/ExifTool/Text.pm +1 -1
- data/bin/lib/Image/ExifTool/Trailer.pm +1 -1
- data/bin/lib/Image/ExifTool/WriteQuickTime.pl +10 -2
- data/bin/lib/Image/ExifTool/Writer.pl +3 -2
- data/bin/lib/Image/ExifTool/XMP.pm +4 -2
- data/bin/lib/Image/ExifTool/ZIP.pm +1 -1
- data/bin/lib/Image/ExifTool.pm +5 -2
- data/bin/lib/Image/ExifTool.pod +79 -79
- data/bin/perl-Image-ExifTool.spec +47 -47
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +2 -1
|
@@ -346,7 +346,7 @@ or "Rights-en-US"). (See L<http://www.ietf.org/rfc/rfc3066.txt> for the RFC
|
|
|
346
346
|
3066 specification.) A C<lang-alt> tag with no language code accesses the
|
|
347
347
|
"x-default" language, but causes other languages for this tag to be deleted
|
|
348
348
|
when writing. The "x-default" language code may be specified when writing
|
|
349
|
-
to preserve other existing languages (eg. "XMP-dc:Description-x-default").
|
|
349
|
+
to preserve other existing languages (eg. "XMP-dc:Description-x-default").
|
|
350
350
|
When reading, "x-default" is not specified.
|
|
351
351
|
|
|
352
352
|
The XMP tags are organized according to schema B<Namespace> in the following
|
|
@@ -629,7 +629,7 @@ and RPM).
|
|
|
629
629
|
Extra => q{
|
|
630
630
|
The extra tags provide extra features or extra information extracted or
|
|
631
631
|
generated by ExifTool that is not directly associated with another tag
|
|
632
|
-
group. The B<Group> column lists the family 1 group name when reading.
|
|
632
|
+
group. The B<Group> column lists the family 1 group name when reading.
|
|
633
633
|
Tags with a "-" in this column are write-only.
|
|
634
634
|
|
|
635
635
|
Tags in the family 1 "System" group are referred to as "pseudo" tags because
|
|
@@ -88,7 +88,7 @@ sub ProcessCTMD($$$);
|
|
|
88
88
|
sub ProcessExifInfo($$$);
|
|
89
89
|
sub SwapWords($);
|
|
90
90
|
|
|
91
|
-
$VERSION = '
|
|
91
|
+
$VERSION = '5.00';
|
|
92
92
|
|
|
93
93
|
# Note: Removed 'USM' from 'L' lenses since it is redundant - PH
|
|
94
94
|
# (or is it? Ref 32 shows 5 non-USM L-type lenses)
|
|
@@ -492,6 +492,7 @@ $VERSION = '4.99';
|
|
|
492
492
|
'368.12' => 'Sigma 18-35mm f/1.8 DC HSM | A', #50
|
|
493
493
|
'368.13' => 'Sigma 24-105mm f/4 DG OS HSM | A', #forum3833
|
|
494
494
|
'368.14' => 'Sigma 18-300mm f/3.5-6.3 DC Macro OS HSM | C', #forum15280 (014)
|
|
495
|
+
'368.15' => 'Sigma 24mm F1.4 DG HSM | A', #50 (015)
|
|
495
496
|
# Note: LensType 488 (0x1e8) is reported as 232 (0xe8) in 7D CameraSettings
|
|
496
497
|
488 => 'Canon EF-S 15-85mm f/3.5-5.6 IS USM', #PH
|
|
497
498
|
489 => 'Canon EF 70-300mm f/4-5.6L IS USM', #Gerald Kapounek
|
|
@@ -1423,6 +1424,11 @@ my %offOn = ( 0 => 'Off', 1 => 'On' );
|
|
|
1423
1424
|
Condition => '$$self{Model} =~ /\bEOS (R6m2|R8|R50)$/',
|
|
1424
1425
|
SubDirectory => { TagTable => 'Image::ExifTool::Canon::CameraInfoR6m2' },
|
|
1425
1426
|
},
|
|
1427
|
+
{
|
|
1428
|
+
Name => 'CanonCameraInfoR6m3',
|
|
1429
|
+
Condition => '$$self{Model} =~ /\bEOS R6 Mark III$/',
|
|
1430
|
+
SubDirectory => { TagTable => 'Image::ExifTool::Canon::CameraInfoR6m3' },
|
|
1431
|
+
},
|
|
1426
1432
|
{
|
|
1427
1433
|
Name => 'CanonCameraInfoG5XII',
|
|
1428
1434
|
Condition => '$$self{Model} =~ /\bG5 X Mark II$/',
|
|
@@ -4794,6 +4800,22 @@ my %ciMaxFocal = (
|
|
|
4794
4800
|
},
|
|
4795
4801
|
);
|
|
4796
4802
|
|
|
4803
|
+
%Image::ExifTool::Canon::CameraInfoR6m3 = (
|
|
4804
|
+
%binaryDataAttrs,
|
|
4805
|
+
FIRST_ENTRY => 0,
|
|
4806
|
+
PRIORITY => 0,
|
|
4807
|
+
GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
|
|
4808
|
+
NOTES => 'CameraInfo tags for the EOS R6 Mark II.',
|
|
4809
|
+
0x086d => { #forum17745
|
|
4810
|
+
Name => 'ShutterCount',
|
|
4811
|
+
Format => 'int32u',
|
|
4812
|
+
# (upper 2 bytes are currently unknown for this tag in JPEG images --
|
|
4813
|
+
# we need samples ideally spanning the 65536 count)
|
|
4814
|
+
RawConv => '$$self{PATH}[2] eq "UUID-Canon" ? $val : $val & 0xffff',
|
|
4815
|
+
Notes => 'includes electronic + mechanical shutter',
|
|
4816
|
+
},
|
|
4817
|
+
);
|
|
4818
|
+
|
|
4797
4819
|
# ref https://exiftool.org/forum/index.php?topic=15356.0
|
|
4798
4820
|
%Image::ExifTool::Canon::CameraInfoG5XII = (
|
|
4799
4821
|
%binaryDataAttrs,
|
|
@@ -1362,7 +1362,7 @@ my %convPFn = ( PrintConv => \&ConvertPfn, PrintConvInv => \&ConvertPfnInv );
|
|
|
1362
1362
|
PrintConvInv => '$val=~/0x([\dA-F]+)/i ? hex($1) : undef',
|
|
1363
1363
|
},{
|
|
1364
1364
|
Name => 'UsableMeteringModes',
|
|
1365
|
-
Count => 2,
|
|
1365
|
+
Count => 2,
|
|
1366
1366
|
PrintConv => [
|
|
1367
1367
|
\%disableEnable,
|
|
1368
1368
|
'sprintf("Flags 0x%x",$val)', # (evaluative,partial,spot,center-weighted average)
|
|
@@ -296,7 +296,7 @@ my %event = (
|
|
|
296
296
|
taxonomicStatus => { },
|
|
297
297
|
verbatimTaxonRank => { },
|
|
298
298
|
vernacularName => { Writable => 'lang-alt' },
|
|
299
|
-
superFamily => { }, # dwc.tdwg.org added 2023
|
|
299
|
+
superFamily => { }, # dwc.tdwg.org added 2023
|
|
300
300
|
subFamily => { }, # dwc.tdwg.org added 2023
|
|
301
301
|
tribe => { }, # dwc.tdwg.org added 2023
|
|
302
302
|
subTribe => { }, # dwc.tdwg.org added 2023
|
|
@@ -332,7 +332,7 @@ my %event = (
|
|
|
332
332
|
georeferenceProtocol => { },
|
|
333
333
|
georeferenceRemarks => { },
|
|
334
334
|
georeferenceSources => { },
|
|
335
|
-
georeferenceVerificationStatus => { }, # dwc.tdwg.org removed 2023
|
|
335
|
+
georeferenceVerificationStatus => { }, # dwc.tdwg.org removed 2023
|
|
336
336
|
higherGeography => { },
|
|
337
337
|
higherGeographyID => { },
|
|
338
338
|
island => { },
|
|
@@ -1113,7 +1113,7 @@ sub ProcessPEResources($$)
|
|
|
1113
1113
|
#------------------------------------------------------------------------------
|
|
1114
1114
|
# Process Windows PE file data dictionary
|
|
1115
1115
|
# Inputs: 0) ExifTool object ref, 1) dirInfo ref
|
|
1116
|
-
# Returns: true on success or if the PE resources didn't exist, or false on error
|
|
1116
|
+
# Returns: true on success or if the PE resources didn't exist, or false on error
|
|
1117
1117
|
# processing the PE resources
|
|
1118
1118
|
sub ProcessPEDict($$)
|
|
1119
1119
|
{
|
|
@@ -1598,6 +1598,7 @@ my %opcodeInfo = (
|
|
|
1598
1598
|
2 => 'Sony Compressed RAW', # (lossy, ref IB)
|
|
1599
1599
|
3 => 'Sony Lossless Compressed RAW', #IB
|
|
1600
1600
|
4 => 'Sony Lossless Compressed RAW 2', #JR (ILCE-1)
|
|
1601
|
+
6 => 'Sony Compressed RAW HQ', # ILCE-7M5
|
|
1601
1602
|
},
|
|
1602
1603
|
},
|
|
1603
1604
|
# 0x7001 - int16u[1] (in SubIFD of Sony ARW images) - values: 0,1
|
|
@@ -479,7 +479,7 @@ my %float8g = ( Format => 'float', PrintConv => 'sprintf("%.8g",$val)' );
|
|
|
479
479
|
VARS => { ID_FMT => 'none' },
|
|
480
480
|
NOTES => q{
|
|
481
481
|
Tags listed below are only for the first measurement tool, however multiple
|
|
482
|
-
measurements may be added, and information is extracted for all of them.
|
|
482
|
+
measurements may be added, and information is extracted for all of them.
|
|
483
483
|
Tags for subsequent measurements are generated as required with the prefixes
|
|
484
484
|
"Meas2", "Meas3", etc.
|
|
485
485
|
},
|
|
@@ -1454,7 +1454,7 @@ sub ProcessContents($$$)
|
|
|
1454
1454
|
my ($w, $h) = unpack('V2',$2);
|
|
1455
1455
|
$et->FoundTag(ImageWidth => $w);
|
|
1456
1456
|
$et->FoundTag(ImageHeight => $h);
|
|
1457
|
-
$et->HandleTag($tagTablePtr, OriginalFileName => $name);
|
|
1457
|
+
$et->HandleTag($tagTablePtr, OriginalFileName => $name);
|
|
1458
1458
|
if ($$dataPt =~ /\G\x01\0{4}(.{12})/sg) {
|
|
1459
1459
|
# (first 4 bytes seem to be number of objects, next 4 bytes are zero, then ICC size)
|
|
1460
1460
|
my $size = unpack('x8V', $1);
|
|
@@ -876,7 +876,7 @@ my %faceCategories = (
|
|
|
876
876
|
0x144a => { Name => 'WBRed', Writable => 'int16u' },
|
|
877
877
|
0x144b => { Name => 'WBGreen', Writable => 'int16u' },
|
|
878
878
|
0x144c => { Name => 'WBBlue', Writable => 'int16u' },
|
|
879
|
-
|
|
879
|
+
|
|
880
880
|
0x144d => { Name => 'RollAngle', Writable => 'rational64s' }, #forum14319
|
|
881
881
|
0x3803 => { #forum10037
|
|
882
882
|
Name => 'VideoRecordingMode',
|
|
@@ -1942,7 +1942,7 @@ sub ProcessRAF($$)
|
|
|
1942
1942
|
$et->SetFileType() unless $$et{DOC_NUM};
|
|
1943
1943
|
my $tbl = GetTagTable('Image::ExifTool::FujiFilm::RAFHeader');
|
|
1944
1944
|
$et->ProcessDirectory({ DataPt => \$buff, DirName => 'RAFHeader', Base => $base }, $tbl);
|
|
1945
|
-
|
|
1945
|
+
|
|
1946
1946
|
# extract information from embedded JPEG
|
|
1947
1947
|
my %dirInfo = (
|
|
1948
1948
|
Parent => 'RAF',
|
|
Binary file
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
# Notes: Set $Image::ExifTool::Geolocation::geoDir to override the
|
|
13
13
|
# default directory containing the database file Geolocation.dat
|
|
14
14
|
# and the GeoLang directory with the alternate language files.
|
|
15
|
-
# If set, this directory is
|
|
15
|
+
# If set, this directory is
|
|
16
16
|
#
|
|
17
17
|
# AltNames.dat may be loaded from a different directory by
|
|
18
18
|
# specifying $Image::ExifTool::Geolocation::altDir. This
|
|
@@ -1269,7 +1269,7 @@ Category: foreach $category (qw{pos track alt orient atemp err dop}) {
|
|
|
1269
1269
|
my $tag = ($$nvHash{WantGroup} ? "$$nvHash{WantGroup}:" : '') . 'Geolocate';
|
|
1270
1270
|
# pass along any regular expressions to qualify geolocation search
|
|
1271
1271
|
my $parms = join ',', grep m(/), split /\s*,\s*/, $geoloc;
|
|
1272
|
-
$parms and $parms = ",$parms,both";
|
|
1272
|
+
$parms and $parms = ",$parms,both";
|
|
1273
1273
|
$et->SetNewValue($tag => "$$fix{lat},$$fix{lon}$parms");
|
|
1274
1274
|
# (the Geolocate tag will be restored to its original value
|
|
1275
1275
|
# by RestoreNewValues before the next file in batch processing)
|
|
@@ -47,7 +47,7 @@ my %sEarthPose = (
|
|
|
47
47
|
NAMESPACE => { EarthPose => 'http://ns.google.com/photos/dd/1.0/earthpose/' },
|
|
48
48
|
Latitude => {
|
|
49
49
|
Writable => 'real',
|
|
50
|
-
Groups => { 2 => 'Location' },
|
|
50
|
+
Groups => { 2 => 'Location' },
|
|
51
51
|
ValueConv => 'Image::ExifTool::GPS::ToDegrees($val, 1)',
|
|
52
52
|
ValueConvInv => '$val',
|
|
53
53
|
PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")',
|
|
@@ -512,7 +512,7 @@ my %sAppInfo = (
|
|
|
512
512
|
GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
|
|
513
513
|
TAG_PREFIX => 'HDRPlusMakerNote',
|
|
514
514
|
PROCESS_PROC => \&ProcessHDRP,
|
|
515
|
-
VARS => {
|
|
515
|
+
VARS => {
|
|
516
516
|
ID_FMT => 'str',
|
|
517
517
|
SORT_PROC => sub {
|
|
518
518
|
my ($a,$b) = @_;
|
|
@@ -335,7 +335,7 @@ Read CSV or JSON file into a database hash.
|
|
|
335
335
|
|
|
336
336
|
1) Hash reference for database object.
|
|
337
337
|
|
|
338
|
-
2) Optional string used to represent an undefined (missing) tag value.
|
|
338
|
+
2) Optional string used to represent an undefined (missing) tag value.
|
|
339
339
|
(Used for deleting tags.)
|
|
340
340
|
|
|
341
341
|
3) For ReadCSV this gives the delimiter for CSV entries, with a default of
|
|
@@ -132,7 +132,7 @@ my %j2cMarker = (
|
|
|
132
132
|
NOTES => q{
|
|
133
133
|
The tags below are found in JPEG 2000 images and the C2PA CAI JUMBF metadata
|
|
134
134
|
in various file types (see below). Note that ExifTool currently writes only
|
|
135
|
-
EXIF, IPTC and XMP tags in Jpeg2000 images, and EXIF and XMP in JXL images.
|
|
135
|
+
EXIF, IPTC and XMP tags in Jpeg2000 images, and EXIF and XMP in JXL images.
|
|
136
136
|
ExifTool will read/write Brotli-compressed EXIF and XMP in JXL images, but
|
|
137
137
|
the API L<Compress|../ExifTool.html#Compress> option must be set to create new EXIF and XMP in compressed
|
|
138
138
|
format.
|
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
#------------------------------------------------------------------------------
|
|
2
|
+
# File: Kandao.pm
|
|
3
|
+
#
|
|
4
|
+
# Description: Read Kandao MP4 metadata
|
|
5
|
+
#
|
|
6
|
+
# Revisions: 2025-12-10 - P. Harvey Created
|
|
7
|
+
#
|
|
8
|
+
# Notes: Tested with videos from the Kandao QooCam 3 Ultra
|
|
9
|
+
#------------------------------------------------------------------------------
|
|
10
|
+
|
|
11
|
+
package Image::ExifTool::Kandao;
|
|
12
|
+
|
|
13
|
+
use strict;
|
|
14
|
+
use vars qw($VERSION);
|
|
15
|
+
use Image::ExifTool qw(:DataAccess :Utils);
|
|
16
|
+
|
|
17
|
+
$VERSION = '1.00';
|
|
18
|
+
|
|
19
|
+
sub ProcessKandao($$$);
|
|
20
|
+
sub ProcessKVAR($$);
|
|
21
|
+
|
|
22
|
+
# Kandao format codes
|
|
23
|
+
my %format = (
|
|
24
|
+
CHAR => 'string',
|
|
25
|
+
BOOL => 'int8u',
|
|
26
|
+
U8 => 'int8u',
|
|
27
|
+
U16 => 'int16u',
|
|
28
|
+
U32 => 'int32u',
|
|
29
|
+
U64 => 'int64u',
|
|
30
|
+
S8 => 'int8s',
|
|
31
|
+
S16 => 'int16s',
|
|
32
|
+
S32 => 'int32s',
|
|
33
|
+
S64 => 'int64s',
|
|
34
|
+
FLOAT => 'float',
|
|
35
|
+
DOUBLE => 'double',
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
# Kandao 'kvar' and 'kfix' information
|
|
39
|
+
%Image::ExifTool::Kandao::Main = (
|
|
40
|
+
GROUPS => { 0 => 'Kandao', 1 => 'KVAR', 2 => 'Camera' },
|
|
41
|
+
VARS => { NO_LOOKUP => 1 },
|
|
42
|
+
NOTES => q{
|
|
43
|
+
Tags extracted from Kandao KVAR files and the 'kvar', 'kfix' and 'kstb'
|
|
44
|
+
atoms in Kandao MP4 videos, and have a family 1 group name of KVAR, KFIX or
|
|
45
|
+
KSTB depending on their location.
|
|
46
|
+
},
|
|
47
|
+
PROCESS_PROC => \&ProcessKandao,
|
|
48
|
+
#
|
|
49
|
+
# 'kvar' tags
|
|
50
|
+
#
|
|
51
|
+
CPU_TEMP => { Name => 'CPUTemperature', ValueConv => '$val / 10' }, # U32[1]
|
|
52
|
+
BAT_TEMP => 'BatteryTemperature', # U32[1]
|
|
53
|
+
PTS_UNIT => { # U32[1]
|
|
54
|
+
Name => 'TimeStampUnit',
|
|
55
|
+
PrintConv => { 0 => 'ms', 1 => 'Subtle', 2 => 'ns' },
|
|
56
|
+
},
|
|
57
|
+
TOTAL_FRAME => 'TotalFrames', # U32[1]
|
|
58
|
+
TOTAL_TIME_MS => { # U32[1]
|
|
59
|
+
Name => 'TotalTime',
|
|
60
|
+
ValueConv => '$val / 1000',
|
|
61
|
+
},
|
|
62
|
+
LENS => 'LensData', # CHAR[534]
|
|
63
|
+
DASHBOARD => 'Dashboard', # U8[1]
|
|
64
|
+
PROJECTION => 'Projection', # CHAR[16]
|
|
65
|
+
CENTER_SHIFT => 'CenterShift', # DOUBLE[1]
|
|
66
|
+
DISTORTION => 'Distortion', # DOUBLE[1]
|
|
67
|
+
INFO => 'Info', # CHAR[239]
|
|
68
|
+
PTS => {
|
|
69
|
+
Name => 'PresentationTimeStamp',
|
|
70
|
+
Notes => 'TimeStamp for each frame',
|
|
71
|
+
Format => 'undef', # U64[x]
|
|
72
|
+
Binary => 1,
|
|
73
|
+
},
|
|
74
|
+
LENS_SN0 => 'Lens0SerialNumber', # CHAR[15]
|
|
75
|
+
LENS_SN1 => 'Lens1SerialNumber', # CHAR[15]
|
|
76
|
+
LENS_OTP_ID0 => 'Lens0OTP_ID', # U8[1]
|
|
77
|
+
LENS_OTP_ID1 => 'Lens1OTP_ID', # U8[1]
|
|
78
|
+
IMU => {
|
|
79
|
+
RecordSize => 20,
|
|
80
|
+
SubDirectory => { TagTable => 'Image::ExifTool::Kandao::IMU' },
|
|
81
|
+
},
|
|
82
|
+
GPS => [{
|
|
83
|
+
Condition => '$$valPt =~ /^\xff{4}/',
|
|
84
|
+
RecordSize => 28,
|
|
85
|
+
SubDirectory => {
|
|
86
|
+
TagTable => 'Image::ExifTool::Kandao::GPS',
|
|
87
|
+
Start => 4,
|
|
88
|
+
},
|
|
89
|
+
},{
|
|
90
|
+
RecordSize => 20,
|
|
91
|
+
SubDirectory => {
|
|
92
|
+
TagTable => 'Image::ExifTool::Kandao::GPS',
|
|
93
|
+
},
|
|
94
|
+
}],
|
|
95
|
+
GPSX => {
|
|
96
|
+
RecordSize => 36,
|
|
97
|
+
SubDirectory => { TagTable => 'Image::ExifTool::Kandao::GPSX' },
|
|
98
|
+
},
|
|
99
|
+
EXP => { # U8[x]
|
|
100
|
+
# actually int64u - monotonically increasing
|
|
101
|
+
Name => 'Exp',
|
|
102
|
+
},
|
|
103
|
+
# (ISP = Image Signal Processor)
|
|
104
|
+
ISP => 'ISP', # U8 - 46-byte records (not very interesting looking)
|
|
105
|
+
FRAME_ISP => {
|
|
106
|
+
# U8 - 12-byte records: int32u-ts, float, float
|
|
107
|
+
RecordSize => 12,
|
|
108
|
+
SubDirectory => { TagTable => 'Image::ExifTool::Kandao::FrameISP' },
|
|
109
|
+
},
|
|
110
|
+
GAINMAP0 => 'GainMap0',
|
|
111
|
+
GAINMAP1 => 'GainMap1',
|
|
112
|
+
#
|
|
113
|
+
# 'kfix' tags
|
|
114
|
+
#
|
|
115
|
+
PRODUCT => 'Model',
|
|
116
|
+
PROJECT => 'Project',
|
|
117
|
+
SN => 'SerialNumber',
|
|
118
|
+
PR_VER => 'ProductVersion',
|
|
119
|
+
SW_VER => 'SoftwareVersion',
|
|
120
|
+
HW_VER => 'HardwareVersion',
|
|
121
|
+
VIDEO_CAPTIME => {
|
|
122
|
+
Name => 'VideoCaptureTime',
|
|
123
|
+
Notes => 'local camera time',
|
|
124
|
+
Groups => { 2 => 'Time' },
|
|
125
|
+
ValueConv => '$val =~ s/^(\d{4})-(\d{2})-/$1:$2:/; $val',
|
|
126
|
+
PrintConv => '$self->ConvertDateTime($val)',
|
|
127
|
+
},
|
|
128
|
+
GPS_CAPTIME => {
|
|
129
|
+
Name => 'GPSCaptureTime',
|
|
130
|
+
Groups => { 2 => 'Time' },
|
|
131
|
+
ValueConv => 'ConvertUnixTime($val/1000, 0, 3) . "Z"',
|
|
132
|
+
PrintConv => '$self->ConvertDateTime($val)',
|
|
133
|
+
},
|
|
134
|
+
LENS_INDEX => { Name => 'LensIndex', Format => 'int16u' },
|
|
135
|
+
NEED_LSC => 'NeedLDSC',
|
|
136
|
+
# (also in 'kvar') CPU_TEMP => { Name => 'CPUTemperature', ValueConv => '$val / 10' },
|
|
137
|
+
# (also in 'kvar') BAT_TEMP => 'BatteryTemperature',
|
|
138
|
+
INPUT_INSERT => 'InputInsert',
|
|
139
|
+
VIDEO_RESOLUTION => 'VideoResolution',
|
|
140
|
+
VIDEO_CODECTYPE => 'VideoCodec',
|
|
141
|
+
VIDEO_BITRATE => { Name => 'VideoBitrate', PrintConv => '($val / 1e6) . " Mbps"' },
|
|
142
|
+
VIDEO_FORMAT => 'VideoFormat',
|
|
143
|
+
OUTPUT_INSERT => 'OutputInsert',
|
|
144
|
+
DYNAMIC_RANGE => 'DynamicRange',
|
|
145
|
+
AWB_CCT => 'AWB_CCT',
|
|
146
|
+
EV => 'EV',
|
|
147
|
+
ISO => 'ISO',
|
|
148
|
+
SHUTTER => 'Shutter',
|
|
149
|
+
IMAGE_STYLE => 'ImageStyle',
|
|
150
|
+
AE_METERING => 'AEMetering',
|
|
151
|
+
CAPTURE_MODE => 'CaptureMode',
|
|
152
|
+
HDR => 'HDR',
|
|
153
|
+
STITCHED => 'Stitched',
|
|
154
|
+
COVER_MODE => 'CoverMode',
|
|
155
|
+
STEREO => 'Stereo',
|
|
156
|
+
FOV => 'FOV',
|
|
157
|
+
AE_MODE => 'AEMode',
|
|
158
|
+
AF_FN => 'AF_FN',
|
|
159
|
+
AWB_MODE => 'AWBMode',
|
|
160
|
+
AUDIO_GAIN => 'AudioGain',
|
|
161
|
+
INTERVAL => 'Interval',
|
|
162
|
+
ISP_VER => 'ISPVersion',
|
|
163
|
+
YAW => 'Yaw',
|
|
164
|
+
FAN_LEVEL => 'FanLevel',
|
|
165
|
+
FAN_MODE => 'FanMode',
|
|
166
|
+
CUSTOMIZED => 'Customized',
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
%Image::ExifTool::Kandao::GPS = (
|
|
170
|
+
GROUPS => { 0 => 'Kandao', 1 => 'KVAR', 2 => 'Location' },
|
|
171
|
+
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
|
172
|
+
NOTES => q{
|
|
173
|
+
These tags are in the family 1 KVAR group instead of a GPS group to allow
|
|
174
|
+
them to be distinguished from the duplicate GPS tags in the GPSX table.
|
|
175
|
+
},
|
|
176
|
+
0 => { Name => 'TimeStamp', Format => 'int32u' },
|
|
177
|
+
4 => {
|
|
178
|
+
Name => 'GPSLatitude',
|
|
179
|
+
Format => 'double',
|
|
180
|
+
ValueConv => 'Image::ExifTool::GPS::ToDegrees($val, 1)',
|
|
181
|
+
PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")',
|
|
182
|
+
},
|
|
183
|
+
12 => {
|
|
184
|
+
Name => 'GPSLongitude',
|
|
185
|
+
Format => 'double',
|
|
186
|
+
ValueConv => 'Image::ExifTool::GPS::ToDegrees($val, 1)',
|
|
187
|
+
PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")',
|
|
188
|
+
},
|
|
189
|
+
20 => { # (optional)
|
|
190
|
+
Name => 'GPSAltitude',
|
|
191
|
+
Format => 'double',
|
|
192
|
+
PrintConv => '$_ = sprintf("%.6f", $val); s/\.?0+$//; "$_ m"',
|
|
193
|
+
},
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
%Image::ExifTool::Kandao::GPSX = (
|
|
197
|
+
GROUPS => { 0 => 'Kandao', 1 => 'GPS', 2 => 'Location' },
|
|
198
|
+
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
|
199
|
+
NOTES => q(
|
|
200
|
+
These tags are in the family 1 GPS group. They are duplicates of the tags
|
|
201
|
+
in the Kandao GPS table with the addition of GPSDateTime.
|
|
202
|
+
),
|
|
203
|
+
0 => { Name => 'TimeStamp', Format => 'int32u' },
|
|
204
|
+
4 => {
|
|
205
|
+
Name => 'GPSDateTime',
|
|
206
|
+
Description => 'GPS Date/Time',
|
|
207
|
+
Groups => { 2 => 'Time' },
|
|
208
|
+
Format => 'int64u',
|
|
209
|
+
ValueConv => 'ConvertUnixTime($val/1000, 0, 3) . "Z"',
|
|
210
|
+
PrintConv => '$self->ConvertDateTime($val)',
|
|
211
|
+
},
|
|
212
|
+
12 => {
|
|
213
|
+
Name => 'GPSLatitude',
|
|
214
|
+
Format => 'double',
|
|
215
|
+
ValueConv => 'Image::ExifTool::GPS::ToDegrees($val, 1)',
|
|
216
|
+
PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")',
|
|
217
|
+
},
|
|
218
|
+
20 => {
|
|
219
|
+
Name => 'GPSLongitude',
|
|
220
|
+
Format => 'double',
|
|
221
|
+
ValueConv => 'Image::ExifTool::GPS::ToDegrees($val, 1)',
|
|
222
|
+
PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")',
|
|
223
|
+
},
|
|
224
|
+
28 => {
|
|
225
|
+
Name => 'GPSAltitude',
|
|
226
|
+
Format => 'double',
|
|
227
|
+
PrintConv => '$_ = sprintf("%.6f", $val); s/\.?0+$//; "$_ m"',
|
|
228
|
+
},
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
# IMU gyroscope data
|
|
232
|
+
%Image::ExifTool::Kandao::IMU = (
|
|
233
|
+
GROUPS => { 0 => 'Kandao', 1 => 'KVAR', 2 => 'Location' },
|
|
234
|
+
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
|
235
|
+
0 => { Name => 'TimeStamp', Format => 'int64u' },
|
|
236
|
+
8 => { Name => 'Gyroscope', Format => 'int16s[3]' }, # 2G max range
|
|
237
|
+
14=> { Name => 'Accelerometer', Format => 'int16s[3]' }, # 2000 deg/sec max range
|
|
238
|
+
# (Kandao docs mention optional 6-byte Magnetometer data here, but
|
|
239
|
+
# with no way to determine if it exists, and it isn't in my samples)
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
# (ISP = Image Signal Processor?)
|
|
243
|
+
%Image::ExifTool::Kandao::FrameISP = (
|
|
244
|
+
GROUPS => { 0 => 'Kandao', 1 => 'KVAR', 2 => 'Other' },
|
|
245
|
+
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
|
246
|
+
0 => { Name => 'TimeStamp', Format => 'int32u', Unknown => 1 },
|
|
247
|
+
4 => { Name => 'FrameISP_4', Format => 'float[2]', Unknown => 1 },
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
#------------------------------------------------------------------------------
|
|
251
|
+
# Extract information from a Kandao 'kfix' and 'kvar' atoms
|
|
252
|
+
# Inputs: 0) ExifTool ref, 1) dirInfo reference, 2) tag table ref
|
|
253
|
+
# Returns: 1 on success
|
|
254
|
+
sub ProcessKandao($$$)
|
|
255
|
+
{
|
|
256
|
+
my ($et, $dirInfo, $tagTbl) = @_;
|
|
257
|
+
my $raf = $$dirInfo{RAF};
|
|
258
|
+
$raf or $raf = File::RandomAccess->new($$dirInfo{DataPt});
|
|
259
|
+
my $dirName = $$dirInfo{DirName};
|
|
260
|
+
my $dataPos = ($$dirInfo{DataPos} || 0) + ($$dirInfo{Base} || 0);
|
|
261
|
+
my $verbose = $et->Options('Verbose');
|
|
262
|
+
my $ee = $et->Options('ExtractEmbedded');
|
|
263
|
+
# extract as a block from MP4 if specified
|
|
264
|
+
if ($$dirInfo{BlockInfo}) {
|
|
265
|
+
my $blockName = $$dirInfo{BlockInfo}{Name};
|
|
266
|
+
my $blockExtract = $et->Options('BlockExtract');
|
|
267
|
+
if (($blockExtract or $$et{REQ_TAG_LOOKUP}{lc $blockName} or
|
|
268
|
+
($$et{TAGS_FROM_FILE} and not $$et{EXCL_TAG_LOOKUP}{lc $blockName})))
|
|
269
|
+
{
|
|
270
|
+
$et->FoundTag($$dirInfo{BlockInfo}, $$dirInfo{DataPt});
|
|
271
|
+
return 1 if $blockExtract and $blockExtract > 1;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
my ($buff, $err, $i, $tag, $fmt);
|
|
275
|
+
SetByteOrder('II');
|
|
276
|
+
$raf->Read($buff, 4) == 4 or return 0;
|
|
277
|
+
my $n = Get32u(\$buff, 0);
|
|
278
|
+
$et->VerboseDir($dirName, $n);
|
|
279
|
+
for ($i=0; $i<$n; ++$i) {
|
|
280
|
+
$raf->Read($buff, 0x2c) == 0x2c or $err = '', last;
|
|
281
|
+
($tag = substr($buff, 0, 0x20)) =~ s/\0+$//;
|
|
282
|
+
($fmt = substr($buff, 0x20, 8)) =~ s/\0+$//;
|
|
283
|
+
my $format = $format{$fmt};
|
|
284
|
+
$format or $err = "Unknown Kandao format '${fmt}'", last;
|
|
285
|
+
my $num = Get32u(\$buff, 0x28);
|
|
286
|
+
my $size = $num * Image::ExifTool::FormatSize($format);
|
|
287
|
+
my %parms = (
|
|
288
|
+
DataPt => \$buff,
|
|
289
|
+
DataPos => $dataPos + $raf->Tell(),
|
|
290
|
+
Index => $i,
|
|
291
|
+
Format => $format,
|
|
292
|
+
);
|
|
293
|
+
$raf->Read($buff, $size) == $size or $err = '', last;
|
|
294
|
+
my $tagInfo = $et->GetTagInfo($tagTbl, $tag, \$buff);
|
|
295
|
+
unless ($tagInfo) {
|
|
296
|
+
my $name = ucfirst lc $tag;
|
|
297
|
+
$name =~ s/_([a-z])/_\u$1/g;
|
|
298
|
+
$name = Image::ExifTool::MakeTagName($name);
|
|
299
|
+
$et->VPrint(0, "$$et{INDENT}\[adding $dirName '${tag}']\n");
|
|
300
|
+
$tagInfo = AddTagToTable($tagTbl, $tag, { Name => $name });
|
|
301
|
+
}
|
|
302
|
+
my $recLen = $$tagInfo{RecordSize};
|
|
303
|
+
if ($recLen) {
|
|
304
|
+
$verbose and $et->VerboseInfo($tag, $tagInfo, %parms);
|
|
305
|
+
my $tbl = GetTagTable($$tagInfo{SubDirectory}{TagTable});
|
|
306
|
+
my $pt = $$tagInfo{SubDirectory}{Start} || 0;
|
|
307
|
+
my %dirInfo = (
|
|
308
|
+
DataPt => \$buff,,
|
|
309
|
+
DataPos => $parms{DataPos},
|
|
310
|
+
DirLen => $recLen,
|
|
311
|
+
DirName => $tag,
|
|
312
|
+
);
|
|
313
|
+
my $nLimit = 10000;
|
|
314
|
+
my $sizeLimit = $size;
|
|
315
|
+
if ($ee and int(($size - $pt) / $recLen) > $nLimit and
|
|
316
|
+
$et->Warn("Extracting only the first $nLimit $$tagInfo{Name} records", 2))
|
|
317
|
+
{
|
|
318
|
+
$sizeLimit = $pt + $recLen * $nLimit;
|
|
319
|
+
}
|
|
320
|
+
while ($pt+$recLen <= $sizeLimit) {
|
|
321
|
+
$$et{DOC_NUM} = ++$$et{DOC_COUNT};
|
|
322
|
+
$dirInfo{DirStart} = $pt;
|
|
323
|
+
$et->ProcessDirectory(\%dirInfo, $tbl);
|
|
324
|
+
$ee or $et->Warn('Use the ExtractEmbedded option to extract all timed metadata',7), last;
|
|
325
|
+
$pt += $recLen;
|
|
326
|
+
}
|
|
327
|
+
delete $$et{DOC_NUM};
|
|
328
|
+
} else {
|
|
329
|
+
my $val;
|
|
330
|
+
if ($fmt eq 'U8' and $num > 1 and not $$tagInfo{Format}) {
|
|
331
|
+
$val = \$buff;
|
|
332
|
+
} else {
|
|
333
|
+
# override format if necessary
|
|
334
|
+
if ($$tagInfo{Format}) {
|
|
335
|
+
$format = $$tagInfo{Format};
|
|
336
|
+
$parms{Format} .= " read as $format";
|
|
337
|
+
$num = int($size / Image::ExifTool::FormatSize($format));
|
|
338
|
+
}
|
|
339
|
+
$val = ReadValue(\$buff, 0, $format, $num, $size);
|
|
340
|
+
}
|
|
341
|
+
my $key = $et->HandleTag($tagTbl, $tag, $val, %parms);
|
|
342
|
+
$et->SetGroup($key, $dirName) if $dirName ne 'KVAR';
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
$et->Warn($err || "Truncated $dirName record") if defined $err;
|
|
346
|
+
return 1;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
#------------------------------------------------------------------------------
|
|
350
|
+
# Process Kandao KVAR file
|
|
351
|
+
# Inputs: 0) ExifTool ref, 1) dirInfo reference
|
|
352
|
+
# Returns: 1 on success, 0 if this wasn't a valid KVAR file
|
|
353
|
+
sub ProcessKVAR($$)
|
|
354
|
+
{
|
|
355
|
+
my ($et, $dirInfo) = @_;
|
|
356
|
+
my $raf = $$dirInfo{RAF};
|
|
357
|
+
my ($buff, $tagTablePtr);
|
|
358
|
+
|
|
359
|
+
# verify this is a valid KVAR file
|
|
360
|
+
return 0 unless $raf->Read($buff, 44) == 44;
|
|
361
|
+
return 0 unless $buff =~ /^.{2}\0\0[A-Z].{31}(CHAR|BOOL|[US](8|16|32|64)|FLOAT|DOUBLE)\0/s;
|
|
362
|
+
$et->SetFileType('KVAR', 'application/x-kandaostudio');
|
|
363
|
+
$raf->Seek(0,0) or $et->Warn('Seek error'), return 1;
|
|
364
|
+
$$dirInfo{DirName} = 'KVAR';
|
|
365
|
+
$tagTablePtr = GetTagTable('Image::ExifTool::Kandao::Main');
|
|
366
|
+
return $et->ProcessDirectory($dirInfo, $tagTablePtr);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
1; # end
|
|
370
|
+
|
|
371
|
+
__END__
|
|
372
|
+
|
|
373
|
+
=head1 NAME
|
|
374
|
+
|
|
375
|
+
Image::ExifTool::Kandao - Read Kandao MP4 metadata
|
|
376
|
+
|
|
377
|
+
=head1 SYNOPSIS
|
|
378
|
+
|
|
379
|
+
This module is used by Image::ExifTool
|
|
380
|
+
|
|
381
|
+
=head1 DESCRIPTION
|
|
382
|
+
|
|
383
|
+
This module contains code to extract metadata from Kandao 'kfix' and 'kvar'
|
|
384
|
+
atoms in MP4 videos as shot by the Kandao QOOCAM 3 ULTRA.
|
|
385
|
+
|
|
386
|
+
=head1 AUTHOR
|
|
387
|
+
|
|
388
|
+
Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
|
|
389
|
+
|
|
390
|
+
This library is free software; you can redistribute it and/or modify it
|
|
391
|
+
under the same terms as Perl itself.
|
|
392
|
+
|
|
393
|
+
=head1 SEE ALSO
|
|
394
|
+
|
|
395
|
+
L<Image::ExifTool::TagNames/Kandao Tags>,
|
|
396
|
+
L<Image::ExifTool(3pm)|Image::ExifTool>
|
|
397
|
+
|
|
398
|
+
=cut
|
|
399
|
+
|
|
@@ -596,7 +596,7 @@ sub ProcessLinkInfo($$$)
|
|
|
596
596
|
$off = Get32u($dataPt, 0x14);
|
|
597
597
|
if ($off and $off + 0x14 <= $dataLen) {
|
|
598
598
|
my $siz = Get32u($dataPt, $off);
|
|
599
|
-
return 0 if $off + $siz > $dataLen;
|
|
599
|
+
return 0 if $off + $siz > $dataLen;
|
|
600
600
|
$pos = Get32u($dataPt, $off + 0x08);
|
|
601
601
|
if ($pos > 0x14 and $siz >= 0x18) {
|
|
602
602
|
$pos = Get32u($dataPt, $off + 0x14);
|