exiftool-vendored.exe 12.89.0 → 12.96.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.
- package/bin/exiftool_files/exiftool.pl +18 -2898
- package/bin/exiftool_files/lib/Image/ExifTool/Canon.pm +147 -9
- package/bin/exiftool_files/lib/Image/ExifTool/Font.pm +15 -4
- package/bin/exiftool_files/lib/Image/ExifTool/Geotag.pm +19 -5
- package/bin/exiftool_files/lib/Image/ExifTool/Jpeg2000.pm +2 -2
- package/bin/exiftool_files/lib/Image/ExifTool/Nikon.pm +35 -1
- package/bin/exiftool_files/lib/Image/ExifTool/NikonSettings.pm +56 -1
- package/bin/exiftool_files/lib/Image/ExifTool/OpenEXR.pm +3 -1
- package/bin/exiftool_files/lib/Image/ExifTool/PNG.pm +10 -2
- package/bin/exiftool_files/lib/Image/ExifTool/PostScript.pm +3 -12
- package/bin/exiftool_files/lib/Image/ExifTool/QuickTime.pm +40 -15
- package/bin/exiftool_files/lib/Image/ExifTool/QuickTimeStream.pl +203 -42
- package/bin/exiftool_files/lib/Image/ExifTool/Samsung.pm +31 -20
- package/bin/exiftool_files/lib/Image/ExifTool/TagLookup.pm +6923 -6903
- package/bin/exiftool_files/lib/Image/ExifTool/TagNames.pod +113 -10
- package/bin/exiftool_files/lib/Image/ExifTool/WriteQuickTime.pl +49 -17
- package/bin/exiftool_files/lib/Image/ExifTool/Writer.pl +8 -54
- package/bin/exiftool_files/lib/Image/ExifTool.pm +66 -4
- package/bin/exiftool_files/windows_exiftool.txt +2831 -0
- package/package.json +7 -7
|
@@ -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 = '
|
|
51
|
+
$VERSION = '3.02';
|
|
52
52
|
|
|
53
53
|
sub ProcessMOV($$;$);
|
|
54
54
|
sub ProcessKeys($$$);
|
|
@@ -6552,7 +6552,7 @@ my %userDefined = (
|
|
|
6552
6552
|
PROCESS_PROC => \&ProcessKeys,
|
|
6553
6553
|
WRITE_PROC => \&WriteKeys,
|
|
6554
6554
|
CHECK_PROC => \&CheckQTValue,
|
|
6555
|
-
VARS => { LONG_TAGS =>
|
|
6555
|
+
VARS => { LONG_TAGS => 8 },
|
|
6556
6556
|
WRITABLE => 1,
|
|
6557
6557
|
# (not PREFERRED when writing)
|
|
6558
6558
|
GROUPS => { 1 => 'Keys' },
|
|
@@ -6606,6 +6606,8 @@ my %userDefined = (
|
|
|
6606
6606
|
PrintConv => '$val * 1e6 . " microseconds"',
|
|
6607
6607
|
PrintConvInv => '$val =~ s/ .*//; $val * 1e-6',
|
|
6608
6608
|
},
|
|
6609
|
+
# 'camera.focal_length.35mm_equivalent' - not top level (written to Keys in video track)
|
|
6610
|
+
# 'camera.lens_model' - not top level (written to Keys in video track)
|
|
6609
6611
|
'location.ISO6709' => {
|
|
6610
6612
|
Name => 'GPSCoordinates',
|
|
6611
6613
|
Groups => { 2 => 'Location' },
|
|
@@ -6668,7 +6670,12 @@ my %userDefined = (
|
|
|
6668
6670
|
#
|
|
6669
6671
|
'com.apple.photos.captureMode' => 'CaptureMode',
|
|
6670
6672
|
'com.android.version' => 'AndroidVersion',
|
|
6671
|
-
'com.android.capture.fps' => 'AndroidCaptureFPS',
|
|
6673
|
+
'com.android.capture.fps' => { Name => 'AndroidCaptureFPS', Writable => 'float' },
|
|
6674
|
+
'com.android.manufacturer' => 'AndroidMake',
|
|
6675
|
+
'com.android.model' => 'AndroidModel',
|
|
6676
|
+
'com.xiaomi.preview_video_cover' => { Name => 'XiaomiPreviewVideoCover', Writable => 'int32s' },
|
|
6677
|
+
'xiaomi.exifInfo.videoinfo' => 'XiaomiExifInfo',
|
|
6678
|
+
'com.xiaomi.hdr10' => { Name => 'XiaomiHDR10', Writable => 'int32s' },
|
|
6672
6679
|
#
|
|
6673
6680
|
# also seen
|
|
6674
6681
|
#
|
|
@@ -9484,7 +9491,7 @@ sub ProcessKeys($$$)
|
|
|
9484
9491
|
$$newInfo{KeysID} = $tag; # save original ID for use in family 7 group name
|
|
9485
9492
|
AddTagToTable($itemList, $id, $newInfo);
|
|
9486
9493
|
$msg or $msg = '';
|
|
9487
|
-
$out and print $out "$$et{INDENT}Added ItemList Tag $id = ($ns) $
|
|
9494
|
+
$out and print $out "$$et{INDENT}Added ItemList Tag $id = ($ns) $full$msg\n";
|
|
9488
9495
|
}
|
|
9489
9496
|
$pos += $len;
|
|
9490
9497
|
++$index;
|
|
@@ -9521,7 +9528,7 @@ sub ProcessMOV($$;$)
|
|
|
9521
9528
|
my $dirID = $$dirInfo{DirID} || '';
|
|
9522
9529
|
my $charsetQuickTime = $et->Options('CharsetQuickTime');
|
|
9523
9530
|
my ($buff, $tag, $size, $track, $isUserData, %triplet, $doDefaultLang, $index);
|
|
9524
|
-
my ($dirEnd, $unkOpt, %saveOptions, $atomCount, $warnStr);
|
|
9531
|
+
my ($dirEnd, $unkOpt, %saveOptions, $atomCount, $warnStr, $trailer);
|
|
9525
9532
|
|
|
9526
9533
|
my $topLevel = not $$et{InQuickTime};
|
|
9527
9534
|
$$et{InQuickTime} = 1;
|
|
@@ -9550,6 +9557,17 @@ sub ProcessMOV($$;$)
|
|
|
9550
9557
|
$tagTablePtr = GetTagTable('Image::ExifTool::QuickTime::Main');
|
|
9551
9558
|
}
|
|
9552
9559
|
($size, $tag) = unpack('Na4', $buff);
|
|
9560
|
+
my $fast = $$et{OPTIONS}{FastScan} || 0;
|
|
9561
|
+
# check for Insta360 trailer
|
|
9562
|
+
if ($topLevel and not $fast) {
|
|
9563
|
+
my $pos = $raf->Tell();
|
|
9564
|
+
if ($raf->Seek(-40, 2) and $raf->Read($buff, 40) == 40 and
|
|
9565
|
+
substr($buff, 8) eq '8db42d694ccc418790edff439fe026bf')
|
|
9566
|
+
{
|
|
9567
|
+
$trailer = [ 'Insta360', $raf->Tell() - unpack('V',$buff) ];
|
|
9568
|
+
}
|
|
9569
|
+
$raf->Seek($pos,0) or return 0;
|
|
9570
|
+
}
|
|
9553
9571
|
if ($dataPt) {
|
|
9554
9572
|
$verbose and $et->VerboseDir($$dirInfo{DirName});
|
|
9555
9573
|
} else {
|
|
@@ -9588,7 +9606,6 @@ sub ProcessMOV($$;$)
|
|
|
9588
9606
|
# have XMP take priority except for HEIC
|
|
9589
9607
|
$$et{PRIORITY_DIR} = 'XMP' unless $fileType and $fileType eq 'HEIC';
|
|
9590
9608
|
}
|
|
9591
|
-
my $fast = $$et{OPTIONS}{FastScan} || 0;
|
|
9592
9609
|
$$raf{NoBuffer} = 1 if $fast; # disable buffering in FastScan mode
|
|
9593
9610
|
|
|
9594
9611
|
my $ee = $$et{OPTIONS}{ExtractEmbedded};
|
|
@@ -9737,7 +9754,7 @@ sub ProcessMOV($$;$)
|
|
|
9737
9754
|
if ($size > 0x2000000) { # start to get worried above 32 MiB
|
|
9738
9755
|
# check for RIFF trailer (written by Auto-Vox dashcam)
|
|
9739
9756
|
if ($buff =~ /^(gpsa|gps0|gsen|gsea)...\0/s) { # (yet seen only gpsa as first record)
|
|
9740
|
-
$et->VPrint(0, "Found RIFF trailer");
|
|
9757
|
+
$et->VPrint(0, sprintf("Found RIFF trailer at offset 0x%x",$lastPos));
|
|
9741
9758
|
if ($et->Options('ExtractEmbedded')) {
|
|
9742
9759
|
$raf->Seek(-8, 1) or last; # seek back to start of trailer
|
|
9743
9760
|
my $tbl = GetTagTable('Image::ExifTool::QuickTime::Stream');
|
|
@@ -9746,6 +9763,11 @@ sub ProcessMOV($$;$)
|
|
|
9746
9763
|
EEWarn($et);
|
|
9747
9764
|
}
|
|
9748
9765
|
last;
|
|
9766
|
+
} elsif ($buff eq 'CCCCCCCC') {
|
|
9767
|
+
$et->VPrint(0, sprintf("Found Kenwood trailer at offset 0x%x",$lastPos));
|
|
9768
|
+
my $tbl = GetTagTable('Image::ExifTool::QuickTime::Stream');
|
|
9769
|
+
ProcessKenwoodTrailer($et, { RAF => $raf }, $tbl);
|
|
9770
|
+
last;
|
|
9749
9771
|
}
|
|
9750
9772
|
$ignore = 1;
|
|
9751
9773
|
if ($tagInfo and not $$tagInfo{Unknown} and not $eeTag) {
|
|
@@ -10124,6 +10146,10 @@ ItemID: foreach $id (reverse sort { $a <=> $b } keys %$items) {
|
|
|
10124
10146
|
$dataPos += $size + 8; # point to start of next atom data
|
|
10125
10147
|
last if $dirEnd and $dataPos >= $dirEnd; # (note: ignores last value if 0 bytes)
|
|
10126
10148
|
$lastPos = $raf->Tell() + $dirBase;
|
|
10149
|
+
if ($trailer and $lastPos >= $$trailer[1]) {
|
|
10150
|
+
$et->Warn(sprintf('%s trailer at offset 0x%x', @$trailer), 1);
|
|
10151
|
+
last;
|
|
10152
|
+
}
|
|
10127
10153
|
$raf->Read($buff, 8) == 8 or last;
|
|
10128
10154
|
$lastTag = $tag if $$tagTablePtr{$tag} and $tag ne 'free'; # (Insta360 sometimes puts free block before trailer)
|
|
10129
10155
|
($size, $tag) = unpack('Na4', $buff);
|
|
@@ -10132,14 +10158,10 @@ ItemID: foreach $id (reverse sort { $a <=> $b } keys %$items) {
|
|
|
10132
10158
|
if ($warnStr) {
|
|
10133
10159
|
# assume this is an unknown trailer if it comes immediately after
|
|
10134
10160
|
# mdat or moov and has a tag name we don't recognize
|
|
10135
|
-
if (($lastTag eq 'mdat' or $lastTag eq 'moov') and
|
|
10136
|
-
ref $$tagTablePtr{$tag} eq 'HASH' and $$tagTablePtr{$tag}{Unknown}))
|
|
10161
|
+
if (($lastTag eq 'mdat' or $lastTag eq 'moov') and
|
|
10162
|
+
(not $$tagTablePtr{$tag} or ref $$tagTablePtr{$tag} eq 'HASH' and $$tagTablePtr{$tag}{Unknown}))
|
|
10137
10163
|
{
|
|
10138
|
-
|
|
10139
|
-
$et->Warn(sprintf('Insta360 trailer at offset 0x%x', $lastPos), 1);
|
|
10140
|
-
} else {
|
|
10141
|
-
$et->Warn('Unknown trailer with '.lcfirst($warnStr));
|
|
10142
|
-
}
|
|
10164
|
+
$et->Warn('Unknown trailer with '.lcfirst($warnStr));
|
|
10143
10165
|
} else {
|
|
10144
10166
|
$et->Warn($warnStr);
|
|
10145
10167
|
}
|
|
@@ -10166,7 +10188,10 @@ QTLang: foreach $tag (@{$$et{QTLang}}) {
|
|
|
10166
10188
|
for ($i=0, $key=$name; $$infoHash{$key}; ++$i, $key="$name ($i)") {
|
|
10167
10189
|
next QTLang if $et->GetGroup($key, 0) eq 'QuickTime';
|
|
10168
10190
|
}
|
|
10169
|
-
$et->FoundTag($tagInfo, $$et{VALUE}{$tag});
|
|
10191
|
+
$key = $et->FoundTag($tagInfo, $$et{VALUE}{$tag});
|
|
10192
|
+
# copy extra tag information (groups, etc) to the synthetic tag
|
|
10193
|
+
$$et{TAG_EXTRA}{$key} = $$et{TAG_EXTRA}{$tag};
|
|
10194
|
+
$et->VPrint(0, "(synthesized default-language tag for QuickTime:$$tagInfo{Name})");
|
|
10170
10195
|
}
|
|
10171
10196
|
delete $$et{QTLang};
|
|
10172
10197
|
}
|
|
@@ -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 77 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' },
|
|
@@ -757,6 +757,15 @@ my %insvLimit = (
|
|
|
757
757
|
10 => { Name => 'FusionYPR', Format => 'float[3]' },
|
|
758
758
|
);
|
|
759
759
|
|
|
760
|
+
#------------------------------------------------------------------------------
|
|
761
|
+
# Convert unsigned 32-bit integer to signed
|
|
762
|
+
# Inputs: <none> (uses value in $_)
|
|
763
|
+
# Returns: signed integer
|
|
764
|
+
sub SignedInt32()
|
|
765
|
+
{
|
|
766
|
+
return $_ < 0x80000000 ? $_ : $_ - 4294967296;
|
|
767
|
+
}
|
|
768
|
+
|
|
760
769
|
#------------------------------------------------------------------------------
|
|
761
770
|
# Save information from keys in OtherSampleDesc directory for processing timed metadata
|
|
762
771
|
# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
|
|
@@ -1420,9 +1429,10 @@ Sample: for ($i=0; ; ) {
|
|
|
1420
1429
|
} elsif ($type eq 'gps ') { # (ie. GPSDataList tag)
|
|
1421
1430
|
|
|
1422
1431
|
if ($buff =~ /^....freeGPS /s) {
|
|
1423
|
-
#
|
|
1424
|
-
# (some videos don't reference all freeGPS info from 'gps ' table, eg. INNOV
|
|
1425
|
-
|
|
1432
|
+
# parse freeGPS data unless done already in brute-force scan
|
|
1433
|
+
# (some videos don't reference all freeGPS info from 'gps ' table, eg. INNOV,
|
|
1434
|
+
# and some videos don't put 'gps ' data in mdat, eg XGODY 12" 4K Dashcam)
|
|
1435
|
+
last if $$et{FoundGPSByScan};
|
|
1426
1436
|
# decode "freeGPS " data (Novatek and others)
|
|
1427
1437
|
ProcessFreeGPS($et, {
|
|
1428
1438
|
DataPt => \$buff,
|
|
@@ -1473,6 +1483,31 @@ sub ConvertLatLon($$)
|
|
|
1473
1483
|
$_[1] = $deg + ($_[1] - $deg * 100) / 60;
|
|
1474
1484
|
}
|
|
1475
1485
|
|
|
1486
|
+
#------------------------------------------------------------------------------
|
|
1487
|
+
# Decrypt Lucky data
|
|
1488
|
+
# Inputs: 0) string to decrypt, 1) encryption key
|
|
1489
|
+
# Returns: decrypted string
|
|
1490
|
+
my @luckyKeys = ('luckychip gps', 'customer ## gps');
|
|
1491
|
+
sub DecryptLucky($$) {
|
|
1492
|
+
my ($str, $key) = @_;
|
|
1493
|
+
my @str = unpack('C*', $str);
|
|
1494
|
+
my @key = unpack('C*', $key);
|
|
1495
|
+
my @enc = (0..255);
|
|
1496
|
+
my ($i, $j, $k) = (0, 0, 0);
|
|
1497
|
+
do {
|
|
1498
|
+
$j = ($j + $enc[$i] + $key[$i % length($key)]) & 0xff;
|
|
1499
|
+
@enc[$i,$j] = @enc[$j,$i];
|
|
1500
|
+
} while (++$i < 256);
|
|
1501
|
+
($i, $j, $k) = (0, 0, 0);
|
|
1502
|
+
do {
|
|
1503
|
+
$j = ($j + 1) & 0xff;
|
|
1504
|
+
$k = ($k + $enc[$j]) & 0xff;
|
|
1505
|
+
@enc[$j,$k] = @enc[$k,$j];
|
|
1506
|
+
$str[$i] ^= $enc[($enc[$j] + $enc[$k]) & 0xff];
|
|
1507
|
+
} while (++$i < @str);
|
|
1508
|
+
return pack('C*', @str);
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1476
1511
|
#------------------------------------------------------------------------------
|
|
1477
1512
|
# Process "freeGPS " data blocks
|
|
1478
1513
|
# Inputs: 0) ExifTool ref, 1) dirInfo ref {DataPt,SampleTime,SampleDuration}, 2) tagTable ref
|
|
@@ -1588,40 +1623,87 @@ sub ProcessFreeGPS($$$)
|
|
|
1588
1623
|
}
|
|
1589
1624
|
if (defined $lat) {
|
|
1590
1625
|
# extract accelerometer readings if GPS was valid
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
map { $_ = $_ - 4294967296 if $_ >= 0x80000000; $_ /= 256 } @acc;
|
|
1626
|
+
# and change to signed integer and divide by 256
|
|
1627
|
+
@acc = map { SignedInt32 / 256 } unpack('x68V3', $$dataPt);
|
|
1594
1628
|
}
|
|
1595
1629
|
|
|
1596
|
-
} elsif ($$dataPt =~ /^.{37}\0\0\0A([NS])([EW])/s) {
|
|
1630
|
+
} elsif ($$dataPt =~ /^.{37}\0\0\0A([NS])([EW])\0/s) {
|
|
1597
1631
|
|
|
1598
|
-
$debug and $et->FoundTag(GPSType => 3);
|
|
1599
|
-
# decode freeGPS from ViofoA119v3 dashcam (similar to Novatek GPS format)
|
|
1600
|
-
# 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 03 00 00 [..@.freeGPS ....]
|
|
1601
|
-
# 0010: 05 00 00 00 2f 00 00 00 03 00 00 00 13 00 00 00 [..../...........]
|
|
1602
|
-
# 0020: 09 00 00 00 1b 00 00 00 41 4e 57 00 25 d1 99 45 [........ANW.%..E]
|
|
1603
|
-
# 0030: f1 47 40 46 66 66 d2 41 85 eb 83 41 00 00 00 00 [.G@Fff.A...A....]
|
|
1604
1632
|
($latRef, $lonRef) = ($1, $2);
|
|
1605
1633
|
($hr,$min,$sec,$yr,$mon,$day) = unpack('x16V6', $$dataPt);
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
$
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
}
|
|
1616
|
-
$
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1634
|
+
# test for base64-encoded and encrypted lucky gps strings
|
|
1635
|
+
my ($notEnc, $notStr, $lt, $ln);
|
|
1636
|
+
if (length($$dataPt) < 0x78) {
|
|
1637
|
+
$notEnc = $notStr = 1;
|
|
1638
|
+
} else {
|
|
1639
|
+
$lt = substr($$dataPt, 0x2c, 20), # latitude
|
|
1640
|
+
$ln = substr($$dataPt, 0x40, 20), # longitude
|
|
1641
|
+
/^[A-Za-z0-9+\/]{8,20}={0,2}\0*$/ or $notEnc = 1, last foreach ($lt, $ln);
|
|
1642
|
+
/^\d{1,5}\.\d+\0*$/ or $notStr = 1, last foreach ($lt, $ln);
|
|
1643
|
+
}
|
|
1644
|
+
if ($notEnc and $notStr) {
|
|
1645
|
+
|
|
1646
|
+
$debug and $et->FoundTag(GPSType => '3a');
|
|
1647
|
+
# decode freeGPS from ViofoA119v3 dashcam (similar to Novatek GPS format)
|
|
1648
|
+
# 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 03 00 00 [..@.freeGPS ....]
|
|
1649
|
+
# 0010: 05 00 00 00 2f 00 00 00 03 00 00 00 13 00 00 00 [..../...........]
|
|
1650
|
+
# 0020: 09 00 00 00 1b 00 00 00 41 4e 57 00 25 d1 99 45 [........ANW.%..E]
|
|
1651
|
+
# 0030: f1 47 40 46 66 66 d2 41 85 eb 83 41 00 00 00 00 [.G@Fff.A...A....]
|
|
1652
|
+
if ($yr >= 2000) {
|
|
1653
|
+
# Kenwood dashcam sometimes stores absolute year and local time
|
|
1654
|
+
# (but sometimes year since 2000 and UTC time in same video!)
|
|
1655
|
+
require Time::Local;
|
|
1656
|
+
my $time = Image::ExifTool::TimeLocal($sec,$min,$hr,$day,$mon-1,$yr);
|
|
1657
|
+
($sec,$min,$hr,$day,$mon,$yr) = gmtime($time);
|
|
1658
|
+
$yr += 1900;
|
|
1659
|
+
++$mon;
|
|
1660
|
+
$et->WarnOnce('Converting GPSDateTime to UTC based on local time zone',1);
|
|
1661
|
+
}
|
|
1662
|
+
$lat = GetFloat($dataPt, 0x2c);
|
|
1663
|
+
$lon = GetFloat($dataPt, 0x30);
|
|
1664
|
+
$spd = GetFloat($dataPt, 0x34) * $knotsToKph;
|
|
1665
|
+
$trk = GetFloat($dataPt, 0x38);
|
|
1666
|
+
# (may be all zeros or int16u counting from 1 to 6 if not valid)
|
|
1667
|
+
my $tmp = substr($$dataPt, 60, 12);
|
|
1668
|
+
if ($tmp ne "\0\0\0\0\0\0\0\0\0\0\0\0" and $tmp ne "\x01\0\x02\0\x03\0\x04\0\x05\0\x06\0") {
|
|
1669
|
+
@acc = map { SignedInt32 / 256 } unpack('V3', $tmp);
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
} else {
|
|
1673
|
+
|
|
1674
|
+
$debug and $et->FoundTag(GPSType => '3b');
|
|
1675
|
+
# decode freeGPS from E-ACE B44 dashcam
|
|
1676
|
+
# 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 03 00 00 [..@.freeGPS ....]
|
|
1677
|
+
# 0010: 08 00 00 00 22 00 00 00 01 00 00 00 18 00 00 00 [...."...........]
|
|
1678
|
+
# 0020: 08 00 00 00 10 00 00 00 41 4e 45 00 67 4e 69 69 [........ANE.gNii]
|
|
1679
|
+
# 0030: 5a 38 4a 54 74 48 63 61 36 74 77 3d 00 00 00 00 [Z8JTtHca6tw=....]
|
|
1680
|
+
# 0040: 68 74 75 69 5a 4d 4a 53 73 58 55 58 37 4e 6f 3d [htuiZMJSsXUX7No=]
|
|
1681
|
+
# 0050: 00 00 00 00 64 3b ac 41 e1 3a 1d 43 2b 01 00 00 [....d;.A.:.C+...]
|
|
1682
|
+
# 0060: fd ff ff ff 43 00 00 00 32 4a 37 31 50 70 55 48 [....C...2J71PpUH]
|
|
1683
|
+
# 0070: 37 69 68 66 00 00 00 00 00 00 00 00 00 00 00 00 [7ihf............]
|
|
1684
|
+
# (16-byte string at 0x68 is base64 encoded and encrypted 'luckychip' string)
|
|
1685
|
+
$spd = GetFloat($dataPt, 0x54) * $knotsToKph;
|
|
1686
|
+
$trk = GetFloat($dataPt, 0x58);
|
|
1687
|
+
@acc = map SignedInt32, unpack('x92V3', $$dataPt);
|
|
1688
|
+
# (accelerometer scaling is roughly 1G=250-300, but it varies depending on the axis,
|
|
1689
|
+
# so leave the values as raw. The axes are positive acceleration up,left,forward)
|
|
1690
|
+
if ($notEnc) { # (not encrypted)
|
|
1691
|
+
($lat = $lt) =~ s/\0+$//;
|
|
1692
|
+
($lon = $ln) =~ s/\0+$//;
|
|
1693
|
+
} else {
|
|
1694
|
+
# decode base64 strings
|
|
1695
|
+
require Image::ExifTool::XMP;
|
|
1696
|
+
$_ = ${Image::ExifTool::XMP::DecodeBase64($_)} foreach ($lt, $ln);
|
|
1697
|
+
# try various keys to decrypt lat/lon
|
|
1698
|
+
my ($i, $ch, $key) = (0, 'a', $luckyKeys[0]);
|
|
1699
|
+
for (; $i<20; ++$i) {
|
|
1700
|
+
$i and ($key = $luckyKeys[1]) =~ s/#/$ch/g, ++$ch;
|
|
1701
|
+
($lat = DecryptLucky($lt, $key)) =~ /^\d{1,4}\.\d+$/ or undef($lat), next;
|
|
1702
|
+
($lon = DecryptLucky($ln, $key)) =~ /^\d{1,5}\.\d+$/ or undef($lon), next;
|
|
1703
|
+
last;
|
|
1704
|
+
}
|
|
1705
|
+
$lon or $et->WarnOnce('Unknown encryption for latitude/longitude');
|
|
1706
|
+
}
|
|
1625
1707
|
}
|
|
1626
1708
|
|
|
1627
1709
|
} elsif ($$dataPt =~ /^.{21}\0\0\0A([NS])([EW])/s) {
|
|
@@ -1682,7 +1764,7 @@ sub ProcessFreeGPS($$$)
|
|
|
1682
1764
|
$trk -= 360 if $trk >= 360;
|
|
1683
1765
|
undef @acc;
|
|
1684
1766
|
} else {
|
|
1685
|
-
|
|
1767
|
+
@acc = map { SignedInt32 / 1000 } @acc; # (NC)
|
|
1686
1768
|
}
|
|
1687
1769
|
|
|
1688
1770
|
} elsif ($$dataPt =~ /^.{60}4W`b]S</s and length($$dataPt) >= 140) {
|
|
@@ -1786,7 +1868,7 @@ sub ProcessFreeGPS($$$)
|
|
|
1786
1868
|
return 0;
|
|
1787
1869
|
}
|
|
1788
1870
|
# (not sure about acc scaling)
|
|
1789
|
-
|
|
1871
|
+
@acc = map { SignedInt32 / 1000 } @acc;
|
|
1790
1872
|
$lon = GetFloat($dataPt, 0x5c);
|
|
1791
1873
|
$lat = GetFloat($dataPt, 0x60);
|
|
1792
1874
|
$spd = GetFloat($dataPt, 0x64) * $knotsToKph;
|
|
@@ -1931,7 +2013,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
|
1931
2013
|
# 0x7c - int32s[3] accelerometer * 1000
|
|
1932
2014
|
($latRef, $lonRef) = ($1, $2);
|
|
1933
2015
|
($hr,$min,$sec,$yr,$mon,$day,@acc) = unpack('x48V3x52V6', $$dataPt);
|
|
1934
|
-
|
|
2016
|
+
@acc = map { SignedInt32 / 1000 } @acc;
|
|
1935
2017
|
$lat = GetDouble($dataPt, 0x40);
|
|
1936
2018
|
$lon = GetDouble($dataPt, 0x50);
|
|
1937
2019
|
$spd = GetDouble($dataPt, 0x60) * $knotsToKph;
|
|
@@ -1947,8 +2029,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
|
1947
2029
|
$lon = abs(GetFloat(\$dat, 8)); # (abs just to be safe)
|
|
1948
2030
|
$spd = GetFloat(\$dat, 12) * $knotsToKph;
|
|
1949
2031
|
$trk = GetFloat(\$dat, 16);
|
|
1950
|
-
@acc = unpack('x20V3', $dat);
|
|
1951
|
-
map { $_ = $_ - 4294967296 if $_ >= 0x80000000 } @acc;
|
|
2032
|
+
@acc = map SignedInt32, unpack('x20V3', $dat);
|
|
1952
2033
|
ConvertLatLon($lat, $lon);
|
|
1953
2034
|
$$et{DOC_NUM} = ++$$et{DOC_COUNT};
|
|
1954
2035
|
$et->HandleTag($tagTbl, GPSLatitude => $lat * (substr($dat,1,1) eq 'S' ? -1 : 1));
|
|
@@ -1982,7 +2063,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
|
1982
2063
|
$lon = abs(GetDouble($dataPt, 48)); # (abs just to be safe)
|
|
1983
2064
|
$spd = GetDouble($dataPt, 64) * $knotsToKph;
|
|
1984
2065
|
$trk = GetDouble($dataPt, 72);
|
|
1985
|
-
|
|
2066
|
+
@acc = map { SignedInt32 / 1000 } @acc; # (NC)
|
|
1986
2067
|
# (not necessary to read RMC sentence because we already have it all)
|
|
1987
2068
|
|
|
1988
2069
|
} elsif ($$dataPt =~ /^.{72}A[NS][EW]\0/s) {
|
|
@@ -2049,9 +2130,41 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
|
2049
2130
|
}
|
|
2050
2131
|
}
|
|
2051
2132
|
|
|
2052
|
-
}
|
|
2133
|
+
} elsif ($$dataPt =~ m<^.{23}(\d{4})/(\d{2})/(\d{2}) (\d{2}):(\d{2}):(\d{2}) [N|S]>s) {
|
|
2053
2134
|
|
|
2054
2135
|
$debug and $et->FoundTag(GPSType => 16);
|
|
2136
|
+
# XGODY 12" 4K Dashcam
|
|
2137
|
+
# 0000: 00 00 00 a8 66 72 65 65 47 50 53 20 98 00 00 00 [....freeGPS ....]
|
|
2138
|
+
# 0010: 6e 6f 72 6d 61 6c 3a 32 30 32 34 2f 30 35 2f 32 [normal:2024/05/2]
|
|
2139
|
+
# 0020: 32 20 30 32 3a 35 34 3a 32 39 20 4e 3a 34 32 2e [2 02:54:29 N:42.]
|
|
2140
|
+
# 0030: 33 38 32 34 37 30 20 57 3a 38 33 2e 33 38 39 35 [382470 W:83.3895]
|
|
2141
|
+
# 0040: 37 30 20 35 33 2e 36 20 6b 6d 2f 68 20 78 3a 2d [70 53.6 km/h x:-]
|
|
2142
|
+
# 0050: 30 2e 30 32 20 79 3a 30 2e 39 39 20 7a 3a 30 2e [0.02 y:0.99 z:0.]
|
|
2143
|
+
# 0060: 31 30 20 41 3a 32 36 39 2e 32 20 48 3a 32 34 35 [10 A:269.2 H:245]
|
|
2144
|
+
# 0070: 2e 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [.5..............]
|
|
2145
|
+
($yr,$mon,$day,$hr,$min,$sec) = ($1,$2,$3,$4,$5,$6);
|
|
2146
|
+
$$dataPt =~ s/\0+$//; # remove trailing nulls
|
|
2147
|
+
my @a = split ' ', substr($$dataPt,43);
|
|
2148
|
+
$ddd = 1;
|
|
2149
|
+
foreach (@a) {
|
|
2150
|
+
unless (/^([A-Z]):([-+]?\d+(\.\d+)?)$/i) {
|
|
2151
|
+
# (the "km/h" after spd is display units? because the value is stored in knots)
|
|
2152
|
+
defined $lon and not defined $spd and /^\d+\.\d+$/ and $spd = $_ * $knotsToKph;
|
|
2153
|
+
next;
|
|
2154
|
+
}
|
|
2155
|
+
($1 eq 'N' or $1 eq 'S') and $lat = $2, $latRef = $1, next;
|
|
2156
|
+
($1 eq 'E' or $1 eq 'W') and $lon = $2, $lonRef = $1, next;
|
|
2157
|
+
($1 eq 'x' or $1 eq 'y' or $1 eq 'z') and push(@acc,$2), next;
|
|
2158
|
+
$1 eq 'A' and $trk = $2, next; # (verified, but why 'A'?)
|
|
2159
|
+
# seen 'H' - one might expect altitude ('H'eight), but it doesn't fit
|
|
2160
|
+
# the sample data, so save all other information as an "Unknown_X" tag
|
|
2161
|
+
$$tagTbl{$1} or AddTagToTable($tagTbl, $1, { Name => "Unknown_$1", Unknown => 1 });
|
|
2162
|
+
push(@xtra, $1 => $2), next;
|
|
2163
|
+
}
|
|
2164
|
+
|
|
2165
|
+
} else {
|
|
2166
|
+
|
|
2167
|
+
$debug and $et->FoundTag(GPSType => 17);
|
|
2055
2168
|
# (look for binary GPS as stored by Nextbase 512G, ref PH)
|
|
2056
2169
|
# 0000: 00 00 80 00 66 72 65 65 47 50 53 20 78 01 00 00 [....freeGPS x...]
|
|
2057
2170
|
# 0010: 78 2e 78 78 00 00 00 00 00 00 00 00 00 00 00 00 [x.xx............]
|
|
@@ -2084,7 +2197,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
|
2084
2197
|
$day < 1 or $day > 31 or
|
|
2085
2198
|
$hr > 59 or $min > 59 or $sec > 600;
|
|
2086
2199
|
# change lat/lon to signed integer and divide by 1e7
|
|
2087
|
-
|
|
2200
|
+
($lat, $lon) = map { SignedInt32 / 1e7 } $lat, $lon;
|
|
2088
2201
|
$trk -= 0x10000 if $trk >= 0x8000; # make it signed
|
|
2089
2202
|
$trk /= 100;
|
|
2090
2203
|
$trk += 360 if $trk < 0;
|
|
@@ -2115,7 +2228,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
|
2115
2228
|
my $time = sprintf('%.2d:%.2d:%sZ',$hr,$min,$sec);
|
|
2116
2229
|
$et->HandleTag($tagTbl, GPSTimeStamp => $time);
|
|
2117
2230
|
}
|
|
2118
|
-
if (defined $lat) {
|
|
2231
|
+
if (defined $lat and defined $lon) {
|
|
2119
2232
|
# lat/long are in DDDMM.MMMM format unless $ddd is set
|
|
2120
2233
|
ConvertLatLon($lat, $lon) unless $ddd;
|
|
2121
2234
|
$et->HandleTag($tagTbl, GPSLatitude => $lat * ($latRef eq 'S' ? -1 : 1));
|
|
@@ -2680,6 +2793,53 @@ sub ProcessRIFFTrailer($$$)
|
|
|
2680
2793
|
return 1;
|
|
2681
2794
|
}
|
|
2682
2795
|
|
|
2796
|
+
#------------------------------------------------------------------------------
|
|
2797
|
+
# Process Kenwood Dashcam trailer (forum16229)
|
|
2798
|
+
# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
|
|
2799
|
+
# Returns: 1 on success
|
|
2800
|
+
# Sample data (chained 512-byte records starting like this):
|
|
2801
|
+
# 0000: 43 43 43 43 43 43 43 43 43 43 43 43 43 43 47 50 [CCCCCCCCCCCCCCGP]
|
|
2802
|
+
# 0010: 53 44 41 54 41 2d 2d 32 30 32 34 30 37 31 31 31 [SDATA--202407111]
|
|
2803
|
+
# 0020: 32 30 34 31 32 4e 35 30 2e 36 31 32 33 38 36 30 [20412N50.6123860]
|
|
2804
|
+
# 0030: 36 37 37 45 38 2e 37 30 32 37 31 38 30 39 38 39 [677E8.7027180989]
|
|
2805
|
+
# 0040: 35 33 33 2e 30 30 30 30 30 30 30 30 30 30 30 30 [533.000000000000]
|
|
2806
|
+
# 0050: 2e 30 30 30 30 30 30 30 30 30 30 30 30 30 2e 30 [.0000000000000.0]
|
|
2807
|
+
# 0060: 31 39 39 39 39 39 39 39 35 35 33 2d 30 2e 30 39 [19999999553-0.09]
|
|
2808
|
+
# 0070: 30 30 30 30 30 30 33 35 37 2d 30 2e 31 34 30 30 [000000357-0.1400]
|
|
2809
|
+
# 0080: 30 30 30 30 30 35 39 47 50 53 44 41 54 41 2d 2d [0000059GPSDATA--]
|
|
2810
|
+
sub ProcessKenwoodTrailer($$$)
|
|
2811
|
+
{
|
|
2812
|
+
my ($et, $dirInfo, $tagTbl) = @_;
|
|
2813
|
+
my $raf = $$dirInfo{RAF};
|
|
2814
|
+
my $buff;
|
|
2815
|
+
# current file position is 8 bytes into the 14 C's, so test the next 6:
|
|
2816
|
+
$raf->Read($buff, 14) and $buff eq 'CCCCCCCCCCCCCC' or return 0;
|
|
2817
|
+
$et->VerboseDir('Kenwood trailer', undef, undef);
|
|
2818
|
+
unless ($$et{OPTIONS}{ExtractEmbedded}) {
|
|
2819
|
+
$et->WarnOnce('Use the ExtractEmbedded option to extract timed GPSData from Kenwood trailer',3);
|
|
2820
|
+
return 1;
|
|
2821
|
+
}
|
|
2822
|
+
while ($raf->Read($buff, 121) and $buff =~ /^GPSDATA--(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/) {
|
|
2823
|
+
FoundSomething($et, $tagTbl);
|
|
2824
|
+
$et->HandleTag($tagTbl, GPSDateTime => "$1:$2:$3 $4:$5:$6");
|
|
2825
|
+
my $i = 9 + 14;
|
|
2826
|
+
my ($val, @acc, $tag);
|
|
2827
|
+
foreach $tag (qw(GPSLatitude GPSLongitude GPSSpeed unk acc acc acc)) {
|
|
2828
|
+
$val = substr($buff, $i, 14); $i += 14;
|
|
2829
|
+
next if $tag eq 'unk';
|
|
2830
|
+
my $hemi;
|
|
2831
|
+
$hemi = $1 if $val =~ s/^([NSEW])//;
|
|
2832
|
+
$val =~ /^[-+]?\d+\.\d+$/ or next;
|
|
2833
|
+
$tag eq 'acc' and push(@acc,$val), next;
|
|
2834
|
+
$val = -$val if $hemi and ($hemi eq 'S' or $hemi eq 'W');
|
|
2835
|
+
$et->HandleTag($tagTbl, $tag => $val);
|
|
2836
|
+
}
|
|
2837
|
+
$et->HandleTag($tagTbl, Accelerometer => "@acc") if @acc == 3;
|
|
2838
|
+
}
|
|
2839
|
+
delete $$et{DOC_NUM};
|
|
2840
|
+
return 1;
|
|
2841
|
+
}
|
|
2842
|
+
|
|
2683
2843
|
#------------------------------------------------------------------------------
|
|
2684
2844
|
# Process 'gps ' atom containing NMEA from Pittasoft Blackvue dashcam (ref PH)
|
|
2685
2845
|
# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
|
|
@@ -3353,6 +3513,7 @@ sub ScanMediaData($)
|
|
|
3353
3513
|
}
|
|
3354
3514
|
my $dirInfo = { DataPt => \$buff, DataPos => $pos + $dataPos, DirLen => $len };
|
|
3355
3515
|
ProcessFreeGPS($et, $dirInfo, $tagTbl);
|
|
3516
|
+
$$et{FoundGPSByScan} = 1;
|
|
3356
3517
|
}
|
|
3357
3518
|
$pos += $len;
|
|
3358
3519
|
$buf2 = substr($buff, $len);
|
|
@@ -22,13 +22,13 @@ use vars qw($VERSION %samsungLensTypes);
|
|
|
22
22
|
use Image::ExifTool qw(:DataAccess :Utils);
|
|
23
23
|
use Image::ExifTool::Exif;
|
|
24
24
|
|
|
25
|
-
$VERSION = '1.
|
|
25
|
+
$VERSION = '1.58';
|
|
26
26
|
|
|
27
27
|
sub WriteSTMN($$$);
|
|
28
28
|
sub ProcessINFO($$$);
|
|
29
29
|
sub ProcessSamsungMeta($$$);
|
|
30
30
|
sub ProcessSamsungIFD($$$);
|
|
31
|
-
sub ProcessSamsung(
|
|
31
|
+
sub ProcessSamsung($$;$);
|
|
32
32
|
|
|
33
33
|
# Samsung LensType lookup
|
|
34
34
|
%samsungLensTypes = (
|
|
@@ -943,25 +943,25 @@ my %formatMinMax = (
|
|
|
943
943
|
);
|
|
944
944
|
|
|
945
945
|
# information extracted from Samsung trailer (ie. Samsung SM-T805 "Sound & Shot" JPEG) (ref PH)
|
|
946
|
+
# NOTE: These tags may use $$self{SamsungTagName} in a Condition statement
|
|
947
|
+
# if necessary to differentiate tags with the same ID but different names
|
|
946
948
|
%Image::ExifTool::Samsung::Trailer = (
|
|
947
949
|
GROUPS => { 0 => 'MakerNotes', 2 => 'Other' },
|
|
948
950
|
VARS => { NO_ID => 1, HEX_ID => 0 },
|
|
949
951
|
PROCESS_PROC => \&ProcessSamsung,
|
|
952
|
+
TAG_PREFIX => 'SamsungTrailer',
|
|
950
953
|
PRIORITY => 0, # (first one takes priority so DepthMapWidth/Height match first DepthMapData)
|
|
951
954
|
NOTES => q{
|
|
952
|
-
Tags extracted from the trailer of JPEG images written when
|
|
953
|
-
features (such as "Sound & Shot" or "Shot & More") from
|
|
954
|
-
as the Galaxy S4 and Tab S, and from the 'sefd' atom in
|
|
955
|
-
|
|
956
|
-
},
|
|
957
|
-
'0x0001-name' => {
|
|
958
|
-
Name => 'EmbeddedImageName', # ("DualShot_1","DualShot_2")
|
|
959
|
-
RawConv => '$$self{EmbeddedImageName} = $val',
|
|
955
|
+
Tags extracted from the SEFT trailer of JPEG and PNG images written when
|
|
956
|
+
using certain features (such as "Sound & Shot" or "Shot & More") from
|
|
957
|
+
Samsung models such as the Galaxy S4 and Tab S, and from the 'sefd' atom in
|
|
958
|
+
HEIC images from models such as the S10+.
|
|
960
959
|
},
|
|
960
|
+
'0x0001-name' => 'EmbeddedImageName', # ("DualShot_1","DualShot_2","SingleShot")
|
|
961
961
|
'0x0001' => [
|
|
962
962
|
{
|
|
963
963
|
Name => 'EmbeddedImage',
|
|
964
|
-
Condition => '$$self{
|
|
964
|
+
Condition => '$$self{SamsungTagName} ne "DualShot_2"',
|
|
965
965
|
Groups => { 2 => 'Preview' },
|
|
966
966
|
Binary => 1,
|
|
967
967
|
},
|
|
@@ -970,6 +970,7 @@ my %formatMinMax = (
|
|
|
970
970
|
Groups => { 2 => 'Preview' },
|
|
971
971
|
Binary => 1,
|
|
972
972
|
},
|
|
973
|
+
# (have also seen the string "BOKEH" here (SM-A226B)
|
|
973
974
|
],
|
|
974
975
|
'0x0100-name' => 'EmbeddedAudioFileName', # ("SoundShot_000")
|
|
975
976
|
'0x0100' => { Name => 'EmbeddedAudioFile', Groups => { 2 => 'Audio' }, Binary => 1 },
|
|
@@ -1265,6 +1266,7 @@ my %formatMinMax = (
|
|
|
1265
1266
|
'0x0b40' => { # (SM-N975X front camera)
|
|
1266
1267
|
Name => 'SingleShotMeta',
|
|
1267
1268
|
SubDirectory => { TagTable => 'Image::ExifTool::Samsung::SingleShotMeta' },
|
|
1269
|
+
# (have also see the string "BOKEH_INFO" here (SM-A226B)
|
|
1268
1270
|
},
|
|
1269
1271
|
# 0x0b41-name - seen 'SingeShot_DepthMap_1' (Yes, "Singe") (SM-N975X front camera)
|
|
1270
1272
|
'0x0b41' => { Name => 'SingleShotDepthMap', Binary => 1 },
|
|
@@ -1277,8 +1279,10 @@ my %formatMinMax = (
|
|
|
1277
1279
|
# 0x0bd0-name - seen 'Dual_Relighting_Bokeh_Info' #forum16086
|
|
1278
1280
|
# 0x0be0-name - seen 'Livefocus_JDM_Info' #forum16086
|
|
1279
1281
|
# 0x0bf0-name - seen 'Remaster_Info' #forum16086
|
|
1282
|
+
'0x0bf0' => 'RemasterInfo', #forum16086/16242
|
|
1280
1283
|
# 0x0c21-name - seen 'Portrait_Effect_Info' #forum16086
|
|
1281
1284
|
# 0x0c51-name - seen 'Samsung_Capture_Info' #forum16086
|
|
1285
|
+
'0x0c51' => 'SamsungCaptureInfo', #forum16086/16242
|
|
1282
1286
|
# 0x0c61-name - seen 'Camera_Capture_Mode_Info' #forum16086
|
|
1283
1287
|
# 0x0c71-name - seen 'Pro_White_Balance_Info' #forum16086
|
|
1284
1288
|
# 0x0c81-name - seen 'Watermark_Info' #forum16086
|
|
@@ -1289,7 +1293,11 @@ my %formatMinMax = (
|
|
|
1289
1293
|
# 0x0d11-name - seen 'Video_Snapshot_Info' #forum16086
|
|
1290
1294
|
# 0x0d21-name - seen 'Camera_Scene_Info' #forum16086
|
|
1291
1295
|
# 0x0d31-name - seen 'Food_Blur_Effect_Info' #forum16086
|
|
1292
|
-
|
|
1296
|
+
'0x0d91' => { #forum16086/16242
|
|
1297
|
+
Name => 'PEg_Info',
|
|
1298
|
+
Description => 'PEg Info',
|
|
1299
|
+
SubDirectory => { TagTable => 'Image::ExifTool::JSON::Main' },
|
|
1300
|
+
},
|
|
1293
1301
|
# 0x0da1-name - seen 'Captured_App_Info' #forum16086
|
|
1294
1302
|
# 0xa050-name - seen 'Jpeg360_2D_Info' (Samsung Gear 360)
|
|
1295
1303
|
# 0xa050 - seen 'Jpeg3602D' (Samsung Gear 360)
|
|
@@ -1487,7 +1495,7 @@ sub ProcessSamsungMeta($$$)
|
|
|
1487
1495
|
my $pos = $$dirInfo{DirStart};
|
|
1488
1496
|
my $end = $$dirInfo{DirLen} + $pos;
|
|
1489
1497
|
unless ($pos + 8 <= $end and substr($$dataPt, $pos, 4) eq 'DOFS') {
|
|
1490
|
-
$et->Warn("Unrecognized $dirName data");
|
|
1498
|
+
$et->Warn("Unrecognized $dirName data", 1);
|
|
1491
1499
|
return 0;
|
|
1492
1500
|
}
|
|
1493
1501
|
my $ver = Get32u($dataPt, $pos + 4);
|
|
@@ -1563,7 +1571,7 @@ sub ProcessSamsungIFD($$$)
|
|
|
1563
1571
|
# Returns: 1 on success, 0 not valid Samsung trailer, or -1 error writing
|
|
1564
1572
|
# - updates DataPos to point to start of Samsung trailer
|
|
1565
1573
|
# - updates DirLen to existing trailer length
|
|
1566
|
-
sub ProcessSamsung(
|
|
1574
|
+
sub ProcessSamsung($$;$)
|
|
1567
1575
|
{
|
|
1568
1576
|
my ($et, $dirInfo) = @_;
|
|
1569
1577
|
my $raf = $$dirInfo{RAF};
|
|
@@ -1653,8 +1661,13 @@ SamBlock:
|
|
|
1653
1661
|
$audioSize = $size - 8 - $len;
|
|
1654
1662
|
next;
|
|
1655
1663
|
}
|
|
1656
|
-
|
|
1664
|
+
last unless $raf->Seek($dirPos-$noff, 0) and $raf->Read($buf2, $size) == $size;
|
|
1665
|
+
# (could validate the first 4 bytes of the block because they
|
|
1666
|
+
# are the same as the first 4 bytes of the directory entry)
|
|
1667
|
+
$len = Get32u(\$buf2, 4);
|
|
1668
|
+
last if $len + 8 > $size;
|
|
1657
1669
|
my $tag = sprintf("0x%.4x", $type);
|
|
1670
|
+
# add unknown tags if necessary
|
|
1658
1671
|
unless ($$tagTablePtr{$tag}) {
|
|
1659
1672
|
next unless $unknown or $verbose;
|
|
1660
1673
|
my %tagInfo = (
|
|
@@ -1673,11 +1686,8 @@ SamBlock:
|
|
|
1673
1686
|
);
|
|
1674
1687
|
AddTagToTable($tagTablePtr, "$tag-name", \%tagInfo2);
|
|
1675
1688
|
}
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
# are the same as the first 4 bytes of the directory entry)
|
|
1679
|
-
$len = Get32u(\$buf2, 4);
|
|
1680
|
-
last if $len + 8 > $size;
|
|
1689
|
+
# set SamsungTagName ExifTool member for use in tag Condition
|
|
1690
|
+
$$et{SamsungTagName} = substr($buf2, 8, $len);
|
|
1681
1691
|
# extract tag name and value
|
|
1682
1692
|
$et->HandleTag($tagTablePtr, "$tag-name", undef,
|
|
1683
1693
|
DataPt => \$buf2,
|
|
@@ -1691,6 +1701,7 @@ SamBlock:
|
|
|
1691
1701
|
Start => 8 + $len,
|
|
1692
1702
|
Size => $size - (8 + $len),
|
|
1693
1703
|
);
|
|
1704
|
+
delete $$et{SamsungTagName};
|
|
1694
1705
|
}
|
|
1695
1706
|
if ($outfile) {
|
|
1696
1707
|
last unless $raf->Seek($dataPos, 0) and $raf->Read($buff, $dirLen) == $dirLen;
|