exiftool_vendored 12.81.0 → 12.83.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 +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
|