exiftool_vendored 12.81.0 → 12.83.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 +39 -1
- data/bin/MANIFEST +4 -18
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +3 -2
- data/bin/build_geolocation +867 -0
- data/bin/exiftool +37 -9
- data/bin/fmt_files/gpx.fmt +2 -1
- data/bin/fmt_files/gpx_wpt.fmt +2 -1
- data/bin/lib/Image/ExifTool/BuildTagLookup.pm +47 -31
- data/bin/lib/Image/ExifTool/CanonVRD.pm +6 -5
- data/bin/lib/Image/ExifTool/DJI.pm +29 -0
- data/bin/lib/Image/ExifTool/Exif.pm +19 -2
- data/bin/lib/Image/ExifTool/FujiFilm.pm +9 -2
- data/bin/lib/Image/ExifTool/GM.pm +552 -0
- data/bin/lib/Image/ExifTool/Geolocation.dat +0 -0
- data/bin/lib/Image/ExifTool/Geolocation.pm +90 -54
- data/bin/lib/Image/ExifTool/Nikon.pm +9 -7
- data/bin/lib/Image/ExifTool/QuickTime.pm +31 -23
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +66 -30
- data/bin/lib/Image/ExifTool/README +2 -0
- data/bin/lib/Image/ExifTool/Sony.pm +15 -6
- data/bin/lib/Image/ExifTool/TagLookup.pm +37 -6
- data/bin/lib/Image/ExifTool/TagNames.pod +407 -239
- data/bin/lib/Image/ExifTool/WriteQuickTime.pl +5 -2
- data/bin/lib/Image/ExifTool/Writer.pl +165 -133
- data/bin/lib/Image/ExifTool/XMP.pm +3 -2
- data/bin/lib/Image/ExifTool/XMP2.pl +3 -0
- data/bin/lib/Image/ExifTool.pm +38 -9
- data/bin/lib/Image/ExifTool.pod +31 -18
- data/bin/perl-Image-ExifTool.spec +1 -1
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +4 -20
- data/bin/lib/Image/ExifTool/GeoLang/cs.pm +0 -978
- data/bin/lib/Image/ExifTool/GeoLang/de.pm +0 -1975
- data/bin/lib/Image/ExifTool/GeoLang/en_ca.pm +0 -44
- data/bin/lib/Image/ExifTool/GeoLang/en_gb.pm +0 -124
- data/bin/lib/Image/ExifTool/GeoLang/es.pm +0 -2921
- data/bin/lib/Image/ExifTool/GeoLang/fi.pm +0 -1116
- data/bin/lib/Image/ExifTool/GeoLang/fr.pm +0 -3171
- data/bin/lib/Image/ExifTool/GeoLang/it.pm +0 -2750
- data/bin/lib/Image/ExifTool/GeoLang/ja.pm +0 -10256
- data/bin/lib/Image/ExifTool/GeoLang/ko.pm +0 -4499
- data/bin/lib/Image/ExifTool/GeoLang/nl.pm +0 -1270
- data/bin/lib/Image/ExifTool/GeoLang/pl.pm +0 -3019
- data/bin/lib/Image/ExifTool/GeoLang/ru.pm +0 -18220
- data/bin/lib/Image/ExifTool/GeoLang/sk.pm +0 -441
- data/bin/lib/Image/ExifTool/GeoLang/sv.pm +0 -714
- data/bin/lib/Image/ExifTool/GeoLang/tr.pm +0 -452
- data/bin/lib/Image/ExifTool/GeoLang/zh_cn.pm +0 -2225
- data/bin/lib/Image/ExifTool/GeoLang/zh_tw.pm +0 -72
@@ -9,14 +9,15 @@
|
|
9
9
|
#
|
10
10
|
# References: https://download.geonames.org/export/
|
11
11
|
#
|
12
|
-
# Notes: Set $Image::ExifTool::Geolocation::geoDir to override
|
13
|
-
# default directory
|
14
|
-
# and
|
12
|
+
# Notes: Set $Image::ExifTool::Geolocation::geoDir to override the
|
13
|
+
# default directory containing the database file Geolocation.dat
|
14
|
+
# and the GeoLang directory with the alternate language files.
|
15
|
+
# If set, this directory is
|
15
16
|
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
# entry is a newline-separated list of alternate names
|
17
|
+
# AltNames.dat may be loaded from a different directory by
|
18
|
+
# specifying $Image::ExifTool::Geolocation::altDir. This
|
19
|
+
# database and has entries in the same order as Geolocation.dat,
|
20
|
+
# and each entry is a newline-separated list of alternate names
|
20
21
|
# terminated by a null byte.
|
21
22
|
#
|
22
23
|
# Databases are based on data from geonames.org with a
|
@@ -34,9 +35,10 @@
|
|
34
35
|
# 5 int8u - index of country in country list
|
35
36
|
# 6 int8u - 0xf0 = population E exponent (in format "N.Fe+0E"), 0x0f = population N digit
|
36
37
|
# 7 int16u - 0xf000 = population F digit, 0x0fff = index in region list (admin1)
|
37
|
-
# 9 int16u - 0x7fff = index in subregion (admin2), 0x8000 = high bit of time zone
|
38
|
+
# 9 int16u - v1.02: 0x7fff = index in subregion (admin2), 0x8000 = high bit of time zone
|
39
|
+
# 9 int16u - v1.03: index in subregion (admin2)
|
38
40
|
# 11 int8u - low byte of time zone index
|
39
|
-
# 12 int8u - 0x0f
|
41
|
+
# 12 int8u - 0x0f = feature code index (see below), v1.03: 0x80 = high bit of time zone
|
40
42
|
# 13 string - UTF8 City name, terminated by newline
|
41
43
|
# "\0\0\0\0\x01"
|
42
44
|
# Country entries:
|
@@ -51,11 +53,14 @@
|
|
51
53
|
# "\0\0\0\0\x04"
|
52
54
|
# Time zone entries:
|
53
55
|
# 1. Time zone name, terminated by newline
|
56
|
+
# "\0\0\0\0\x05" (feature codes added in v1.03)
|
57
|
+
# Feature codes:
|
58
|
+
# 1. Feature code, terminated by newline
|
54
59
|
# "\0\0\0\0\0"
|
55
60
|
#
|
56
|
-
# Feature Codes: (see http://www.geonames.org/export/codes.html#P for descriptions)
|
61
|
+
# Feature Codes (v1.02): (see http://www.geonames.org/export/codes.html#P for descriptions)
|
57
62
|
#
|
58
|
-
# 0. Other 3. PPLA2 6. PPLA5 9. PPLF 12. PPLR
|
63
|
+
# 0. Other 3. PPLA2 6. PPLA5 9. PPLF 12. PPLR 15. PPLX
|
59
64
|
# 1. PPL 4. PPLA3 7. PPLC 10. PPLG 13. PPLS
|
60
65
|
# 2. PPLA 5. PPLA4 8. PPLCH 11. PPLL 14. STLMT
|
61
66
|
#------------------------------------------------------------------------------
|
@@ -65,9 +70,7 @@ package Image::ExifTool::Geolocation;
|
|
65
70
|
use strict;
|
66
71
|
use vars qw($VERSION $geoDir $altDir $dbInfo);
|
67
72
|
|
68
|
-
$VERSION = '1.
|
69
|
-
|
70
|
-
my $databaseVersion = '1.02';
|
73
|
+
$VERSION = '1.06'; # (this is the module version number, not the database version)
|
71
74
|
|
72
75
|
my $debug; # set to output processing time for testing
|
73
76
|
|
@@ -79,16 +82,15 @@ sub Geolocate($;$$$$$);
|
|
79
82
|
|
80
83
|
my (@cityList, @countryList, @regionList, @subregionList, @timezoneList);
|
81
84
|
my (%countryNum, %regionNum, %subregionNum, %timezoneNum); # reverse lookups
|
82
|
-
my (@sortOrder, @altNames, %langLookup, $nCity);
|
85
|
+
my (@sortOrder, @altNames, %langLookup, $nCity, %featureCodes);
|
83
86
|
my ($lastArgs, %lastFound, @lastByPop, @lastByLat); # cached city matches
|
87
|
+
my $dbVer = '1.03';
|
84
88
|
my $sortedBy = 'Latitude';
|
85
89
|
my $pi = 3.1415926536;
|
86
90
|
my $earthRadius = 6371; # earth radius in km
|
87
|
-
|
88
|
-
my @featureCodes = qw(Other PPL PPLA PPLA2 PPLA3 PPLA4 PPLA5
|
89
|
-
|
90
|
-
my $i = 0;
|
91
|
-
my %featureCodes = map { lc($_) => $i++ } @featureCodes;
|
91
|
+
# hard-coded feature codes for v1.02 database
|
92
|
+
my @featureCodes = qw(Other PPL PPLA PPLA2 PPLA3 PPLA4 PPLA5 PPLC
|
93
|
+
PPLCH PPLF PPLG PPLL PPLR PPLS STLMT PPLX);
|
92
94
|
|
93
95
|
# get path name for database file from lib/Image/ExifTool/Geolocation.dat by default,
|
94
96
|
# or according to $Image::ExifTool::Geolocation::directory if specified
|
@@ -107,12 +109,10 @@ unless (defined $geoDir and not $geoDir) {
|
|
107
109
|
}
|
108
110
|
}
|
109
111
|
|
110
|
-
# set directory for language files
|
111
|
-
|
112
|
-
if ($geoDir and -
|
113
|
-
$
|
114
|
-
} elsif ($geoDir or not defined $geoDir) {
|
115
|
-
$geoLang = "$defaultDir/GeoLang";
|
112
|
+
# set directory for language files and alternate names
|
113
|
+
$geoDir = $defaultDir unless defined $geoDir;
|
114
|
+
if (not defined $altDir and $geoDir and -e "$geoDir/AltNames.dat") {
|
115
|
+
$altDir = $geoDir;
|
116
116
|
}
|
117
117
|
|
118
118
|
# add user-defined entries to the database
|
@@ -136,16 +136,16 @@ sub ReadDatabase($)
|
|
136
136
|
close(DATFILE);
|
137
137
|
return 0;
|
138
138
|
}
|
139
|
-
|
140
|
-
|
139
|
+
($dbVer, $nCity) = ($1, $2);
|
140
|
+
if ($dbVer !~ /^1\.0[23]$/) {
|
141
|
+
my $which = $dbVer < 1.03 ? 'database' : 'ExifTool';
|
141
142
|
warn("Incompatible Geolocation database (update your $which)\n");
|
142
143
|
close(DATFILE);
|
143
144
|
return 0;
|
144
145
|
}
|
145
|
-
$nCity = $2;
|
146
146
|
my $comment = <DATFILE>;
|
147
|
-
defined $comment and $comment =~ /(\d+)/ or close(DATFILE), return 0;
|
148
|
-
$dbInfo = "$datfile v$
|
147
|
+
defined $comment and $comment =~ / (\d+) / or close(DATFILE), return 0;
|
148
|
+
$dbInfo = "$datfile v$dbVer: $nCity cities with population > $1";
|
149
149
|
my $isUserDefined = @Image::ExifTool::UserDefined::Geolocation;
|
150
150
|
|
151
151
|
undef @altNames; # reset altNames
|
@@ -193,7 +193,20 @@ sub ReadDatabase($)
|
|
193
193
|
push @timezoneList, $line;
|
194
194
|
$timezoneNum{lc $line} = $#timezoneList if $isUserDefined;
|
195
195
|
}
|
196
|
+
# read feature codes if available
|
197
|
+
if ($line eq "\0\0\0\0\x05\n") {
|
198
|
+
undef @featureCodes;
|
199
|
+
for (;;) {
|
200
|
+
$line = <DATFILE>;
|
201
|
+
last if length($line) == 6 and $line =~ /\0\0\0\0/;
|
202
|
+
chomp $line;
|
203
|
+
push @featureCodes, $line;
|
204
|
+
}
|
205
|
+
}
|
196
206
|
close DATFILE;
|
207
|
+
# initialize featureCodes lookup
|
208
|
+
$i = 0;
|
209
|
+
%featureCodes = map { lc($_) => $i++ } @featureCodes;
|
197
210
|
return 1;
|
198
211
|
}
|
199
212
|
|
@@ -268,11 +281,12 @@ sub SortDatabase($)
|
|
268
281
|
# Add cities to the Geolocation database
|
269
282
|
# Inputs: 0-8) city,region,subregion,country_code,country,timezone,feature_code,population,lat,lon,altNames
|
270
283
|
# eg. AddEntry('Sinemorets','Burgas','Obshtina Tsarevo','BG','Bulgaria','Europe/Sofia','',400,42.06115,27.97833)
|
284
|
+
# Returns: true on success, otherwise issues warning
|
271
285
|
sub AddEntry(@)
|
272
286
|
{
|
273
287
|
my ($city, $region, $subregion, $cc, $country, $timezone, $fc, $pop, $lat, $lon, $altNames) = @_;
|
274
|
-
@_ < 10 and warn("Too few arguments in $city definition (check for updated format)\n"), return;
|
275
|
-
length($cc) != 2 and warn("Country code '${cc}' is not 2 characters\n"), return;
|
288
|
+
@_ < 10 and warn("Too few arguments in $city definition (check for updated format)\n"), return 0;
|
289
|
+
length($cc) != 2 and warn("Country code '${cc}' is not 2 characters\n"), return 0;
|
276
290
|
$fc = $featureCodes{lc $fc} || 0;
|
277
291
|
chomp $lon; # (just in case it was read from file)
|
278
292
|
# create reverse lookups for country/region/subregion/timezone if not done already
|
@@ -286,6 +300,7 @@ sub AddEntry(@)
|
|
286
300
|
}
|
287
301
|
my $cn = $countryNum{lc $cc};
|
288
302
|
unless (defined $cn) {
|
303
|
+
$#countryList >= 0xff and warn("AddEntry: Too many countries\n"), return 0;
|
289
304
|
push @countryList, "$cc$country";
|
290
305
|
$cn = $countryNum{lc $cc} = $#countryList;
|
291
306
|
} elsif ($country) {
|
@@ -293,16 +308,20 @@ sub AddEntry(@)
|
|
293
308
|
}
|
294
309
|
my $tn = $timezoneNum{lc $timezone};
|
295
310
|
unless (defined $tn) {
|
311
|
+
$#timezoneList >= 0x1ff and warn("AddEntry: Too many time zones\n"), return 0;
|
296
312
|
push @timezoneList, $timezone;
|
297
313
|
$tn = $timezoneNum{lc $timezone} = $#timezoneList;
|
298
314
|
}
|
299
315
|
my $rn = $regionNum{lc $region};
|
300
316
|
unless (defined $rn) {
|
317
|
+
$#regionList >= 0xfff and warn("AddEntry: Too many regions\n"), return 0;
|
301
318
|
push @regionList, $region;
|
302
319
|
$rn = $regionNum{lc $region} = $#regionList;
|
303
320
|
}
|
304
321
|
my $sn = $subregionNum{lc $subregion};
|
305
322
|
unless (defined $sn) {
|
323
|
+
my $max = $dbVer eq '1.02' ? 0x0fff : 0xffff;
|
324
|
+
$#subregionList >= $max and warn("AddEntry: Too many subregions\n"), return 0;
|
306
325
|
push @subregionList, $subregion;
|
307
326
|
$sn = $subregionNum{lc $subregion} = $#subregionList;
|
308
327
|
}
|
@@ -310,7 +329,14 @@ sub AddEntry(@)
|
|
310
329
|
# pack CC index, population and region index into a 32-bit integer
|
311
330
|
my $code = ($cn << 24) | (substr($pop,-1,1)<<20) | (substr($pop,0,1)<<16) | (substr($pop,2,1)<<12) | $rn;
|
312
331
|
# store high bit of timezone index
|
313
|
-
$tn > 255
|
332
|
+
if ($tn > 255) {
|
333
|
+
if ($dbVer eq '1.02') {
|
334
|
+
$sn |= 0x8000;
|
335
|
+
} else {
|
336
|
+
$fc |= 0x80;
|
337
|
+
}
|
338
|
+
$tn -= 256;
|
339
|
+
}
|
314
340
|
$lat = int(($lat + 90) / 180 * 0x100000 + 0.5) & 0xfffff;
|
315
341
|
$lon = int(($lon + 180) / 360 * 0x100000 + 0.5) & 0xfffff;
|
316
342
|
my $hdr = pack('nCnNnCC', $lat>>4, (($lat&0x0f)<<4)|($lon&0x0f), $lon>>4, $code, $sn, $tn, $fc);
|
@@ -328,6 +354,7 @@ sub AddEntry(@)
|
|
328
354
|
}
|
329
355
|
$sortedBy = '';
|
330
356
|
undef $lastArgs; # (faster than ClearLastArgs)
|
357
|
+
return 1;
|
331
358
|
}
|
332
359
|
|
333
360
|
#------------------------------------------------------------------------------
|
@@ -341,24 +368,28 @@ sub GetEntry($;$$)
|
|
341
368
|
my ($entryNum, $lang, $sort) = @_;
|
342
369
|
return() if $entryNum > $#cityList;
|
343
370
|
$entryNum = $sortOrder[$entryNum] if $sort and @sortOrder > $entryNum;
|
344
|
-
my ($lt,$f,$ln,$code,$
|
371
|
+
my ($lt,$f,$ln,$code,$sn,$tn,$fc) = unpack('nCnNnCC', $cityList[$entryNum]);
|
345
372
|
my $city = substr($cityList[$entryNum],13);
|
346
373
|
my $ctry = $countryList[$code >> 24];
|
347
374
|
my $rgn = $regionList[$code & 0x0fff];
|
348
|
-
|
375
|
+
if ($dbVer eq '1.02') {
|
376
|
+
$sn & 0x8000 and $tn += 256, $sn &= 0x7fff;
|
377
|
+
} else {
|
378
|
+
$fc & 0x80 and $tn += 256;
|
379
|
+
}
|
380
|
+
my $sub = $subregionList[$sn];
|
349
381
|
# convert population digits back into exponent format
|
350
382
|
my $pop = (($code>>16 & 0x0f) . '.' . ($code>>12 & 0x0f) . 'e+' . ($code>>20 & 0x0f)) + 0;
|
351
|
-
$tn += 256 if $sb & 0x8000;
|
352
383
|
$lt = sprintf('%.4f', (($lt<<4)|($f >> 4)) * 180 / 0x100000 - 90);
|
353
384
|
$ln = sprintf('%.4f', (($ln<<4)|($f & 0x0f))* 360 / 0x100000 - 180);
|
354
|
-
$fc = $featureCodes[$fc &
|
385
|
+
$fc = $featureCodes[$fc & 0x1f];
|
355
386
|
my $cc = substr($ctry, 0, 2);
|
356
387
|
my $country = substr($ctry, 2);
|
357
388
|
if ($lang) {
|
358
389
|
my $xlat = $langLookup{$lang};
|
359
390
|
# load language lookups if not done already
|
360
391
|
if (not defined $xlat) {
|
361
|
-
if (eval "require '$
|
392
|
+
if (eval "require '$geoDir/GeoLang/$lang.pm'") {
|
362
393
|
my $trans = "Image::ExifTool::GeoLang::${lang}::Translate";
|
363
394
|
no strict 'refs';
|
364
395
|
$xlat = \%$trans if %$trans;
|
@@ -511,9 +542,10 @@ Entry: for (; $i<@cityList; ++$i) {
|
|
511
542
|
if ($regex{8}) { $cty =~ $_ or next Entry foreach @{$regex{8}} }
|
512
543
|
if ($regex{18}) { $cty !~ $_ or next Entry foreach @{$regex{18}} }
|
513
544
|
# test other arguments
|
514
|
-
my ($cd,$
|
545
|
+
my ($cd,$sn) = unpack('x5Nn', $cityList[$i]);
|
515
546
|
my $ct = $countryList[$cd >> 24];
|
516
|
-
|
547
|
+
$sn &= 0x7fff if $dbVer eq '1.02';
|
548
|
+
my @geo = (substr($ct,0,2), substr($ct,2), $regionList[$cd & 0x0fff], $subregionList[$sn]);
|
517
549
|
if (@exact) {
|
518
550
|
# make quick lookup for all names at this location
|
519
551
|
my %geoLkup;
|
@@ -672,10 +704,10 @@ True on success.
|
|
672
704
|
=head2 ReadAltNames
|
673
705
|
|
674
706
|
Load the alternate names database. Before calling this method the $altDir
|
675
|
-
package variable
|
676
|
-
|
677
|
-
|
678
|
-
|
707
|
+
package variable may be set, otherwise AltNames.dat is loaded from the same
|
708
|
+
directory as Geolocation.dat. This method is called automatically by
|
709
|
+
L</Geolocate> if the GeolocAltNames option is used and an input city name is
|
710
|
+
provided.
|
679
711
|
|
680
712
|
Image::ExifTool::Geolocation::ReadAltNames();
|
681
713
|
|
@@ -687,8 +719,8 @@ option is used and an input city name is provided.
|
|
687
719
|
|
688
720
|
=item Return Value:
|
689
721
|
|
690
|
-
True on success.
|
691
|
-
|
722
|
+
True on success. May be called repeatedly, but AltNames.dat is loaded only
|
723
|
+
on the first call.
|
692
724
|
|
693
725
|
=back
|
694
726
|
|
@@ -746,6 +778,10 @@ database, then the database entry is updated with the new country name.
|
|
746
778
|
|
747
779
|
10) Optional comma-separated list of alternate names for the city
|
748
780
|
|
781
|
+
=item Return Value:
|
782
|
+
|
783
|
+
1 on success, otherwise sends a warning message to stderr
|
784
|
+
|
749
785
|
=back
|
750
786
|
|
751
787
|
=head2 GetEntry
|
@@ -810,8 +846,7 @@ Comma-separated string of alternate names for this city.
|
|
810
846
|
|
811
847
|
=item Notes:
|
812
848
|
|
813
|
-
|
814
|
-
calling this routine.
|
849
|
+
L</ReadAltNames> must be called before calling this routine.
|
815
850
|
|
816
851
|
=back
|
817
852
|
|
@@ -873,11 +908,12 @@ contain the Geolocation.dat file, and optionally a GeoLang directory for the
|
|
873
908
|
language translations. The $geoDir variable may be set to an empty string
|
874
909
|
to disable loading of a database.
|
875
910
|
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
911
|
+
When searching for a city by name, AltNames.dat is checked to provide
|
912
|
+
additional possibilities for matches if the GeolocAltNames option is set.
|
913
|
+
The package $altDir variable may be set to specify a different directory for
|
914
|
+
AltNames.dat, otherwise the Geolocation.dat directory is assumed. The
|
915
|
+
entries in AltNames.dat must match those in the currently loaded version of
|
916
|
+
Geolocation.dat.
|
881
917
|
|
882
918
|
=head1 ADDING USER-DEFINED DATABASE ENTRIES
|
883
919
|
|
@@ -65,7 +65,7 @@ use Image::ExifTool::Exif;
|
|
65
65
|
use Image::ExifTool::GPS;
|
66
66
|
use Image::ExifTool::XMP;
|
67
67
|
|
68
|
-
$VERSION = '4.
|
68
|
+
$VERSION = '4.33';
|
69
69
|
|
70
70
|
sub LensIDConv($$$);
|
71
71
|
sub ProcessNikonAVI($$$);
|
@@ -678,6 +678,7 @@ sub GetAFPointGrid($$;$);
|
|
678
678
|
'FD 00 50 50 18 18 DF 00' => 'Voigtlander APO-Lanthar 50mm F2 Aspherical', #35
|
679
679
|
'FD 00 44 44 18 18 DF 00' => 'Voigtlander APO-Lanthar 35mm F2', #30
|
680
680
|
'FD 00 59 59 18 18 DF 00' => 'Voigtlander Macro APO-Lanthar 65mm F2', #30
|
681
|
+
'FD 00 48 48 07 07 DF 00' => 'Voigtlander Nokton 40mm F1.2 Aspherical', #30
|
681
682
|
#
|
682
683
|
'00 40 2D 2D 2C 2C 00 00' => 'Carl Zeiss Distagon T* 3.5/18 ZF.2',
|
683
684
|
'00 48 27 27 24 24 00 00' => 'Carl Zeiss Distagon T* 2.8/15 ZF.2', #MykytaKozlov
|
@@ -5498,20 +5499,21 @@ my %nikonFocalConversions = (
|
|
5498
5499
|
28 => 'Nikkor Z 100-400mm f/4.5-5.6 VR S', #28
|
5499
5500
|
29 => 'Nikkor Z 28mm f/2.8', #IB
|
5500
5501
|
30 => 'Nikkor Z 400mm f/2.8 TC VR S', #28
|
5501
|
-
31 => 'Nikkor Z 24-
|
5502
|
+
31 => 'Nikkor Z 24-120mm f/4 S', #github#250
|
5502
5503
|
32 => 'Nikkor Z 800mm f/6.3 VR S', #28
|
5503
5504
|
35 => 'Nikkor Z 28-75mm f/2.8', #IB
|
5504
5505
|
36 => 'Nikkor Z 400mm f/4.5 VR S', #IB
|
5505
5506
|
37 => 'Nikkor Z 600mm f/4 TC VR S', #28
|
5506
5507
|
38 => 'Nikkor Z 85mm f/1.2 S', #28
|
5507
5508
|
39 => 'Nikkor Z 17-28mm f/2.8', #IB
|
5508
|
-
40 => '
|
5509
|
-
41 => '
|
5509
|
+
40 => 'Nikkor Z 26mm f/2.8', #28
|
5510
|
+
41 => 'Nikkor Z DX 12-28mm f/3.5-5.6 PZ VR', #28
|
5510
5511
|
42 => 'Nikkor Z 180-600mm f/5.6-6.3 VR', #30
|
5511
|
-
43 => '
|
5512
|
-
44 => '
|
5513
|
-
45 => '
|
5512
|
+
43 => 'Nikkor Z DX 24mm f/1.7', #28
|
5513
|
+
44 => 'Nikkor Z 70-180mm f/2.8', #28
|
5514
|
+
45 => 'Nikkor Z 600mm f/6.3 VR S', #28
|
5514
5515
|
46 => 'Nikkor Z 135mm f/1.8 S Plena', #28
|
5516
|
+
48 => 'Nikkor Z 28-400mm f/4-8 VR', #30
|
5515
5517
|
32768 => 'Nikkor Z 400mm f/2.8 TC VR S TC-1.4x', #28
|
5516
5518
|
32769 => 'Nikkor Z 600mm f/4 TC VR S TC-1.4x', #28
|
5517
5519
|
},
|
@@ -48,7 +48,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
|
|
48
48
|
use Image::ExifTool::Exif;
|
49
49
|
use Image::ExifTool::GPS;
|
50
50
|
|
51
|
-
$VERSION = '2.
|
51
|
+
$VERSION = '2.96';
|
52
52
|
|
53
53
|
sub ProcessMOV($$;$);
|
54
54
|
sub ProcessKeys($$$);
|
@@ -59,6 +59,9 @@ sub ProcessSampleDesc($$$);
|
|
59
59
|
sub ProcessHybrid($$$);
|
60
60
|
sub ProcessRights($$$);
|
61
61
|
sub ProcessNextbase($$$);
|
62
|
+
sub Process_mrlh($$$);
|
63
|
+
sub Process_mrlv($$$);
|
64
|
+
sub Process_mrld($$$);
|
62
65
|
# ++vvvvvvvvvvvv++ (in QuickTimeStream.pl)
|
63
66
|
sub Process_mebx($$$);
|
64
67
|
sub Process_3gf($$$);
|
@@ -6491,6 +6494,9 @@ my %isImageData = ( av01 => 1, avc1 => 1, hvc1 => 1, lhv1 => 1, hvt1 => 1 );
|
|
6491
6494
|
},
|
6492
6495
|
ownr => 'Owner', #PH (obscure) (ref ChrisAdan private communication)
|
6493
6496
|
'xid ' => 'ISRC', #PH
|
6497
|
+
# found in DJI Osmo Action4 video
|
6498
|
+
tnal => { Name => 'ThumbnailImage', Groups => { 2 => 'Preview' } },
|
6499
|
+
snal => { Name => 'PreviewImage', Groups => { 2 => 'Preview' } },
|
6494
6500
|
);
|
6495
6501
|
|
6496
6502
|
# tag decoded from timed face records
|
@@ -7870,20 +7876,9 @@ my %isImageData = ( av01 => 1, avc1 => 1, hvc1 => 1, lhv1 => 1, hvt1 => 1 );
|
|
7870
7876
|
#
|
7871
7877
|
ftab => { Name => 'FontTable', Format => 'undef', ValueConv => 'substr($val, 5)' },
|
7872
7878
|
name => { Name => 'OtherName', Format => 'undef', ValueConv => 'substr($val, 4)' },
|
7873
|
-
|
7874
|
-
|
7875
|
-
|
7876
|
-
# 0 - int32u count
|
7877
|
-
# 4 - int32u ? (related to units) 0=none,1=m/km,2=L,3=kph,4=C,7=deg,8=rpm,9=kPa,10=G,11=V,15=Nm,16=%
|
7878
|
-
# 8 - int32u ? (0,1,3,4,5)
|
7879
|
-
# 12 - string[64] units
|
7880
|
-
# 76 - int32u ? (1,3,7,15)
|
7881
|
-
# 80 - int32u 0
|
7882
|
-
# 84 - undef[4] ?
|
7883
|
-
# 88 - int16u[6] ?
|
7884
|
-
# 100 - undef[32] ?
|
7885
|
-
# 132 - string[64] measurement name
|
7886
|
-
# 196 - string[64] measurement name
|
7879
|
+
mrlh => { Name => 'MarlinHeader', SubDirectory => { TagTable => 'Image::ExifTool::GM::mrlh' } },
|
7880
|
+
mrlv => { Name => 'MarlinValues', SubDirectory => { TagTable => 'Image::ExifTool::GM::mrlv' } },
|
7881
|
+
mrld => { Name => 'MarlinDictionary',SubDirectory => { TagTable => 'Image::ExifTool::GM::mrld' } },
|
7887
7882
|
);
|
7888
7883
|
|
7889
7884
|
# MP4 data information box (ref 5)
|
@@ -9478,7 +9473,7 @@ sub ProcessMOV($$;$)
|
|
9478
9473
|
my $dirID = $$dirInfo{DirID} || '';
|
9479
9474
|
my $charsetQuickTime = $et->Options('CharsetQuickTime');
|
9480
9475
|
my ($buff, $tag, $size, $track, $isUserData, %triplet, $doDefaultLang, $index);
|
9481
|
-
my ($dirEnd, $unkOpt, %saveOptions, $atomCount);
|
9476
|
+
my ($dirEnd, $unkOpt, %saveOptions, $atomCount, $warnStr);
|
9482
9477
|
|
9483
9478
|
my $topLevel = not $$et{InQuickTime};
|
9484
9479
|
$$et{InQuickTime} = 1;
|
@@ -9558,6 +9553,7 @@ sub ProcessMOV($$;$)
|
|
9558
9553
|
$index = $$tagTablePtr{VARS}{START_INDEX};
|
9559
9554
|
$atomCount = $$tagTablePtr{VARS}{ATOM_COUNT};
|
9560
9555
|
}
|
9556
|
+
my $lastTag = '';
|
9561
9557
|
for (;;) {
|
9562
9558
|
my ($eeTag, $ignore);
|
9563
9559
|
last if defined $atomCount and --$atomCount < 0;
|
@@ -9584,22 +9580,22 @@ sub ProcessMOV($$;$)
|
|
9584
9580
|
}
|
9585
9581
|
last;
|
9586
9582
|
}
|
9587
|
-
$size == 1 or $
|
9583
|
+
$size == 1 or $warnStr = 'Invalid atom size', last;
|
9588
9584
|
# read extended atom size
|
9589
|
-
$raf->Read($buff, 8) == 8 or $
|
9585
|
+
$raf->Read($buff, 8) == 8 or $warnStr = 'Truncated atom header', last;
|
9590
9586
|
$dataPos += 8;
|
9591
9587
|
my ($hi, $lo) = unpack('NN', $buff);
|
9592
9588
|
if ($hi or $lo > 0x7fffffff) {
|
9593
9589
|
if ($hi > 0x7fffffff) {
|
9594
|
-
$
|
9590
|
+
$warnStr = 'Invalid atom size';
|
9595
9591
|
last;
|
9596
9592
|
} elsif (not $et->Options('LargeFileSupport')) {
|
9597
|
-
$
|
9593
|
+
$warnStr = 'End of processing at large atom (LargeFileSupport not enabled)';
|
9598
9594
|
last;
|
9599
9595
|
}
|
9600
9596
|
}
|
9601
9597
|
$size = $hi * 4294967296 + $lo - 16;
|
9602
|
-
$size < 0 and $
|
9598
|
+
$size < 0 and $warnStr = 'Invalid extended size', last;
|
9603
9599
|
} else {
|
9604
9600
|
$size -= 8;
|
9605
9601
|
}
|
@@ -9755,7 +9751,7 @@ ItemID: foreach $id (reverse sort { $a <=> $b } keys %$items) {
|
|
9755
9751
|
my $missing = $size - $raf->Read($val, $size);
|
9756
9752
|
if ($missing) {
|
9757
9753
|
my $t = PrintableTagID($tag,2);
|
9758
|
-
$
|
9754
|
+
$warnStr = "Truncated '${t}' data (missing $missing bytes)";
|
9759
9755
|
last;
|
9760
9756
|
}
|
9761
9757
|
# use value to get tag info if necessary
|
@@ -10070,16 +10066,28 @@ ItemID: foreach $id (reverse sort { $a <=> $b } keys %$items) {
|
|
10070
10066
|
) if $verbose;
|
10071
10067
|
if ($size and (not $raf->Seek($size-1, 1) or $raf->Read($buff, 1) != 1)) {
|
10072
10068
|
my $t = PrintableTagID($tag,2);
|
10073
|
-
$
|
10069
|
+
$warnStr = "Truncated '${t}' data";
|
10074
10070
|
last;
|
10075
10071
|
}
|
10076
10072
|
}
|
10077
10073
|
$dataPos += $size + 8; # point to start of next atom data
|
10078
10074
|
last if $dirEnd and $dataPos >= $dirEnd; # (note: ignores last value if 0 bytes)
|
10079
10075
|
$raf->Read($buff, 8) == 8 or last;
|
10076
|
+
$lastTag = $tag if $$tagTablePtr{$tag};
|
10080
10077
|
($size, $tag) = unpack('Na4', $buff);
|
10081
10078
|
++$index if defined $index;
|
10082
10079
|
}
|
10080
|
+
if ($warnStr) {
|
10081
|
+
# assume this is an unknown trailer if it comes immediately after
|
10082
|
+
# mdat or moov and has a tag name we don't recognize
|
10083
|
+
if (($lastTag eq 'mdat' or $lastTag eq 'moov') and (not $$tagTablePtr{$tag} or
|
10084
|
+
ref $$tagTablePtr{$tag} eq 'HASH' and $$tagTablePtr{$tag}{Unknown}))
|
10085
|
+
{
|
10086
|
+
$et->Warn('Unknown trailer with '.lcfirst($warnStr));
|
10087
|
+
} else {
|
10088
|
+
$et->Warn($warnStr);
|
10089
|
+
}
|
10090
|
+
}
|
10083
10091
|
# tweak file type based on track content ("iso*" and "dash" ftyp only)
|
10084
10092
|
if ($topLevel and $$et{FileType} and $$et{FileType} eq 'MP4' and
|
10085
10093
|
$$et{save_ftyp} and $$et{HasHandler} and $$et{save_ftyp} =~ /^(iso|dash)/ and
|
@@ -22,12 +22,12 @@ use Image::ExifTool qw(:DataAccess :Utils);
|
|
22
22
|
use Image::ExifTool::QuickTime;
|
23
23
|
|
24
24
|
sub Process_tx3g($$$);
|
25
|
-
sub Process_marl($$$);
|
26
25
|
sub Process_mebx($$$);
|
27
26
|
sub Process_text($$$;$);
|
28
27
|
sub ProcessFreeGPS($$$);
|
29
28
|
sub Process360Fly($$$);
|
30
29
|
sub ProcessFMAS($$$);
|
30
|
+
sub ProcessWolfbox($$$);
|
31
31
|
sub ProcessCAMM($$$);
|
32
32
|
|
33
33
|
# QuickTime data types that have ExifTool equivalents
|
@@ -109,7 +109,7 @@ my %insvLimit = (
|
|
109
109
|
The tags below are extracted from timed metadata in QuickTime and other
|
110
110
|
formats of video files when the ExtractEmbedded option is used. Although
|
111
111
|
most of these tags are combined into the single table below, ExifTool
|
112
|
-
currently reads
|
112
|
+
currently reads 74 different formats of timed GPS metadata from video files.
|
113
113
|
},
|
114
114
|
VARS => { NO_ID => 1 },
|
115
115
|
GPSLatitude => { PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', RawConv => '$$self{FoundGPSLatitude} = 1; $val' },
|
@@ -207,6 +207,13 @@ my %insvLimit = (
|
|
207
207
|
TagTable => 'Image::ExifTool::QuickTime::Stream',
|
208
208
|
ProcessProc => \&ProcessFMAS,
|
209
209
|
},
|
210
|
+
},{
|
211
|
+
Name => 'gpmd_Wolfbox', # Wolfbox G900 Dashcam
|
212
|
+
Condition => '$$valPt =~ /^.{136}0{16}HYTH/s',
|
213
|
+
SubDirectory => {
|
214
|
+
TagTable => 'Image::ExifTool::QuickTime::Stream',
|
215
|
+
ProcessProc => \&ProcessWolfbox,
|
216
|
+
},
|
210
217
|
},{
|
211
218
|
Name => 'gpmd_GoPro',
|
212
219
|
SubDirectory => { TagTable => 'Image::ExifTool::GoPro::GPMF' },
|
@@ -223,7 +230,7 @@ my %insvLimit = (
|
|
223
230
|
},
|
224
231
|
marl => {
|
225
232
|
Name => 'marl',
|
226
|
-
SubDirectory => { TagTable => 'Image::ExifTool::
|
233
|
+
SubDirectory => { TagTable => 'Image::ExifTool::GM::marl' },
|
227
234
|
},
|
228
235
|
CTMD => { # (Canon Timed MetaData)
|
229
236
|
Name => 'CTMD',
|
@@ -326,6 +333,14 @@ my %insvLimit = (
|
|
326
333
|
Groups => { 0 => 'Trailer', 1 => 'Insta360' }, # (so these groups will appear in the -listg options)
|
327
334
|
SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::INSV_MakerNotes' },
|
328
335
|
},
|
336
|
+
ssmd => { # Chigee AIO-5 dashcam
|
337
|
+
Name => 'PreviewImage',
|
338
|
+
Groups => { 2 => 'Preview' },
|
339
|
+
RawConv => '$self->ValidateImage(\$val,$tag)',
|
340
|
+
},
|
341
|
+
# djmd - DJI AC003 Osmo Action 4 cam
|
342
|
+
#TODO djmd => { SubDirectory => { TagTable => 'Image::ExifTool::DJI::djmd', ByteOrder => 'Little-Endian' } },
|
343
|
+
# dbgi - DJI AC003 Osmo Action 4 cam -- lots more unknown stuff
|
329
344
|
Unknown00 => { Unknown => 1 },
|
330
345
|
Unknown01 => { Unknown => 1 },
|
331
346
|
Unknown02 => { Unknown => 1 },
|
@@ -741,13 +756,6 @@ my %insvLimit = (
|
|
741
756
|
10 => { Name => 'FusionYPR', Format => 'float[3]' },
|
742
757
|
);
|
743
758
|
|
744
|
-
# tags found in 'marl' ctbx timed metadata (ref PH)
|
745
|
-
%Image::ExifTool::QuickTime::marl = (
|
746
|
-
PROCESS_PROC => \&Process_marl,
|
747
|
-
GROUPS => { 2 => 'Other' },
|
748
|
-
NOTES => 'Tags extracted from the marl ctbx timed metadata of GM cars.',
|
749
|
-
);
|
750
|
-
|
751
759
|
#------------------------------------------------------------------------------
|
752
760
|
# Save information from keys in OtherSampleDesc directory for processing timed metadata
|
753
761
|
# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
|
@@ -2219,26 +2227,6 @@ sub Process_tx3g($$$)
|
|
2219
2227
|
return 1;
|
2220
2228
|
}
|
2221
2229
|
|
2222
|
-
#------------------------------------------------------------------------------
|
2223
|
-
# Process GM 'marl' ctbx metadata (ref PH)
|
2224
|
-
# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
|
2225
|
-
# Returns: 1 on success
|
2226
|
-
sub Process_marl($$$)
|
2227
|
-
{
|
2228
|
-
my ($et, $dirInfo, $tagTablePtr) = @_;
|
2229
|
-
my $dataPt = $$dirInfo{DataPt};
|
2230
|
-
return 0 if length $$dataPt < 2;
|
2231
|
-
|
2232
|
-
# 8-byte records:
|
2233
|
-
# byte 0 seems to be tag ID (0=timestamp in sec * 1e7)
|
2234
|
-
# bytes 1-3 seem to be 24-bit signed integer (unknown meaning)
|
2235
|
-
# bytes 4-7 are an int32u value, usually a multiple of 10000
|
2236
|
-
|
2237
|
-
$et->WarnOnce("Can't yet decode timed GM data", 1);
|
2238
|
-
# (see https://exiftool.org/forum/index.php?topic=11335.msg61393#msg61393)
|
2239
|
-
return 1;
|
2240
|
-
}
|
2241
|
-
|
2242
2230
|
#------------------------------------------------------------------------------
|
2243
2231
|
# Process QuickTime 'mebx' timed metadata
|
2244
2232
|
# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
|
@@ -2443,7 +2431,9 @@ sub Process_nbmt($$$)
|
|
2443
2431
|
$$et{DOC_NUM} = $$et{DOC_COUNT} + 1;
|
2444
2432
|
delete $$et{UnknownTextCount};
|
2445
2433
|
delete $$et{NoMoreTextDecoding};
|
2434
|
+
$$et{SET_GROUP1} = 'Nextbase';
|
2446
2435
|
Process_text($et, $dataPt, $tagTbl, 1);
|
2436
|
+
delete $$et{SET_GROUP1};
|
2447
2437
|
delete $$et{UnknownTextCount};
|
2448
2438
|
delete $$et{NoMoreTextDecoding};
|
2449
2439
|
delete $$et{DOC_NUM};
|
@@ -3229,6 +3219,52 @@ sub ProcessFMAS($$$)
|
|
3229
3219
|
return 1;
|
3230
3220
|
}
|
3231
3221
|
|
3222
|
+
#------------------------------------------------------------------------------
|
3223
|
+
# Process GPS from Wolfbox G900 Dashcam
|
3224
|
+
# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
|
3225
|
+
# Returns: 1 on success
|
3226
|
+
sub ProcessWolfbox($$$)
|
3227
|
+
{
|
3228
|
+
my ($et, $dirInfo, $tagTbl) = @_;
|
3229
|
+
my $dataPt = $$dirInfo{DataPt};
|
3230
|
+
return 0 if length($$dataPt) < 0xc8;
|
3231
|
+
$et->VerboseDir('Wolfbox', undef, length($$dataPt));
|
3232
|
+
# 0000: 65 00 00 00 00 00 00 00 31 01 01 00 e3 ff 00 00 [e.......1.......]
|
3233
|
+
# 0010: 04 00 00 00 10 00 00 00 2a 00 00 00 00 00 00 00 [........*.......]
|
3234
|
+
# 0020: 01 00 00 00 00 00 00 00 8b 33 ff 51 00 00 00 00 [.........3.Q....]
|
3235
|
+
# 0030: a0 86 01 00 00 00 00 00 4d 5e 07 fa ff ff ff ff [........M^......]
|
3236
|
+
# 0040: a0 86 01 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
|
3237
|
+
# 0050: 64 00 00 00 00 00 00 00 90 21 00 00 00 00 00 00 [d........!......]
|
3238
|
+
# 0060: 64 00 00 00 00 00 00 00 18 00 00 00 03 00 00 00 [d...............]
|
3239
|
+
# 0070: e8 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
|
3240
|
+
# 0080: 00 00 00 00 00 00 00 00 30 30 30 30 30 30 30 30 [........00000000]
|
3241
|
+
# 0090: 30 30 30 30 30 30 30 30 48 59 54 48 00 00 00 00 [00000000HYTH....]
|
3242
|
+
# 00a0: 0c 00 00 00 10 00 00 00 2a 00 00 00 00 00 00 00 [........*.......]
|
3243
|
+
# 00b0: 4f 3f 0c 1f 00 00 00 00 a0 86 01 00 00 00 00 00 [O?..............]
|
3244
|
+
# 00c0: 7f cf 2d ff ff ff ff ff a0 86 01 00 00 00 00 00 [..-.............]
|
3245
|
+
# 00d0: 01 00 00 00 08 00 00 00 0a 00 00 00 00 00 00 00 [................]
|
3246
|
+
# 00e0: 0a 00 00 00 00 00 00 00 e8 03 00 00 00 00 00 00 [................]
|
3247
|
+
# 00f0: 0a 00 00 00 00 00 00 00 4d 00 00 00 00 00 00 00 [........M.......]
|
3248
|
+
# lat/lon at 0xb0/0xc0 and 0x128/0x138
|
3249
|
+
# h/m/s at 0x10 and 0xa0 and 0x148 (the first imprinted on the video, the latter 2 presumed UTC)
|
3250
|
+
# spd at 0x48, dir at 0x58, alt at 0xe8
|
3251
|
+
SetByteOrder('II');
|
3252
|
+
my ($spd,$dir,$d,$mo,$yr,$h,$m,$s) = unpack('x72Vx12Vx12V3x44V3',$$dataPt);
|
3253
|
+
# offset 0xa0 also stores hh mm ss, but is out by 8 hours!
|
3254
|
+
my $time = sprintf '%.4d:%.2d:%.2d %.2d:%.2d:%.2dZ', $yr, $mo, $d, $h, $m, $s;
|
3255
|
+
my ($lat, $lon) = (Get32s($dataPt, 0xb0) / 1e5, Get32s($dataPt, 0xc0) / 1e5);
|
3256
|
+
my $alt = Get32s($dataPt, 0xe8);
|
3257
|
+
ConvertLatLon($lat, $lon);
|
3258
|
+
$et->HandleTag($tagTbl, GPSDateTime => $time);
|
3259
|
+
$et->HandleTag($tagTbl, GPSLatitude => $lat);
|
3260
|
+
$et->HandleTag($tagTbl, GPSLongitude => $lon);
|
3261
|
+
$et->HandleTag($tagTbl, GPSSpeed => $spd * $knotsToKph / 100);
|
3262
|
+
$et->HandleTag($tagTbl, GPSTrack => $dir / 100);
|
3263
|
+
$et->HandleTag($tagTbl, GPSAltitude => $alt / 10); # (NC)
|
3264
|
+
SetByteOrder('MM');
|
3265
|
+
return 1;
|
3266
|
+
}
|
3267
|
+
|
3232
3268
|
#------------------------------------------------------------------------------
|
3233
3269
|
# Scan media data for "freeGPS" metadata if not found already (ref PH)
|
3234
3270
|
# Inputs: 0) ExifTool ref
|