exiftool_vendored 12.81.0 → 12.82.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 +19 -1
- data/bin/MANIFEST +2 -0
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +2 -2
- data/bin/exiftool +13 -7
- data/bin/lib/Image/ExifTool/BuildTagLookup.pm +44 -31
- data/bin/lib/Image/ExifTool/FujiFilm.pm +9 -2
- data/bin/lib/Image/ExifTool/GM.pm +543 -0
- data/bin/lib/Image/ExifTool/Geolocation.pm +43 -20
- data/bin/lib/Image/ExifTool/Nikon.pm +3 -2
- data/bin/lib/Image/ExifTool/QuickTime.pm +28 -23
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +61 -30
- data/bin/lib/Image/ExifTool/README +2 -0
- data/bin/lib/Image/ExifTool/TagLookup.pm +26 -1
- data/bin/lib/Image/ExifTool/TagNames.pod +392 -237
- data/bin/lib/Image/ExifTool/WriteQuickTime.pl +3 -1
- data/bin/lib/Image/ExifTool/Writer.pl +2 -2
- data/bin/lib/Image/ExifTool/XMP.pm +3 -2
- data/bin/lib/Image/ExifTool.pm +27 -5
- data/bin/lib/Image/ExifTool.pod +18 -11
- data/bin/perl-Image-ExifTool.spec +1 -1
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +3 -2
@@ -34,9 +34,10 @@
|
|
34
34
|
# 5 int8u - index of country in country list
|
35
35
|
# 6 int8u - 0xf0 = population E exponent (in format "N.Fe+0E"), 0x0f = population N digit
|
36
36
|
# 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
|
37
|
+
# 9 int16u - v1.02: 0x7fff = index in subregion (admin2), 0x8000 = high bit of time zone
|
38
|
+
# 9 int16u - v1.03: index in subregion (admin2)
|
38
39
|
# 11 int8u - low byte of time zone index
|
39
|
-
# 12 int8u - 0x0f
|
40
|
+
# 12 int8u - 0x0f = feature code index (see below), v1.03: 0x80 = high bit of time zone
|
40
41
|
# 13 string - UTF8 City name, terminated by newline
|
41
42
|
# "\0\0\0\0\x01"
|
42
43
|
# Country entries:
|
@@ -55,7 +56,7 @@
|
|
55
56
|
#
|
56
57
|
# Feature Codes: (see http://www.geonames.org/export/codes.html#P for descriptions)
|
57
58
|
#
|
58
|
-
# 0. Other 3. PPLA2 6. PPLA5 9. PPLF 12. PPLR
|
59
|
+
# 0. Other 3. PPLA2 6. PPLA5 9. PPLF 12. PPLR 15. PPLX
|
59
60
|
# 1. PPL 4. PPLA3 7. PPLC 10. PPLG 13. PPLS
|
60
61
|
# 2. PPLA 5. PPLA4 8. PPLCH 11. PPLL 14. STLMT
|
61
62
|
#------------------------------------------------------------------------------
|
@@ -65,9 +66,7 @@ package Image::ExifTool::Geolocation;
|
|
65
66
|
use strict;
|
66
67
|
use vars qw($VERSION $geoDir $altDir $dbInfo);
|
67
68
|
|
68
|
-
$VERSION = '1.
|
69
|
-
|
70
|
-
my $databaseVersion = '1.02';
|
69
|
+
$VERSION = '1.04'; # (this is the module version number, not the database version)
|
71
70
|
|
72
71
|
my $debug; # set to output processing time for testing
|
73
72
|
|
@@ -81,12 +80,13 @@ my (@cityList, @countryList, @regionList, @subregionList, @timezoneList);
|
|
81
80
|
my (%countryNum, %regionNum, %subregionNum, %timezoneNum); # reverse lookups
|
82
81
|
my (@sortOrder, @altNames, %langLookup, $nCity);
|
83
82
|
my ($lastArgs, %lastFound, @lastByPop, @lastByLat); # cached city matches
|
83
|
+
my $dbVer = '1.03';
|
84
84
|
my $sortedBy = 'Latitude';
|
85
85
|
my $pi = 3.1415926536;
|
86
86
|
my $earthRadius = 6371; # earth radius in km
|
87
87
|
|
88
|
-
my @featureCodes = qw(Other PPL PPLA PPLA2 PPLA3 PPLA4 PPLA5
|
89
|
-
|
88
|
+
my @featureCodes = qw(Other PPL PPLA PPLA2 PPLA3 PPLA4 PPLA5 PPLC
|
89
|
+
PPLCH PPLF PPLG PPLL PPLR PPLS STLMT PPLX);
|
90
90
|
my $i = 0;
|
91
91
|
my %featureCodes = map { lc($_) => $i++ } @featureCodes;
|
92
92
|
|
@@ -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
147
|
defined $comment and $comment =~ /(\d+)/ or close(DATFILE), return 0;
|
148
|
-
$dbInfo = "$datfile v$
|
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
|
@@ -268,11 +268,12 @@ sub SortDatabase($)
|
|
268
268
|
# Add cities to the Geolocation database
|
269
269
|
# Inputs: 0-8) city,region,subregion,country_code,country,timezone,feature_code,population,lat,lon,altNames
|
270
270
|
# eg. AddEntry('Sinemorets','Burgas','Obshtina Tsarevo','BG','Bulgaria','Europe/Sofia','',400,42.06115,27.97833)
|
271
|
+
# Returns: true on success, otherwise issues warning
|
271
272
|
sub AddEntry(@)
|
272
273
|
{
|
273
274
|
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;
|
275
|
+
@_ < 10 and warn("Too few arguments in $city definition (check for updated format)\n"), return 0;
|
276
|
+
length($cc) != 2 and warn("Country code '${cc}' is not 2 characters\n"), return 0;
|
276
277
|
$fc = $featureCodes{lc $fc} || 0;
|
277
278
|
chomp $lon; # (just in case it was read from file)
|
278
279
|
# create reverse lookups for country/region/subregion/timezone if not done already
|
@@ -286,6 +287,7 @@ sub AddEntry(@)
|
|
286
287
|
}
|
287
288
|
my $cn = $countryNum{lc $cc};
|
288
289
|
unless (defined $cn) {
|
290
|
+
$#countryList >= 0xff and warn("AddEntry: Too many countries\n"), return 0;
|
289
291
|
push @countryList, "$cc$country";
|
290
292
|
$cn = $countryNum{lc $cc} = $#countryList;
|
291
293
|
} elsif ($country) {
|
@@ -293,16 +295,20 @@ sub AddEntry(@)
|
|
293
295
|
}
|
294
296
|
my $tn = $timezoneNum{lc $timezone};
|
295
297
|
unless (defined $tn) {
|
298
|
+
$#timezoneList >= 0x1ff and warn("AddEntry: Too many time zones\n"), return 0;
|
296
299
|
push @timezoneList, $timezone;
|
297
300
|
$tn = $timezoneNum{lc $timezone} = $#timezoneList;
|
298
301
|
}
|
299
302
|
my $rn = $regionNum{lc $region};
|
300
303
|
unless (defined $rn) {
|
304
|
+
$#regionList >= 0xfff and warn("AddEntry: Too many regions\n"), return 0;
|
301
305
|
push @regionList, $region;
|
302
306
|
$rn = $regionNum{lc $region} = $#regionList;
|
303
307
|
}
|
304
308
|
my $sn = $subregionNum{lc $subregion};
|
305
309
|
unless (defined $sn) {
|
310
|
+
my $max = $dbVer eq '1.02' ? 0x0fff : 0xffff;
|
311
|
+
$#subregionList >= $max and warn("AddEntry: Too many subregions\n"), return 0;
|
306
312
|
push @subregionList, $subregion;
|
307
313
|
$sn = $subregionNum{lc $subregion} = $#subregionList;
|
308
314
|
}
|
@@ -310,7 +316,14 @@ sub AddEntry(@)
|
|
310
316
|
# pack CC index, population and region index into a 32-bit integer
|
311
317
|
my $code = ($cn << 24) | (substr($pop,-1,1)<<20) | (substr($pop,0,1)<<16) | (substr($pop,2,1)<<12) | $rn;
|
312
318
|
# store high bit of timezone index
|
313
|
-
$tn > 255
|
319
|
+
if ($tn > 255) {
|
320
|
+
if ($dbVer eq '1.02') {
|
321
|
+
$sn |= 0x8000;
|
322
|
+
} else {
|
323
|
+
$fc |= 0x80;
|
324
|
+
}
|
325
|
+
$tn -= 256;
|
326
|
+
}
|
314
327
|
$lat = int(($lat + 90) / 180 * 0x100000 + 0.5) & 0xfffff;
|
315
328
|
$lon = int(($lon + 180) / 360 * 0x100000 + 0.5) & 0xfffff;
|
316
329
|
my $hdr = pack('nCnNnCC', $lat>>4, (($lat&0x0f)<<4)|($lon&0x0f), $lon>>4, $code, $sn, $tn, $fc);
|
@@ -328,6 +341,7 @@ sub AddEntry(@)
|
|
328
341
|
}
|
329
342
|
$sortedBy = '';
|
330
343
|
undef $lastArgs; # (faster than ClearLastArgs)
|
344
|
+
return 1;
|
331
345
|
}
|
332
346
|
|
333
347
|
#------------------------------------------------------------------------------
|
@@ -341,14 +355,18 @@ sub GetEntry($;$$)
|
|
341
355
|
my ($entryNum, $lang, $sort) = @_;
|
342
356
|
return() if $entryNum > $#cityList;
|
343
357
|
$entryNum = $sortOrder[$entryNum] if $sort and @sortOrder > $entryNum;
|
344
|
-
my ($lt,$f,$ln,$code,$
|
358
|
+
my ($lt,$f,$ln,$code,$sn,$tn,$fc) = unpack('nCnNnCC', $cityList[$entryNum]);
|
345
359
|
my $city = substr($cityList[$entryNum],13);
|
346
360
|
my $ctry = $countryList[$code >> 24];
|
347
361
|
my $rgn = $regionList[$code & 0x0fff];
|
348
|
-
|
362
|
+
if ($dbVer eq '1.02') {
|
363
|
+
$sn & 0x8000 and $tn += 256, $sn &= 0x7fff;
|
364
|
+
} else {
|
365
|
+
$fc & 0x80 and $tn += 256;
|
366
|
+
}
|
367
|
+
my $sub = $subregionList[$sn];
|
349
368
|
# convert population digits back into exponent format
|
350
369
|
my $pop = (($code>>16 & 0x0f) . '.' . ($code>>12 & 0x0f) . 'e+' . ($code>>20 & 0x0f)) + 0;
|
351
|
-
$tn += 256 if $sb & 0x8000;
|
352
370
|
$lt = sprintf('%.4f', (($lt<<4)|($f >> 4)) * 180 / 0x100000 - 90);
|
353
371
|
$ln = sprintf('%.4f', (($ln<<4)|($f & 0x0f))* 360 / 0x100000 - 180);
|
354
372
|
$fc = $featureCodes[$fc & 0x0f];
|
@@ -511,9 +529,10 @@ Entry: for (; $i<@cityList; ++$i) {
|
|
511
529
|
if ($regex{8}) { $cty =~ $_ or next Entry foreach @{$regex{8}} }
|
512
530
|
if ($regex{18}) { $cty !~ $_ or next Entry foreach @{$regex{18}} }
|
513
531
|
# test other arguments
|
514
|
-
my ($cd,$
|
532
|
+
my ($cd,$sn) = unpack('x5Nn', $cityList[$i]);
|
515
533
|
my $ct = $countryList[$cd >> 24];
|
516
|
-
|
534
|
+
$sn &= 0x7fff if $dbVer eq '1.02';
|
535
|
+
my @geo = (substr($ct,0,2), substr($ct,2), $regionList[$cd & 0x0fff], $subregionList[$sn]);
|
517
536
|
if (@exact) {
|
518
537
|
# make quick lookup for all names at this location
|
519
538
|
my %geoLkup;
|
@@ -746,6 +765,10 @@ database, then the database entry is updated with the new country name.
|
|
746
765
|
|
747
766
|
10) Optional comma-separated list of alternate names for the city
|
748
767
|
|
768
|
+
=item Return Value:
|
769
|
+
|
770
|
+
1 on success, otherwise sends a warning message to stderr
|
771
|
+
|
749
772
|
=back
|
750
773
|
|
751
774
|
=head2 GetEntry
|
@@ -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.32';
|
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,7 +5499,7 @@ 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
|
@@ -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.95';
|
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($$$);
|
@@ -7870,20 +7873,9 @@ my %isImageData = ( av01 => 1, avc1 => 1, hvc1 => 1, lhv1 => 1, hvt1 => 1 );
|
|
7870
7873
|
#
|
7871
7874
|
ftab => { Name => 'FontTable', Format => 'undef', ValueConv => 'substr($val, 5)' },
|
7872
7875
|
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
|
7876
|
+
mrlh => { Name => 'MarlinHeader', SubDirectory => { TagTable => 'Image::ExifTool::GM::mrlh' } },
|
7877
|
+
mrlv => { Name => 'MarlinValues', SubDirectory => { TagTable => 'Image::ExifTool::GM::mrlv' } },
|
7878
|
+
mrld => { Name => 'MarlinDictionary',SubDirectory => { TagTable => 'Image::ExifTool::GM::mrld' } },
|
7887
7879
|
);
|
7888
7880
|
|
7889
7881
|
# MP4 data information box (ref 5)
|
@@ -9478,7 +9470,7 @@ sub ProcessMOV($$;$)
|
|
9478
9470
|
my $dirID = $$dirInfo{DirID} || '';
|
9479
9471
|
my $charsetQuickTime = $et->Options('CharsetQuickTime');
|
9480
9472
|
my ($buff, $tag, $size, $track, $isUserData, %triplet, $doDefaultLang, $index);
|
9481
|
-
my ($dirEnd, $unkOpt, %saveOptions, $atomCount);
|
9473
|
+
my ($dirEnd, $unkOpt, %saveOptions, $atomCount, $warnStr);
|
9482
9474
|
|
9483
9475
|
my $topLevel = not $$et{InQuickTime};
|
9484
9476
|
$$et{InQuickTime} = 1;
|
@@ -9558,6 +9550,7 @@ sub ProcessMOV($$;$)
|
|
9558
9550
|
$index = $$tagTablePtr{VARS}{START_INDEX};
|
9559
9551
|
$atomCount = $$tagTablePtr{VARS}{ATOM_COUNT};
|
9560
9552
|
}
|
9553
|
+
my $lastTag = '';
|
9561
9554
|
for (;;) {
|
9562
9555
|
my ($eeTag, $ignore);
|
9563
9556
|
last if defined $atomCount and --$atomCount < 0;
|
@@ -9584,22 +9577,22 @@ sub ProcessMOV($$;$)
|
|
9584
9577
|
}
|
9585
9578
|
last;
|
9586
9579
|
}
|
9587
|
-
$size == 1 or $
|
9580
|
+
$size == 1 or $warnStr = 'Invalid atom size', last;
|
9588
9581
|
# read extended atom size
|
9589
|
-
$raf->Read($buff, 8) == 8 or $
|
9582
|
+
$raf->Read($buff, 8) == 8 or $warnStr = 'Truncated atom header', last;
|
9590
9583
|
$dataPos += 8;
|
9591
9584
|
my ($hi, $lo) = unpack('NN', $buff);
|
9592
9585
|
if ($hi or $lo > 0x7fffffff) {
|
9593
9586
|
if ($hi > 0x7fffffff) {
|
9594
|
-
$
|
9587
|
+
$warnStr = 'Invalid atom size';
|
9595
9588
|
last;
|
9596
9589
|
} elsif (not $et->Options('LargeFileSupport')) {
|
9597
|
-
$
|
9590
|
+
$warnStr = 'End of processing at large atom (LargeFileSupport not enabled)';
|
9598
9591
|
last;
|
9599
9592
|
}
|
9600
9593
|
}
|
9601
9594
|
$size = $hi * 4294967296 + $lo - 16;
|
9602
|
-
$size < 0 and $
|
9595
|
+
$size < 0 and $warnStr = 'Invalid extended size', last;
|
9603
9596
|
} else {
|
9604
9597
|
$size -= 8;
|
9605
9598
|
}
|
@@ -9755,7 +9748,7 @@ ItemID: foreach $id (reverse sort { $a <=> $b } keys %$items) {
|
|
9755
9748
|
my $missing = $size - $raf->Read($val, $size);
|
9756
9749
|
if ($missing) {
|
9757
9750
|
my $t = PrintableTagID($tag,2);
|
9758
|
-
$
|
9751
|
+
$warnStr = "Truncated '${t}' data (missing $missing bytes)";
|
9759
9752
|
last;
|
9760
9753
|
}
|
9761
9754
|
# use value to get tag info if necessary
|
@@ -10070,16 +10063,28 @@ ItemID: foreach $id (reverse sort { $a <=> $b } keys %$items) {
|
|
10070
10063
|
) if $verbose;
|
10071
10064
|
if ($size and (not $raf->Seek($size-1, 1) or $raf->Read($buff, 1) != 1)) {
|
10072
10065
|
my $t = PrintableTagID($tag,2);
|
10073
|
-
$
|
10066
|
+
$warnStr = "Truncated '${t}' data";
|
10074
10067
|
last;
|
10075
10068
|
}
|
10076
10069
|
}
|
10077
10070
|
$dataPos += $size + 8; # point to start of next atom data
|
10078
10071
|
last if $dirEnd and $dataPos >= $dirEnd; # (note: ignores last value if 0 bytes)
|
10079
10072
|
$raf->Read($buff, 8) == 8 or last;
|
10073
|
+
$lastTag = $tag if $$tagTablePtr{$tag};
|
10080
10074
|
($size, $tag) = unpack('Na4', $buff);
|
10081
10075
|
++$index if defined $index;
|
10082
10076
|
}
|
10077
|
+
if ($warnStr) {
|
10078
|
+
# assume this is an unknown trailer if it comes immediately after
|
10079
|
+
# mdat or moov and has a tag name we don't recognize
|
10080
|
+
if (($lastTag eq 'mdat' or $lastTag eq 'moov') and (not $$tagTablePtr{$tag} or
|
10081
|
+
ref $$tagTablePtr{$tag} eq 'HASH' and $$tagTablePtr{$tag}{Unknown}))
|
10082
|
+
{
|
10083
|
+
$et->Warn('Unknown trailer with '.lcfirst($warnStr));
|
10084
|
+
} else {
|
10085
|
+
$et->Warn($warnStr);
|
10086
|
+
}
|
10087
|
+
}
|
10083
10088
|
# tweak file type based on track content ("iso*" and "dash" ftyp only)
|
10084
10089
|
if ($topLevel and $$et{FileType} and $$et{FileType} eq 'MP4' and
|
10085
10090
|
$$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,11 @@ 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
|
+
},
|
329
341
|
Unknown00 => { Unknown => 1 },
|
330
342
|
Unknown01 => { Unknown => 1 },
|
331
343
|
Unknown02 => { Unknown => 1 },
|
@@ -741,13 +753,6 @@ my %insvLimit = (
|
|
741
753
|
10 => { Name => 'FusionYPR', Format => 'float[3]' },
|
742
754
|
);
|
743
755
|
|
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
756
|
#------------------------------------------------------------------------------
|
752
757
|
# Save information from keys in OtherSampleDesc directory for processing timed metadata
|
753
758
|
# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
|
@@ -2219,26 +2224,6 @@ sub Process_tx3g($$$)
|
|
2219
2224
|
return 1;
|
2220
2225
|
}
|
2221
2226
|
|
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
2227
|
#------------------------------------------------------------------------------
|
2243
2228
|
# Process QuickTime 'mebx' timed metadata
|
2244
2229
|
# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
|
@@ -3229,6 +3214,52 @@ sub ProcessFMAS($$$)
|
|
3229
3214
|
return 1;
|
3230
3215
|
}
|
3231
3216
|
|
3217
|
+
#------------------------------------------------------------------------------
|
3218
|
+
# Process GPS from Wolfbox G900 Dashcam
|
3219
|
+
# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
|
3220
|
+
# Returns: 1 on success
|
3221
|
+
sub ProcessWolfbox($$$)
|
3222
|
+
{
|
3223
|
+
my ($et, $dirInfo, $tagTbl) = @_;
|
3224
|
+
my $dataPt = $$dirInfo{DataPt};
|
3225
|
+
return 0 if length($$dataPt) < 0xc8;
|
3226
|
+
$et->VerboseDir('Wolfbox', undef, length($$dataPt));
|
3227
|
+
# 0000: 65 00 00 00 00 00 00 00 31 01 01 00 e3 ff 00 00 [e.......1.......]
|
3228
|
+
# 0010: 04 00 00 00 10 00 00 00 2a 00 00 00 00 00 00 00 [........*.......]
|
3229
|
+
# 0020: 01 00 00 00 00 00 00 00 8b 33 ff 51 00 00 00 00 [.........3.Q....]
|
3230
|
+
# 0030: a0 86 01 00 00 00 00 00 4d 5e 07 fa ff ff ff ff [........M^......]
|
3231
|
+
# 0040: a0 86 01 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
|
3232
|
+
# 0050: 64 00 00 00 00 00 00 00 90 21 00 00 00 00 00 00 [d........!......]
|
3233
|
+
# 0060: 64 00 00 00 00 00 00 00 18 00 00 00 03 00 00 00 [d...............]
|
3234
|
+
# 0070: e8 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
|
3235
|
+
# 0080: 00 00 00 00 00 00 00 00 30 30 30 30 30 30 30 30 [........00000000]
|
3236
|
+
# 0090: 30 30 30 30 30 30 30 30 48 59 54 48 00 00 00 00 [00000000HYTH....]
|
3237
|
+
# 00a0: 0c 00 00 00 10 00 00 00 2a 00 00 00 00 00 00 00 [........*.......]
|
3238
|
+
# 00b0: 4f 3f 0c 1f 00 00 00 00 a0 86 01 00 00 00 00 00 [O?..............]
|
3239
|
+
# 00c0: 7f cf 2d ff ff ff ff ff a0 86 01 00 00 00 00 00 [..-.............]
|
3240
|
+
# 00d0: 01 00 00 00 08 00 00 00 0a 00 00 00 00 00 00 00 [................]
|
3241
|
+
# 00e0: 0a 00 00 00 00 00 00 00 e8 03 00 00 00 00 00 00 [................]
|
3242
|
+
# 00f0: 0a 00 00 00 00 00 00 00 4d 00 00 00 00 00 00 00 [........M.......]
|
3243
|
+
# lat/lon at 0xb0/0xc0 and 0x128/0x138
|
3244
|
+
# h/m/s at 0x10 and 0xa0 and 0x148 (the first imprinted on the video, the latter 2 presumed UTC)
|
3245
|
+
# spd at 0x48, dir at 0x58, alt at 0xe8
|
3246
|
+
SetByteOrder('II');
|
3247
|
+
my ($spd,$dir,$d,$mo,$yr,$h,$m,$s) = unpack('x72Vx12Vx12V3x44V3',$$dataPt);
|
3248
|
+
# offset 0xa0 also stores hh mm ss, but is out by 8 hours!
|
3249
|
+
my $time = sprintf '%.4d:%.2d:%.2d %.2d:%.2d:%.2dZ', $yr, $mo, $d, $h, $m, $s;
|
3250
|
+
my ($lat, $lon) = (Get32s($dataPt, 0xb0) / 1e5, Get32s($dataPt, 0xc0) / 1e5);
|
3251
|
+
my $alt = Get32s($dataPt, 0xe8);
|
3252
|
+
ConvertLatLon($lat, $lon);
|
3253
|
+
$et->HandleTag($tagTbl, GPSDateTime => $time);
|
3254
|
+
$et->HandleTag($tagTbl, GPSLatitude => $lat);
|
3255
|
+
$et->HandleTag($tagTbl, GPSLongitude => $lon);
|
3256
|
+
$et->HandleTag($tagTbl, GPSSpeed => $spd * $knotsToKph / 100);
|
3257
|
+
$et->HandleTag($tagTbl, GPSTrack => $dir / 100);
|
3258
|
+
$et->HandleTag($tagTbl, GPSAltitude => $alt / 10); # (NC)
|
3259
|
+
SetByteOrder('MM');
|
3260
|
+
return 1;
|
3261
|
+
}
|
3262
|
+
|
3232
3263
|
#------------------------------------------------------------------------------
|
3233
3264
|
# Scan media data for "freeGPS" metadata if not found already (ref PH)
|
3234
3265
|
# Inputs: 0) ExifTool ref
|
@@ -1132,6 +1132,8 @@ keys in structure hashes are:
|
|
1132
1132
|
GROUPS : Same as in tag table, but only the family 2 group name is used,
|
1133
1133
|
as the default for the flattened tags.
|
1134
1134
|
|
1135
|
+
SORT_ORDER : Order for sorting fields in documentation.
|
1136
|
+
|
1135
1137
|
The contained structure field information hashes are similar to tag information
|
1136
1138
|
hashes, except that only the following elements are used:
|
1137
1139
|
|
@@ -2083,6 +2083,7 @@ my %tagLookup = (
|
|
2083
2083
|
'cropcirclex' => { 112 => 0xd7 },
|
2084
2084
|
'cropcircley' => { 112 => 0xd8 },
|
2085
2085
|
'cropconstraintowarp' => { 511 => 'CropConstrainToWarp', 513 => 'CropConstrainToWarp' },
|
2086
|
+
'cropflag' => { 130 => 0x1051 },
|
2086
2087
|
'croph' => { 505 => 'CropH' },
|
2087
2088
|
'cropheight' => { 104 => 0x6, 111 => 0x24c, 328 => 0x615, 332 => 0x615, 511 => 'CropHeight', 513 => 'CropHeight' },
|
2088
2089
|
'crophispeed' => { 239 => 0x1b },
|
@@ -2098,7 +2099,6 @@ my %tagLookup = (
|
|
2098
2099
|
'cropoutputscale' => { 292 => 0xbe },
|
2099
2100
|
'cropoutputwidth' => { 292 => 0xc6 },
|
2100
2101
|
'cropoutputwidthinches' => { 292 => 0x8e },
|
2101
|
-
'cropped' => { 130 => 0x1051 },
|
2102
2102
|
'croppedareaimageheightpixels' => { 499 => 'CroppedAreaImageHeightPixels', 500 => 'CroppedAreaImageHeightPixels' },
|
2103
2103
|
'croppedareaimagewidthpixels' => { 499 => 'CroppedAreaImageWidthPixels', 500 => 'CroppedAreaImageWidthPixels' },
|
2104
2104
|
'croppedarealeftpixels' => { 499 => 'CroppedAreaLeftPixels', 500 => 'CroppedAreaLeftPixels' },
|
@@ -8330,6 +8330,21 @@ my %tagExists = (
|
|
8330
8330
|
'cfagreenthreshold2' => 1,
|
8331
8331
|
'cfalayout' => 1,
|
8332
8332
|
'cfaplanecolor' => 1,
|
8333
|
+
'channel01' => 1,
|
8334
|
+
'channel01description' => 1,
|
8335
|
+
'channel01dispmax' => 1,
|
8336
|
+
'channel01dispmin' => 1,
|
8337
|
+
'channel01flags' => 1,
|
8338
|
+
'channel01id' => 1,
|
8339
|
+
'channel01interval' => 1,
|
8340
|
+
'channel01max' => 1,
|
8341
|
+
'channel01min' => 1,
|
8342
|
+
'channel01multiplier' => 1,
|
8343
|
+
'channel01name' => 1,
|
8344
|
+
'channel01num' => 1,
|
8345
|
+
'channel01offset' => 1,
|
8346
|
+
'channel01type' => 1,
|
8347
|
+
'channel01units' => 1,
|
8333
8348
|
'channel0lagkernel' => 1,
|
8334
8349
|
'channel1coordinates' => 1,
|
8335
8350
|
'channel1flags' => 1,
|
@@ -8707,6 +8722,7 @@ my %tagExists = (
|
|
8707
8722
|
'crgbtoerimm9spline' => 1,
|
8708
8723
|
'cropdata' => 1,
|
8709
8724
|
'cropinfo' => 1,
|
8725
|
+
'cropped' => 1,
|
8710
8726
|
'cropxcommonoffset' => 1,
|
8711
8727
|
'cropxoffset' => 1,
|
8712
8728
|
'cropxoffset2' => 1,
|
@@ -8818,6 +8834,8 @@ my %tagExists = (
|
|
8818
8834
|
'datasize64' => 1,
|
8819
8835
|
'datatype' => 1,
|
8820
8836
|
'datawindow' => 1,
|
8837
|
+
'date1' => 1,
|
8838
|
+
'date2' => 1,
|
8821
8839
|
'dateaccessed' => 1,
|
8822
8840
|
'datearchived' => 1,
|
8823
8841
|
'datecompleted' => 1,
|
@@ -9652,6 +9670,7 @@ my %tagExists = (
|
|
9652
9670
|
'gpmd_gopro' => 1,
|
9653
9671
|
'gpmd_kingslim' => 1,
|
9654
9672
|
'gpmd_rove' => 1,
|
9673
|
+
'gpmd_wolfbox' => 1,
|
9655
9674
|
'gps' => 1,
|
9656
9675
|
'gps360fly' => 1,
|
9657
9676
|
'gpsaltituderaw' => 1,
|
@@ -10467,6 +10486,10 @@ my %tagExists = (
|
|
10467
10486
|
'markerid' => 1,
|
10468
10487
|
'markinfo' => 1,
|
10469
10488
|
'marl' => 1,
|
10489
|
+
'marlindataversion' => 1,
|
10490
|
+
'marlindictionary' => 1,
|
10491
|
+
'marlinheader' => 1,
|
10492
|
+
'marlinvalues' => 1,
|
10470
10493
|
'masksubarea' => 1,
|
10471
10494
|
'masteredby' => 1,
|
10472
10495
|
'mastergainadjustment' => 1,
|
@@ -12517,6 +12540,8 @@ my %tagExists = (
|
|
12517
12540
|
'tilegaindeterminationtable' => 1,
|
12518
12541
|
'tileoffsets' => 1,
|
12519
12542
|
'tiles' => 1,
|
12543
|
+
'time1' => 1,
|
12544
|
+
'time2' => 1,
|
12520
12545
|
'timeanddate' => 1,
|
12521
12546
|
'timecode' => 1,
|
12522
12547
|
'timecodeindex' => 1,
|