exiftool_vendored 12.22.0 → 12.25.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 +50 -0
- data/bin/MANIFEST +11 -0
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +44 -43
- data/bin/config_files/acdsee.config +193 -6
- data/bin/config_files/cuepointlist.config +70 -0
- data/bin/exiftool +45 -44
- data/bin/lib/Image/ExifTool.pm +85 -26
- data/bin/lib/Image/ExifTool.pod +61 -50
- data/bin/lib/Image/ExifTool/BuildTagLookup.pm +1 -1
- data/bin/lib/Image/ExifTool/Canon.pm +3 -2
- data/bin/lib/Image/ExifTool/DjVu.pm +6 -5
- data/bin/lib/Image/ExifTool/Exif.pm +16 -7
- data/bin/lib/Image/ExifTool/FujiFilm.pm +18 -8
- data/bin/lib/Image/ExifTool/JPEG.pm +6 -2
- data/bin/lib/Image/ExifTool/JSON.pm +24 -3
- data/bin/lib/Image/ExifTool/Jpeg2000.pm +361 -16
- data/bin/lib/Image/ExifTool/MRC.pm +341 -0
- data/bin/lib/Image/ExifTool/MWG.pm +3 -3
- data/bin/lib/Image/ExifTool/MXF.pm +1 -1
- data/bin/lib/Image/ExifTool/MacOS.pm +1 -1
- data/bin/lib/Image/ExifTool/Microsoft.pm +5 -3
- data/bin/lib/Image/ExifTool/Nikon.pm +3 -2
- data/bin/lib/Image/ExifTool/NikonSettings.pm +10 -1
- data/bin/lib/Image/ExifTool/PNG.pm +2 -2
- data/bin/lib/Image/ExifTool/Panasonic.pm +14 -1
- data/bin/lib/Image/ExifTool/PhaseOne.pm +4 -3
- data/bin/lib/Image/ExifTool/QuickTime.pm +102 -44
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +88 -29
- data/bin/lib/Image/ExifTool/RIFF.pm +83 -11
- data/bin/lib/Image/ExifTool/Samsung.pm +2 -1
- data/bin/lib/Image/ExifTool/Sony.pm +98 -24
- data/bin/lib/Image/ExifTool/TagLookup.pm +56 -15
- data/bin/lib/Image/ExifTool/TagNames.pod +388 -173
- data/bin/lib/Image/ExifTool/WritePostScript.pl +1 -0
- data/bin/lib/Image/ExifTool/WriteQuickTime.pl +37 -12
- data/bin/lib/Image/ExifTool/WriteXMP.pl +6 -2
- data/bin/lib/Image/ExifTool/Writer.pl +1 -0
- data/bin/lib/Image/ExifTool/XMP.pm +20 -7
- data/bin/perl-Image-ExifTool.spec +42 -42
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +6 -8
@@ -17,7 +17,7 @@ use strict;
|
|
17
17
|
use vars qw($VERSION);
|
18
18
|
use Image::ExifTool qw(:DataAccess :Utils);
|
19
19
|
|
20
|
-
$VERSION = '1.
|
20
|
+
$VERSION = '1.03';
|
21
21
|
|
22
22
|
sub ProcessNikonSettings($$$);
|
23
23
|
|
@@ -1919,6 +1919,15 @@ my %infoD6 = (
|
|
1919
1919
|
10 => 'Auto (Animals)',
|
1920
1920
|
},
|
1921
1921
|
},
|
1922
|
+
0x170 => { Name => 'PreferSubSelectorCenter', PrintConv => \%offOn }, # CSf13 (D6 firmware v1.2.0)
|
1923
|
+
0x174 => { # CSa17-d (D6 firmware v1.2.0)
|
1924
|
+
Name => 'FocusPointSelectionSpeed',
|
1925
|
+
PrintConv => {
|
1926
|
+
1 => 'Normal',
|
1927
|
+
2 => 'High',
|
1928
|
+
3 => 'Very High',
|
1929
|
+
},
|
1930
|
+
},
|
1922
1931
|
);
|
1923
1932
|
|
1924
1933
|
#------------------------------------------------------------------------------
|
@@ -36,7 +36,7 @@ use strict;
|
|
36
36
|
use vars qw($VERSION $AUTOLOAD %stdCase);
|
37
37
|
use Image::ExifTool qw(:DataAccess :Utils);
|
38
38
|
|
39
|
-
$VERSION = '1.
|
39
|
+
$VERSION = '1.57';
|
40
40
|
|
41
41
|
sub ProcessPNG_tEXt($$$);
|
42
42
|
sub ProcessPNG_iTXt($$$);
|
@@ -975,7 +975,7 @@ sub FoundPNG($$$$;$$$$)
|
|
975
975
|
$$tagInfo{LangCode} = $lang if $lang;
|
976
976
|
# make unknown profiles binary data type
|
977
977
|
$$tagInfo{Binary} = 1 if $tag =~ /^Raw profile type /;
|
978
|
-
$verbose and $et->VPrint(0, "
|
978
|
+
$verbose and $et->VPrint(0, " [adding $tag]\n");
|
979
979
|
AddTagToTable($tagTablePtr, $tag, $tagInfo);
|
980
980
|
}
|
981
981
|
#
|
@@ -2118,6 +2118,7 @@ my %shootingMode = (
|
|
2118
2118
|
Name => 'UserProfile',
|
2119
2119
|
Writable => 'string',
|
2120
2120
|
},
|
2121
|
+
# 0x357 int32u - 0=DNG, 3162=JPG (ref 23)
|
2121
2122
|
0x359 => { #23
|
2122
2123
|
Name => 'ISOSelected',
|
2123
2124
|
Writable => 'int32s',
|
@@ -2134,7 +2135,19 @@ my %shootingMode = (
|
|
2134
2135
|
PrintConv => 'sprintf("%.1f", $val)',
|
2135
2136
|
PrintConvInv => '$val',
|
2136
2137
|
},
|
2137
|
-
|
2138
|
+
0x035b => { #IB
|
2139
|
+
Name => 'CorrelatedColorTemp', # (in Kelvin)
|
2140
|
+
Writable => 'int16u',
|
2141
|
+
},
|
2142
|
+
0x035c => { #IB
|
2143
|
+
Name => 'ColorTint', # (same units as Adobe is using)
|
2144
|
+
Writable => 'int16s',
|
2145
|
+
},
|
2146
|
+
0x035d => { #IB
|
2147
|
+
Name => 'WhitePoint', # (x/y)
|
2148
|
+
Writable => 'rational64u',
|
2149
|
+
Count => 2,
|
2150
|
+
},
|
2138
2151
|
);
|
2139
2152
|
|
2140
2153
|
# Type 2 tags (ref PH)
|
@@ -15,7 +15,7 @@ use vars qw($VERSION);
|
|
15
15
|
use Image::ExifTool qw(:DataAccess :Utils);
|
16
16
|
use Image::ExifTool::Exif;
|
17
17
|
|
18
|
-
$VERSION = '1.
|
18
|
+
$VERSION = '1.07';
|
19
19
|
|
20
20
|
sub WritePhaseOne($$$);
|
21
21
|
sub ProcessPhaseOne($$$);
|
@@ -73,10 +73,11 @@ my @formatName = ( undef, 'string', 'int16s', undef, 'int32s' );
|
|
73
73
|
PrintConv => { #PH
|
74
74
|
1 => 'RAW 1', #? (encrypted)
|
75
75
|
2 => 'RAW 2', #? (encrypted)
|
76
|
-
3 => 'IIQ L',
|
76
|
+
3 => 'IIQ L', # (now "L14", ref IB)
|
77
77
|
# 4?
|
78
78
|
5 => 'IIQ S',
|
79
|
-
6 => 'IIQ Sv2',
|
79
|
+
6 => 'IIQ Sv2', # (now "S14" for "IIQ 14 Smart" and "IIQ 14 Sensor+", ref IB)
|
80
|
+
8 => 'IIQ L16', #IB ("IIQ 16 Extended" and "IIQ 16 Large")
|
80
81
|
},
|
81
82
|
},
|
82
83
|
0x010f => {
|
@@ -47,7 +47,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
|
|
47
47
|
use Image::ExifTool::Exif;
|
48
48
|
use Image::ExifTool::GPS;
|
49
49
|
|
50
|
-
$VERSION = '2.
|
50
|
+
$VERSION = '2.63';
|
51
51
|
|
52
52
|
sub ProcessMOV($$;$);
|
53
53
|
sub ProcessKeys($$$);
|
@@ -65,6 +65,7 @@ sub Process_gsen($$$);
|
|
65
65
|
sub ProcessRIFFTrailer($$$);
|
66
66
|
sub ProcessTTAD($$$);
|
67
67
|
sub ProcessNMEA($$$);
|
68
|
+
sub ProcessGPSLog($$$);
|
68
69
|
sub SaveMetaKeys($$$);
|
69
70
|
# ++^^^^^^^^^^^^++
|
70
71
|
sub ParseItemLocation($$);
|
@@ -160,8 +161,15 @@ my %ftypLookup = (
|
|
160
161
|
'F4P ' => 'Protected Video for Adobe Flash Player 9+ (.F4P)', # video/mp4
|
161
162
|
'F4V ' => 'Video for Adobe Flash Player 9+ (.F4V)', # video/mp4
|
162
163
|
'isc2' => 'ISMACryp 2.0 Encrypted File', # ?/enc-isoff-generic
|
163
|
-
'iso2' => 'MP4 Base Media v2 [ISO 14496-12:2005]', # video/mp4
|
164
|
-
'
|
164
|
+
'iso2' => 'MP4 Base Media v2 [ISO 14496-12:2005]', # video/mp4 (or audio)
|
165
|
+
'iso3' => 'MP4 Base Media v3', # video/mp4 (or audio)
|
166
|
+
'iso4' => 'MP4 Base Media v4', # video/mp4 (or audio)
|
167
|
+
'iso5' => 'MP4 Base Media v5', # video/mp4 (or audio)
|
168
|
+
'iso6' => 'MP4 Base Media v6', # video/mp4 (or audio)
|
169
|
+
'iso7' => 'MP4 Base Media v7', # video/mp4 (or audio)
|
170
|
+
'iso8' => 'MP4 Base Media v8', # video/mp4 (or audio)
|
171
|
+
'iso9' => 'MP4 Base Media v9', # video/mp4 (or audio)
|
172
|
+
'isom' => 'MP4 Base Media v1 [IS0 14496-12:2003]', # video/mp4 (or audio)
|
165
173
|
'JP2 ' => 'JPEG 2000 Image (.JP2) [ISO 15444-1 ?]', # image/jp2
|
166
174
|
'JP20' => 'Unknown, from GPAC samples (prob non-existent)',
|
167
175
|
'jpm ' => 'JPEG 2000 Compound Image (.JPM) [ISO 15444-6]', # image/jpm
|
@@ -678,6 +686,15 @@ my %eeBox2 = (
|
|
678
686
|
udat => { #PH (GPS NMEA-format log written by Datakam Player software)
|
679
687
|
Name => 'GPSLog',
|
680
688
|
Binary => 1, # (actually ASCII, but very lengthy)
|
689
|
+
Notes => 'parsed to extract GPS separately when ExtractEmbedded is used',
|
690
|
+
RawConv => q{
|
691
|
+
$val =~ s/\0+$//; # remove trailing nulls
|
692
|
+
if (length $val and $$self{OPTIONS}{ExtractEmbedded}) {
|
693
|
+
my $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream');
|
694
|
+
Image::ExifTool::QuickTime::ProcessGPSLog($self, { DataPt => \$val }, $tagTbl);
|
695
|
+
}
|
696
|
+
return $val;
|
697
|
+
},
|
681
698
|
},
|
682
699
|
# meta - proprietary XML information written by some Flip cameras - PH
|
683
700
|
# beam - 16 bytes found in an iPhone video
|
@@ -1564,36 +1581,29 @@ my %eeBox2 = (
|
|
1564
1581
|
coll => { Name => 'CollectionName', %langText3gp }, #17
|
1565
1582
|
rtng => {
|
1566
1583
|
Name => 'Rating',
|
1584
|
+
Writable => 'undef',
|
1585
|
+
Avoid => 1,
|
1567
1586
|
# (4-byte flags, 4-char entity, 4-char criteria, 2-byte lang, string)
|
1568
|
-
|
1569
|
-
|
1570
|
-
|
1571
|
-
|
1572
|
-
my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 12));
|
1573
|
-
$lang = $lang ? "($lang) " : '';
|
1574
|
-
$val = substr($val, 14);
|
1575
|
-
$val = $self->Decode($val, 'UCS2') if $val =~ /^\xfe\xff/;
|
1576
|
-
return $lang . $str . ' ' . $val;
|
1577
|
-
},
|
1587
|
+
IText => 14, # (14 bytes before string)
|
1588
|
+
Notes => 'string in the form "Entity=XXXX Criteria=XXXX XXXXX", used in 3gp videos',
|
1589
|
+
ValueConv => '$val=~s/^(.{4})(.{4})/Entity=$1 Criteria=$2 /i; $val',
|
1590
|
+
ValueConvInv => '$val=~s/Entity=(.{4}) Criteria=(.{4}) ?/$1$2/i; $val',
|
1578
1591
|
},
|
1579
1592
|
clsf => {
|
1580
1593
|
Name => 'Classification',
|
1594
|
+
Writable => 'undef',
|
1595
|
+
Avoid => 1,
|
1581
1596
|
# (4-byte flags, 4-char entity, 2-byte index, 2-byte lang, string)
|
1582
|
-
|
1583
|
-
|
1584
|
-
|
1585
|
-
|
1586
|
-
my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 10));
|
1587
|
-
$lang = $lang ? "($lang) " : '';
|
1588
|
-
$val = substr($val, 12);
|
1589
|
-
$val = $self->Decode($val, 'UCS2') if $val =~ /^\xfe\xff/;
|
1590
|
-
return $lang . $str . ' ' . $val;
|
1591
|
-
},
|
1597
|
+
IText => 12,
|
1598
|
+
Notes => 'string in the form "Entity=XXXX Index=### XXXXX", used in 3gp videos',
|
1599
|
+
ValueConv => '$val=~s/^(.{4})(.{2})/"Entity=$1 Index=".unpack("n",$2)." "/ie; $val',
|
1600
|
+
ValueConvInv => '$val=~s/Entity=(.{4}) Index=(\d+) ?/$1.pack("n",$2)/ie; $val',
|
1592
1601
|
},
|
1593
1602
|
kywd => {
|
1594
1603
|
Name => 'Keywords',
|
1595
1604
|
# (4 byte flags, 2-byte lang, 1-byte count, count x pascal strings, ref 17)
|
1596
|
-
# (but I have also seen a simple string written by iPhone)
|
1605
|
+
# (but I have also seen a simple string written by iPhone, so don't make writable yet)
|
1606
|
+
Notes => "not writable because Apple doesn't follow the 3gp specification",
|
1597
1607
|
RawConv => q{
|
1598
1608
|
my $sep = $self->Options('ListSep');
|
1599
1609
|
return join($sep, split /\0+/, $val) unless $val =~ /^\0/; # (iPhone)
|
@@ -1618,20 +1628,24 @@ my %eeBox2 = (
|
|
1618
1628
|
loci => {
|
1619
1629
|
Name => 'LocationInformation',
|
1620
1630
|
Groups => { 2 => 'Location' },
|
1631
|
+
Writable => 'undef',
|
1632
|
+
IText => 6,
|
1633
|
+
Avoid => 1,
|
1634
|
+
NoDecode => 1, # (we'll decode the data ourself)
|
1635
|
+
Notes => q{
|
1636
|
+
string in the form "XXXXX Role=XXX Lat=XXX Lon=XXX Alt=XXX Body=XXX
|
1637
|
+
Notes=XXX", used in 3gp videos
|
1638
|
+
},
|
1621
1639
|
# (4-byte flags, 2-byte lang, location string, 1-byte role, 4-byte fixed longitude,
|
1622
1640
|
# 4-byte fixed latitude, 4-byte fixed altitude, body string, notes string)
|
1623
1641
|
RawConv => q{
|
1624
|
-
return '<err>' unless length $val >= 6;
|
1625
|
-
my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 4));
|
1626
|
-
$lang = $lang ? "($lang) " : '';
|
1627
|
-
$val = substr($val, 6);
|
1628
1642
|
my $str;
|
1629
1643
|
if ($val =~ /^\xfe\xff/) {
|
1630
1644
|
$val =~ s/^(\xfe\xff(.{2})*?)\0\0//s or return '<err>';
|
1631
1645
|
$str = $self->Decode($1, 'UCS2');
|
1632
1646
|
} else {
|
1633
1647
|
$val =~ s/^(.*?)\0//s or return '<err>';
|
1634
|
-
$str = $1;
|
1648
|
+
$str = $self->Decode($1, 'UTF8');
|
1635
1649
|
}
|
1636
1650
|
$str = '(none)' unless length $str;
|
1637
1651
|
return '<err>' if length $val < 13;
|
@@ -1646,27 +1660,52 @@ my %eeBox2 = (
|
|
1646
1660
|
if ($val =~ s/^(\xfe\xff(.{2})*?)\0\0//s) {
|
1647
1661
|
$str .= ' Body=' . $self->Decode($1, 'UCS2');
|
1648
1662
|
} elsif ($val =~ s/^(.*?)\0//s) {
|
1649
|
-
$str .=
|
1663
|
+
$str .= ' Body=' . $self->Decode($1, 'UTF8');
|
1650
1664
|
}
|
1651
1665
|
if ($val =~ s/^(\xfe\xff(.{2})*?)\0\0//s) {
|
1652
1666
|
$str .= ' Notes=' . $self->Decode($1, 'UCS2');
|
1653
1667
|
} elsif ($val =~ s/^(.*?)\0//s) {
|
1654
|
-
$str .=
|
1668
|
+
$str .= ' Notes=' . $self->Decode($1, 'UTF8');
|
1655
1669
|
}
|
1656
|
-
return $
|
1670
|
+
return $str;
|
1671
|
+
},
|
1672
|
+
RawConvInv => q{
|
1673
|
+
my ($role, $lat, $lon, $alt, $body, $note);
|
1674
|
+
$lat = $1 if $val =~ s/ Lat=([-+]?[.\d]+)//i;
|
1675
|
+
$lon = $1 if $val =~ s/ Lon=([-+]?[.\d]+)//i;
|
1676
|
+
$alt = $1 if $val =~ s/ Alt=([-+]?[.\d]+)//i;
|
1677
|
+
$note = $val =~ s/ Notes=(.*)//i ? $1 : '';
|
1678
|
+
$body = $val =~ s/ Body=(.*)//i ? $1 : '';
|
1679
|
+
$role = $val =~ s/ Role=(.*)//i ? $1 : '';
|
1680
|
+
$val = '' if $val eq '(none)';
|
1681
|
+
$role = {shooting=>0,real=>1,fictional=>2}->{lc $role} || 0;
|
1682
|
+
return $self->Encode($val, 'UTF8') . "\0" . Set8u($role) .
|
1683
|
+
SetFixed32s(defined $lon ? $lon : 999) .
|
1684
|
+
SetFixed32s(defined $lat ? $lat : 999) .
|
1685
|
+
SetFixed32s(defined $alt ? $alt : 0) .
|
1686
|
+
$self->Encode($body) . "\0" .
|
1687
|
+
$self->Encode($note) . "\0";
|
1657
1688
|
},
|
1658
1689
|
},
|
1659
1690
|
yrrc => {
|
1660
1691
|
Name => 'Year',
|
1692
|
+
Writable => 'undef',
|
1661
1693
|
Groups => { 2 => 'Time' },
|
1662
|
-
|
1694
|
+
Avoid => 1,
|
1695
|
+
Notes => 'used in 3gp videos',
|
1696
|
+
ValueConv => 'length($val) >= 6 ? unpack("x4n",$val) : "<err>"',
|
1697
|
+
ValueConvInv => 'pack("Nn",0,$val)',
|
1663
1698
|
},
|
1664
1699
|
urat => { #17
|
1665
1700
|
Name => 'UserRating',
|
1666
|
-
|
1701
|
+
Writable => 'undef',
|
1702
|
+
Notes => 'used in 3gp videos',
|
1703
|
+
Avoid => 1,
|
1704
|
+
ValueConv => q{
|
1667
1705
|
return '<err>' unless length $val >= 8;
|
1668
|
-
|
1706
|
+
unpack('x7C', $val);
|
1669
1707
|
},
|
1708
|
+
ValueConvInv => 'pack("N2",0,$val)',
|
1670
1709
|
},
|
1671
1710
|
# tsel - TrackSelection (ref 17)
|
1672
1711
|
# Apple tags (ref 16[dead] -- see ref 25 instead)
|
@@ -7611,7 +7650,11 @@ my %eeBox2 = (
|
|
7611
7650
|
8 => {
|
7612
7651
|
Name => 'HandlerType',
|
7613
7652
|
Format => 'undef[4]',
|
7614
|
-
RawConv =>
|
7653
|
+
RawConv => q{
|
7654
|
+
$$self{HandlerType} = $val unless $val eq 'alis' or $val eq 'url ';
|
7655
|
+
$$self{HasHandler}{$val} = 1; # remember all our handlers
|
7656
|
+
return $val;
|
7657
|
+
},
|
7615
7658
|
PrintConvColumns => 2,
|
7616
7659
|
PrintConv => {
|
7617
7660
|
alis => 'Alias Data', #PH
|
@@ -7716,7 +7759,7 @@ my %eeBox2 = (
|
|
7716
7759
|
$val =~ s/\0+$//; # remove trailing nulls
|
7717
7760
|
if (length $val and $$self{OPTIONS}{ExtractEmbedded}) {
|
7718
7761
|
my $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream');
|
7719
|
-
Image::ExifTool::QuickTime::
|
7762
|
+
Image::ExifTool::QuickTime::ProcessGPSLog($self, { DataPt => \$val }, $tagTbl);
|
7720
7763
|
}
|
7721
7764
|
return $val;
|
7722
7765
|
},
|
@@ -8949,6 +8992,7 @@ sub ProcessMOV($$;$)
|
|
8949
8992
|
if ($raf->Read($buff, $size-8) == $size-8) {
|
8950
8993
|
$raf->Seek(-($size-8), 1);
|
8951
8994
|
my $type = substr($buff, 0, 4);
|
8995
|
+
$$et{save_ftyp} = $type;
|
8952
8996
|
# see if we know the extension for this file type
|
8953
8997
|
if ($ftypLookup{$type} and $ftypLookup{$type} =~ /\(\.(\w+)/) {
|
8954
8998
|
$fileType = $1;
|
@@ -9372,9 +9416,9 @@ ItemID: foreach $id (keys %$items) {
|
|
9372
9416
|
}
|
9373
9417
|
for (;;) {
|
9374
9418
|
my ($len, $lang);
|
9375
|
-
if ($$tagInfo{IText} and $$tagInfo{IText}
|
9376
|
-
last if $pos +
|
9377
|
-
$pos +=
|
9419
|
+
if ($$tagInfo{IText} and $$tagInfo{IText} >= 6) {
|
9420
|
+
last if $pos + $$tagInfo{IText} > $size;
|
9421
|
+
$pos += $$tagInfo{IText} - 2;
|
9378
9422
|
$lang = unpack("x${pos}n", $val);
|
9379
9423
|
$pos += 2;
|
9380
9424
|
$len = $size - $pos;
|
@@ -9394,7 +9438,7 @@ ItemID: foreach $id (keys %$items) {
|
|
9394
9438
|
# ignore any empty entries (or null padding) after the first
|
9395
9439
|
next if not $len and $pos;
|
9396
9440
|
my $str = substr($val, $pos, $len);
|
9397
|
-
my $langInfo;
|
9441
|
+
my ($langInfo, $enc);
|
9398
9442
|
if (($lang < 0x400 or $lang == 0x7fff) and $str !~ /^\xfe\xff/) {
|
9399
9443
|
# this is a Macintosh language code
|
9400
9444
|
# a language code of 0 is Macintosh english, so treat as default
|
@@ -9411,15 +9455,22 @@ ItemID: foreach $id (keys %$items) {
|
|
9411
9455
|
}
|
9412
9456
|
# the spec says only "Macintosh text encoding", but
|
9413
9457
|
# allow this to be configured by the user
|
9414
|
-
$
|
9458
|
+
$enc = $charsetQuickTime;
|
9415
9459
|
} else {
|
9416
9460
|
# convert language code to ASCII (ignore read-only bit)
|
9417
9461
|
$lang = UnpackLang($lang);
|
9418
9462
|
# may be either UTF-8 or UTF-16BE
|
9419
|
-
|
9463
|
+
$enc = $str=~s/^\xfe\xff// ? 'UTF16' : 'UTF8';
|
9464
|
+
}
|
9465
|
+
unless ($$tagInfo{NoDecode}) {
|
9420
9466
|
$str = $et->Decode($str, $enc);
|
9467
|
+
$str =~ s/\0+$//; # remove any trailing nulls (eg. 3gp tags)
|
9468
|
+
}
|
9469
|
+
if ($$tagInfo{IText} and $$tagInfo{IText} > 6) {
|
9470
|
+
my $n = $$tagInfo{IText} - 6;
|
9471
|
+
# add back extra bytes (eg. 'rtng' box)
|
9472
|
+
$str = substr($val, $pos-$n-2, $n) . $str;
|
9421
9473
|
}
|
9422
|
-
$str =~ s/\0+$//; # remove any trailing nulls (eg. 3gp tags)
|
9423
9474
|
$langInfo = GetLangInfoQT($et, $tagInfo, $lang) if $lang;
|
9424
9475
|
$et->FoundTag($langInfo || $tagInfo, $str);
|
9425
9476
|
$pos += $len;
|
@@ -9469,6 +9520,13 @@ ItemID: foreach $id (keys %$items) {
|
|
9469
9520
|
($size, $tag) = unpack('Na4', $buff);
|
9470
9521
|
++$index if defined $index;
|
9471
9522
|
}
|
9523
|
+
# tweak file type based on track content ("iso*" ftyp only)
|
9524
|
+
if ($$et{VALUE}{FileType} and $$et{VALUE}{FileType} eq 'MP4' and
|
9525
|
+
$$et{save_ftyp} and $$et{HasHandler} and $$et{save_ftyp} =~ /^iso/ and
|
9526
|
+
$$et{HasHandler}{soun} and not $$et{HasHandler}{vide})
|
9527
|
+
{
|
9528
|
+
$et->OverrideFileType('M4A', 'audio/mp4');
|
9529
|
+
}
|
9472
9530
|
# fill in missing defaults for alternate language tags
|
9473
9531
|
# (the first language is taken as the default)
|
9474
9532
|
if ($doDefaultLang and $$et{QTLang}) {
|
@@ -140,6 +140,7 @@ my %insvLimit = (
|
|
140
140
|
SampleTime => { Groups => { 2 => 'Video' }, PrintConv => 'ConvertDuration($val)', Notes => 'sample decoding time' },
|
141
141
|
SampleDuration=>{ Groups => { 2 => 'Video' }, PrintConv => 'ConvertDuration($val)' },
|
142
142
|
UserLabel => { Groups => { 2 => 'Other' } },
|
143
|
+
KiloCalories => { Groups => { 2 => 'Other' } },
|
143
144
|
SampleDateTime => {
|
144
145
|
Groups => { 2 => 'Time' },
|
145
146
|
ValueConv => q{
|
@@ -2273,39 +2274,97 @@ sub ProcessNMEA($$$)
|
|
2273
2274
|
{
|
2274
2275
|
my ($et, $dirInfo, $tagTbl) = @_;
|
2275
2276
|
my $dataPt = $$dirInfo{DataPt};
|
2276
|
-
|
2277
|
-
|
2278
|
-
|
2279
|
-
my ($
|
2280
|
-
|
2281
|
-
|
2282
|
-
|
2283
|
-
|
2284
|
-
|
2285
|
-
|
2286
|
-
|
2287
|
-
|
2288
|
-
|
2289
|
-
|
2290
|
-
|
2291
|
-
|
2292
|
-
|
2293
|
-
|
2294
|
-
|
2295
|
-
|
2296
|
-
|
2297
|
-
|
2298
|
-
|
2299
|
-
|
2300
|
-
|
2277
|
+
my ($rtnVal, %fix);
|
2278
|
+
# parse only RMC and GGA sentence [with leading timecode] for now
|
2279
|
+
for (;;) {
|
2280
|
+
my ($tc, $type, $tim);
|
2281
|
+
if ($$dataPt =~ /(?:\[(\d+)\])?\$[A-Z]{2}(RMC|GGA),(\d{2}\d{2}\d+(\.\d*)?),/g) {
|
2282
|
+
($tc, $type, $tim) = ($1, $2, $3);
|
2283
|
+
}
|
2284
|
+
# write out last fix now if complete
|
2285
|
+
# (use the GPS timestamps because they may be different for the same timecode)
|
2286
|
+
if ($fix{tim} and (not $tim or $fix{tim} != $tim)) {
|
2287
|
+
if ($fix{dat} and defined $fix{lat} and defined $fix{lon}) {
|
2288
|
+
my $sampleTime;
|
2289
|
+
$sampleTime = ($fix{tc} - $$et{StartTime}) / 1000 if $fix{tc} and $$et{StartTime};
|
2290
|
+
FoundSomething($et, $tagTbl, $sampleTime);
|
2291
|
+
$et->HandleTag($tagTbl, GPSDateTime => $fix{dat});
|
2292
|
+
$et->HandleTag($tagTbl, GPSLatitude => $fix{lat});
|
2293
|
+
$et->HandleTag($tagTbl, GPSLongitude => $fix{lon});
|
2294
|
+
if (defined $fix{spd}) {
|
2295
|
+
$et->HandleTag($tagTbl, GPSSpeed => $fix{spd} * $knotsToKph);
|
2296
|
+
$et->HandleTag($tagTbl, GPSSpeedRef => 'K');
|
2297
|
+
}
|
2298
|
+
if (defined $fix{trk}) {
|
2299
|
+
$et->HandleTag($tagTbl, GPSTrack => $fix{trk});
|
2300
|
+
$et->HandleTag($tagTbl, GPSTrackRef => 'T');
|
2301
|
+
}
|
2302
|
+
$et->HandleTag($tagTbl, GPSAltitude => $fix{alt}) if defined $fix{alt};
|
2303
|
+
$et->HandleTag($tagTbl, GPSSatellites => $fix{nsats}+0) if defined $fix{nsats};
|
2304
|
+
$et->HandleTag($tagTbl, GPSDOP => $fix{hdop}) if defined $fix{hdop};
|
2305
|
+
}
|
2306
|
+
undef %fix;
|
2301
2307
|
}
|
2302
|
-
|
2303
|
-
|
2304
|
-
|
2308
|
+
$fix{tim} = $tim or last;
|
2309
|
+
my $pos = pos($$dataPt);
|
2310
|
+
pos($$dataPt) = $pos - length($tim) - 1; # rewind to re-parse time
|
2311
|
+
# (parsing of NMEA strings copied from Geotag.pm)
|
2312
|
+
if ($type eq 'RMC' and
|
2313
|
+
$$dataPt =~ /\G(\d{2})(\d{2})(\d+(\.\d*)?),A?,(\d*?)(\d{1,2}\.\d+),([NS]),(\d*?)(\d{1,2}\.\d+),([EW]),(\d*\.?\d*),(\d*\.?\d*),(\d{2})(\d{2})(\d+)/g)
|
2314
|
+
{
|
2315
|
+
my $year = $15 + ($15 >= 70 ? 1900 : 2000);
|
2316
|
+
$fix{tc} = $tc; # use timecode of RMC sentence
|
2317
|
+
$fix{dat} = sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%sZ',$year,$14,$13,$1,$2,$3);
|
2318
|
+
$fix{lat} = (($5 || 0) + $6/60) * ($7 eq 'N' ? 1 : -1);
|
2319
|
+
$fix{lon} = (($8 || 0) + $9/60) * ($10 eq 'E' ? 1 : -1);
|
2320
|
+
$fix{spd} = $11 if length $11;
|
2321
|
+
$fix{trk} = $12 if length $12;
|
2322
|
+
} elsif ($type eq 'GGA' and
|
2323
|
+
$$dataPt =~ /\G(\d{2})(\d{2})(\d+(\.\d*)?),(\d*?)(\d{1,2}\.\d+),([NS]),(\d*?)(\d{1,2}\.\d+),([EW]),[1-6]?,(\d+)?,(\.\d+|\d+\.?\d*)?,(-?\d+\.?\d*)?,M?/g)
|
2324
|
+
{
|
2325
|
+
$fix{lat} = (($5 || 0) + $6/60) * ($7 eq 'N' ? 1 : -1);
|
2326
|
+
$fix{lon} = (($8 || 0) + $9/60) * ($10 eq 'E' ? 1 : -1);
|
2327
|
+
@fix{qw(nsats hdop alt)} = ($11,$12,$13);
|
2328
|
+
} else {
|
2329
|
+
pos($$dataPt) = $pos; # continue searching from our last match
|
2305
2330
|
}
|
2306
2331
|
}
|
2307
2332
|
delete $$et{DOC_NUM};
|
2308
|
-
return
|
2333
|
+
return $rtnVal;
|
2334
|
+
}
|
2335
|
+
|
2336
|
+
#------------------------------------------------------------------------------
|
2337
|
+
# Process 'gps ' or 'udat' atom possibly containing NMEA (ref PH)
|
2338
|
+
# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
|
2339
|
+
# Returns: 1 on success
|
2340
|
+
sub ProcessGPSLog($$$)
|
2341
|
+
{
|
2342
|
+
my ($et, $dirInfo, $tagTbl) = @_;
|
2343
|
+
my $dataPt = $$dirInfo{DataPt};
|
2344
|
+
my ($rtnVal, @a);
|
2345
|
+
|
2346
|
+
# try NMEA format first
|
2347
|
+
return 1 if ProcessNMEA($et,$dirInfo,$tagTbl);
|
2348
|
+
|
2349
|
+
# DENVER ACG-8050WMK2 format looks like this:
|
2350
|
+
# 210318073213[1][N][52200970][E][006362321][+00152][100][00140][C000000]+000+000+000+000+000+000+000+000+000+000+000+000+000+000+000+000+000+000
|
2351
|
+
# YYMMDDHHMMSS A? NS lat EW lon alt kph dir kCal accel
|
2352
|
+
while ($$dataPt =~ /\b(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})\[1\]\[([NS])\]\[(\d{8})\]\[([EW])\]\[(\d{9})\]\[([-+]?\d*)\]\[(\d*)\]\[(\d*)\]\[C?(\d*)\](([-+]\d{3})+)/g) {
|
2353
|
+
my $lat = substr( $8,0,2) + substr( $8,2) / 600000;
|
2354
|
+
my $lon = substr($10,0,3) + substr($10,3) / 600000;
|
2355
|
+
$$et{DOC_NUM} = ++$$et{DOC_COUNT};
|
2356
|
+
$et->HandleTag($tagTbl, GPSDateTime => "20$1:$2:$3 $4:$5:$6Z");
|
2357
|
+
$et->HandleTag($tagTbl, GPSLatitude => $lat * ($7 eq 'S' ? -1 : 1));
|
2358
|
+
$et->HandleTag($tagTbl, GPSLongitude => $lon * ($9 eq 'W' ? -1 : 1));
|
2359
|
+
$et->HandleTag($tagTbl, GPSAltitude => $11 / 10) if length $11;
|
2360
|
+
$et->HandleTag($tagTbl, GPSSpeed => $12 + 0) if length $12;
|
2361
|
+
$et->HandleTag($tagTbl, GPSTrack => $13 + 0) if length $13;
|
2362
|
+
$et->HandleTag($tagTbl, KiloCalories => $14 / 10) if length $14;
|
2363
|
+
$et->HandleTag($tagTbl, Accelerometer=> $15) if length $15;
|
2364
|
+
$rtnVal = 1;
|
2365
|
+
}
|
2366
|
+
delete $$et{DOC_NUM};
|
2367
|
+
return $rtnVal;
|
2309
2368
|
}
|
2310
2369
|
|
2311
2370
|
#------------------------------------------------------------------------------
|