exiftool_vendored 11.44.0 → 11.47.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of exiftool_vendored might be problematic. Click here for more details.

@@ -16,7 +16,7 @@ use strict;
16
16
  use vars qw($VERSION);
17
17
  use Image::ExifTool qw(:DataAccess :Utils);
18
18
 
19
- $VERSION = '1.51';
19
+ $VERSION = '1.52';
20
20
 
21
21
  sub ProcessID3v2($$$);
22
22
  sub ProcessPrivate($$$);
@@ -964,7 +964,7 @@ sub PrintGenre($)
964
964
  $genre{$1} or $genre{$1} = "Unknown ($1)";
965
965
  }
966
966
  $val =~ s/\((\d+)\)/\($genre{$1}\)/g;
967
- $val =~ s/(^|\/)(\d+)(?=\/|$)/$1$genre{$2}$3/g;
967
+ $val =~ s/(^|\/)(\d+)(?=\/|$)/$1$genre{$2}/g;
968
968
  $val =~ s/^\(([^)]+)\)\1?$/$1/; # clean up by removing brackets and duplicates
969
969
  return $val;
970
970
  }
@@ -59,7 +59,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
59
59
  use Image::ExifTool::Exif;
60
60
  use Image::ExifTool::GPS;
61
61
 
62
- $VERSION = '3.63';
62
+ $VERSION = '3.64';
63
63
 
64
64
  sub LensIDConv($$$);
65
65
  sub ProcessNikonAVI($$$);
@@ -653,6 +653,7 @@ sub GetAFPointGrid($$;$);
653
653
  '00 54 72 72 18 18 00 00' => 'Carl Zeiss Apo Sonnar T* 2/135 ZF.2',
654
654
  '00 54 53 53 0C 0C 00 00' => 'Zeiss Otus 1.4/55', #IB
655
655
  '01 54 62 62 0C 0C 00 00' => 'Zeiss Otus 1.4/85',
656
+ '03 54 68 68 0C 0C 00 00' => 'Zeiss Otus 1.4/100', #IB
656
657
  '52 54 44 44 18 18 00 00' => 'Zeiss Milvus 35mm f/2',
657
658
  '53 54 50 50 0C 0C 00 00' => 'Zeiss Milvus 50mm f/1.4', #IB
658
659
  '54 54 50 50 18 18 00 00' => 'Zeiss Milvus 50mm f/2 Macro',
@@ -1874,7 +1875,7 @@ my %binaryDataAttrs = (
1874
1875
  DirOffset => 10,
1875
1876
  },
1876
1877
  },
1877
- { # (D3100=0215,D7000/D5100=0216,D4/D800/D3200=0217)
1878
+ { # (D3100=0215,D7000/D5100=0216,D4/D600/D800/D800E/D3200=0217)
1878
1879
  Condition => '$$valPt =~ /^021[567]/',
1879
1880
  Name => 'ColorBalance0215',
1880
1881
  SubDirectory => {
@@ -39,7 +39,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
39
39
  use Image::ExifTool::Exif;
40
40
  use Image::ExifTool::APP12;
41
41
 
42
- $VERSION = '2.58';
42
+ $VERSION = '2.59';
43
43
 
44
44
  sub PrintLensInfo($$$);
45
45
 
@@ -364,6 +364,7 @@ my %olympusCameraTypes = (
364
364
  D4587 => 'TG-860',
365
365
  D4591 => 'TG-870',
366
366
  D4593 => 'TG-5', #IB
367
+ D4603 => 'TG-6', #IB
367
368
  D4809 => 'C2500L',
368
369
  D4842 => 'E-10',
369
370
  D4856 => 'C-1',
@@ -304,7 +304,7 @@ sub DecodeAFPoints($$$$;$);
304
304
  '7 243' => 'smc PENTAX-DA 70mm F2.4 Limited', #PH
305
305
  '7 244' => 'smc PENTAX-DA 21mm F3.2 AL Limited', #16
306
306
  '8 0' => 'Sigma 50-150mm F2.8 II APO EX DC HSM', #forum2997
307
- '8 3' => 'Sigma AF 18-125mm F3.5-5.6 DC', #29
307
+ '8 3' => 'Sigma AF 18-125mm F3.5-5.6 DC', #29 (and F3.8-5.6, ref forum10167)
308
308
  '8 4' => 'Sigma 50mm F1.4 EX DG HSM', #Artur private communication
309
309
  '8 7' => 'Sigma 24-70mm F2.8 IF EX DG HSM', #Exiv2
310
310
  '8 8' => 'Sigma 18-250mm F3.5-6.3 DC OS HSM', #27
@@ -42,7 +42,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
42
42
  use Image::ExifTool::Exif;
43
43
  use Image::ExifTool::GPS;
44
44
 
45
- $VERSION = '2.28';
45
+ $VERSION = '2.30';
46
46
 
47
47
  sub ProcessMOV($$;$);
48
48
  sub ProcessKeys($$$);
@@ -74,6 +74,7 @@ sub PrintChapter($);
74
74
  sub PrintGPSCoordinates($);
75
75
  sub PrintInvGPSCoordinates($);
76
76
  sub UnpackLang($;$);
77
+ sub WriteKeys($$$);
77
78
  sub WriteQuickTime($$$);
78
79
  sub WriteMOV($$);
79
80
  sub GetLangInfo($$);
@@ -210,7 +211,9 @@ my %timeInfo = (
210
211
  RawConv => q{
211
212
  my $offset = (66 * 365 + 17) * 24 * 3600;
212
213
  return $val - $offset if $val >= $offset or $$self{OPTIONS}{QuickTimeUTC};
213
- $self->WarnOnce('Patched incorrect time zero for QuickTime date/time tag',1) if $val;
214
+ if ($val and not $$self{IsWriting}) {
215
+ $self->WarnOnce('Patched incorrect time zero for QuickTime date/time tag',1);
216
+ }
214
217
  return $val;
215
218
  },
216
219
  Shift => 'Time',
@@ -382,6 +385,12 @@ my %dontInherit = (
382
385
  ispe => 1, # size of parent may be different
383
386
  );
384
387
 
388
+ # tags that may be duplicated and directories that may contain duplicate tags
389
+ # (used only to avoid warnings when Validate-ing)
390
+ my %dupTagOK = ( mdat => 1, trak => 1, free => 1, infe => 1, sgpd => 1, dimg => 1, CCDT => 1,
391
+ sbgp => 1, csgm => 1, uuid => 1, cdsc => 1, maxr => 1, '----' => 1 );
392
+ my %dupDirOK = ( ipco => 1, '----' => 1 );
393
+
385
394
  # the usual atoms required to decode timed metadata with the ExtractEmbedded option
386
395
  my %eeStd = ( stco => 'stbl', co64 => 'stbl', stsz => 'stbl', stz2 => 'stbl',
387
396
  stsc => 'stbl', stts => 'stbl' );
@@ -412,22 +421,29 @@ my %eeBox = (
412
421
  NOTES => q{
413
422
  The QuickTime format is used for many different types of audio, video and
414
423
  image files (most notably, MOV/MP4 videos and HEIC/CR3 images). Exiftool
415
- extracts standard meta information a variety of audio, video and image
424
+ extracts standard meta information and a variety of audio, video and image
416
425
  parameters, as well as proprietary information written by many camera
417
426
  models. Tags with a question mark after their name are not extracted unless
418
427
  the Unknown option is set.
419
428
 
420
429
  When writing, ExifTool creates both QuickTime and XMP tags by default, but
421
- the group may be specified to write one or the other separately. Newly
422
- created QuickTime tags are added in the ItemList location if possible,
423
- otherwise in UserData, but this may be changed by specifying the location.
424
- Alternate language tags may be accessed for ItemList tags by adding a
425
- language-country code to the tag name (eg. "ItemList:Artist-fra-FR"), or for
426
- UserData tags by adding a language code (eg. "UserData:Artist-fra"). If no
427
- language code is specified when writing, alternate languages are deleted.
428
- Use the "und" language code to write the default language without deleting
429
- alternate languages. Note that "eng" is treated as a default language when
430
- reading, but not when writing.
430
+ the group may be specified to write one or the other separately. If no
431
+ location is specified, newly created QuickTime tags are added in the
432
+ ItemList location if possible, otherwise in UserData, and finally in Keys,
433
+ but this order may be changed by setting the PREFERRED level of the
434
+ appropriate table in the config file (see L<example.config|../config.html#PREF> in the full
435
+ distribution for an example). ExifTool currently writes only top-level
436
+ metadata in QuickTime-based files; it extracts other track-specific and
437
+ timed metadata, but can not yet edit tags in these locations.
438
+
439
+ Alternate language tags may be accessed for ItemList and Keys tags by adding
440
+ a 3-character ISO 639-2 language code and an optional ISO 3166-1 alpha 2
441
+ country code to the tag name (eg. "ItemList:Artist-deu" or
442
+ "ItemList::Artist-deu-DE"). UserData tags support only a language code
443
+ (without a country code). If no language code is specified when writing,
444
+ alternate languages for the tag are deleted. Use the "und" language code to
445
+ write the default language without deleting alternate languages. Note that
446
+ "eng" is treated as a default language when reading, but not when writing.
431
447
 
432
448
  According to the specification, many QuickTime date/time tags should be
433
449
  stored as UTC. Unfortunately, digital cameras often store local time values
@@ -560,10 +576,29 @@ my %eeBox = (
560
576
  },
561
577
  },
562
578
  # "\x98\x7f\xa3\xdf\x2a\x85\x43\xc0\x8f\x8f\xd9\x7c\x47\x1e\x8e\xea" - unknown data in Flip videos
579
+ { #PH (Canon CR3)
580
+ Name => 'UUID-Canon2',
581
+ WriteLast => 1, # MUST come after mdat or DPP will drop mdat when writing!
582
+ Condition => '$$valPt=~/^\x21\x0f\x16\x87\x91\x49\x11\xe4\x81\x11\x00\x24\x21\x31\xfc\xe4/',
583
+ SubDirectory => {
584
+ TagTable => 'Image::ExifTool::Canon::uuid2',
585
+ Start => 16,
586
+ },
587
+ },
563
588
  { #PH (Canon CR3)
564
589
  Name => 'PreviewImage',
565
590
  Condition => '$$valPt=~/^\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16/',
566
591
  Groups => { 2 => 'Preview' },
592
+ # 0x00 - undef[16]: UUID
593
+ # 0x10 - int32u[2]: "0 1" (version and/or item count?)
594
+ # 0x18 - int32u: PRVW atom size
595
+ # 0x20 - int32u: 'PRVW'
596
+ # 0x30 - int32u: 0
597
+ # 0x34 - int16u: 1
598
+ # 0x36 - int16u: image width
599
+ # 0x38 - int16u: image height
600
+ # 0x3a - int16u: 1
601
+ # 0x3c - int32u: preview length
567
602
  RawConv => '$val = substr($val, 0x30); $self->ValidateImage(\$val, $tag)',
568
603
  },
569
604
  { #8
@@ -837,9 +872,10 @@ my %eeBox = (
837
872
  # mjqt - default quantization table for MJPEG
838
873
  # mjht - default Huffman table for MJPEG
839
874
  # csgm ? (seen in hevc video)
840
- # CMP1 - 52 bytes (Canon CR3)
841
- # JPEG - 4 bytes all 0 (Canon CR3)
842
- # free - (Canon CR3)
875
+ CMP1 => { # Canon CR3
876
+ Name => 'CMP1',
877
+ SubDirectory => { TagTable => 'Image::ExifTool::Canon::CMP1' },
878
+ },
843
879
  CDI1 => { # Canon CR3
844
880
  Name => 'CDI1',
845
881
  SubDirectory => {
@@ -847,6 +883,8 @@ my %eeBox = (
847
883
  Start => 4,
848
884
  },
849
885
  },
886
+ # JPEG - 4 bytes all 0 (Canon CR3)
887
+ # free - (Canon CR3)
850
888
  #
851
889
  # spherical video v2 stuff (untested)
852
890
  #
@@ -1320,14 +1358,15 @@ my %eeBox = (
1320
1358
  CHECK_PROC => \&CheckQTValue,
1321
1359
  GROUPS => { 1 => 'UserData', 2 => 'Video' },
1322
1360
  WRITABLE => 1,
1361
+ PREFERRED => 1, # (preferred over Keys tags when writing)
1323
1362
  FORMAT => 'string',
1324
1363
  WRITE_GROUP => 'UserData',
1325
1364
  LANG_INFO => \&GetLangInfo,
1326
1365
  NOTES => q{
1327
1366
  Tag ID's beginning with the copyright symbol (hex 0xa9) are multi-language
1328
- text. Alternate language tags are accessed by adding a dash followed by the
1329
- language/country code to the tag name. ExifTool will extract any
1330
- multi-language user data tags found, even if they don't exist in this table.
1367
+ text. Alternate language tags are accessed by adding a dash followed by a
1368
+ 3-character ISO 639-2 language code to the tag name. ExifTool will extract
1369
+ any multi-language user data tags found, even if they aren't in this table.
1331
1370
  },
1332
1371
  "\xa9cpy" => { Name => 'Copyright', Groups => { 2 => 'Author' } },
1333
1372
  "\xa9day" => {
@@ -2100,7 +2139,7 @@ my %eeBox = (
2100
2139
 
2101
2140
  # User-specific media data atoms (ref 11)
2102
2141
  %Image::ExifTool::QuickTime::MetaData = (
2103
- PROCESS_PROC => \&Image::ExifTool::QuickTime::ProcessMetaData,
2142
+ PROCESS_PROC => \&ProcessMetaData,
2104
2143
  GROUPS => { 2 => 'Video' },
2105
2144
  TAG_PREFIX => 'MetaData',
2106
2145
  0x01 => 'Title',
@@ -2598,7 +2637,7 @@ my %eeBox = (
2598
2637
  WRITE_PROC => \&WriteQuickTime,
2599
2638
  CHECK_PROC => \&CheckQTValue,
2600
2639
  WRITABLE => 1,
2601
- PREFERRED => 1,
2640
+ PREFERRED => 2, # (preferred over UserData and Keys tags when writing)
2602
2641
  FORMAT => 'string',
2603
2642
  GROUPS => { 1 => 'ItemList', 2 => 'Audio' },
2604
2643
  WRITE_GROUP => 'ItemList',
@@ -2606,6 +2645,10 @@ my %eeBox = (
2606
2645
  NOTES => q{
2607
2646
  As well as these tags, the "mdta" handler uses numerical tag ID's which are
2608
2647
  added dynamically to this table after processing the Meta Keys information.
2648
+ Tags in this table support alternate languages which are accessed by adding
2649
+ a 3-character ISO 639-2 language code and an optional ISO 3166-1 alpha 2
2650
+ country code to the tag name (eg. "ItemList:Title-fra" or
2651
+ "ItemList::Title-fra-FR").
2609
2652
  },
2610
2653
  # in this table, binary 1 and 2-byte "data"-type tags are interpreted as
2611
2654
  # int8u and int16u. Multi-byte binary "data" tags are extracted as binary data.
@@ -5391,16 +5434,15 @@ my %eeBox = (
5391
5434
 
5392
5435
  # item list keys (ref PH)
5393
5436
  %Image::ExifTool::QuickTime::Keys = (
5394
- PROCESS_PROC => \&Image::ExifTool::QuickTime::ProcessKeys,
5395
- WRITE_PROC => \&Image::ExifTool::QuickTime::ProcessKeys,
5437
+ PROCESS_PROC => \&ProcessKeys,
5438
+ WRITE_PROC => \&WriteKeys,
5396
5439
  CHECK_PROC => \&CheckQTValue,
5397
5440
  VARS => { LONG_TAGS => 3 },
5398
5441
  WRITABLE => 1,
5442
+ # (not PREFERRED when writing)
5399
5443
  GROUPS => { 1 => 'Keys' },
5400
5444
  WRITE_GROUP => 'Keys',
5401
5445
  LANG_INFO => \&GetLangInfo,
5402
- PRIORITY => 0, # (so empty (deleted) values don't obscure other good values)
5403
- PERMANENT => 1, # (can't be deleted)
5404
5446
  FORMAT => 'string',
5405
5447
  NOTES => q{
5406
5448
  This directory contains a list of key names which are used to decode
@@ -6034,6 +6076,12 @@ my %eeBox = (
6034
6076
  sgpd => {
6035
6077
  Name => 'SampleGroupDescription',
6036
6078
  Flags => ['Binary','Unknown'],
6079
+ # bytes 4-7 give grouping type (ref ISO/IEC 14496-15:2014)
6080
+ # tsas - temporal sublayer sample
6081
+ # stsa - step-wise temporal layer access
6082
+ # avss - AVC sample
6083
+ # tscl - temporal layer scaleability
6084
+ # sync - sync sample
6037
6085
  },
6038
6086
  subs => {
6039
6087
  Name => 'Sub-sampleInformation',
@@ -7903,51 +7951,44 @@ sub ProcessEncodingParams($$$)
7903
7951
  }
7904
7952
 
7905
7953
  #------------------------------------------------------------------------------
7906
- # Process Meta keys and add tags to the ItemList table ('mdta' handler) (ref PH)
7954
+ # Read Meta Keys and add tags to ItemList table ('mdta' handler) (ref PH)
7907
7955
  # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
7908
- # Returns: 1 on success (undef when writing)
7956
+ # Returns: 1 on success
7909
7957
  sub ProcessKeys($$$)
7910
7958
  {
7911
7959
  local $_;
7912
7960
  my ($et, $dirInfo, $tagTablePtr) = @_;
7913
- $et or return 1; # allow dummy access to autoload this package
7914
- my $newVal = $$et{NEW_VALUE};
7915
7961
  my $dataPt = $$dirInfo{DataPt};
7916
7962
  my $dirLen = length $$dataPt;
7917
7963
  my $out;
7918
- if ($et->Options('Verbose') and not $$dirInfo{OutFile}) {
7964
+ if ($et->Options('Verbose')) {
7919
7965
  $et->VerboseDir('Keys');
7920
7966
  $out = $et->Options('TextOut');
7921
7967
  }
7922
7968
  my $pos = 8;
7923
7969
  my $index = 1;
7924
- ++$$et{KeyCount}; # increment key count for this directory
7925
- my $infoTable = GetTagTable('Image::ExifTool::QuickTime::ItemList');
7926
- my $userTable = GetTagTable('Image::ExifTool::QuickTime::UserData');
7970
+ ++$$et{KeysCount}; # increment key count for this directory
7971
+ my $itemList = GetTagTable('Image::ExifTool::QuickTime::ItemList');
7972
+ my $userData = GetTagTable('Image::ExifTool::QuickTime::UserData');
7927
7973
  while ($pos < $dirLen - 4) {
7928
7974
  my $len = unpack("x${pos}N", $$dataPt);
7929
7975
  last if $len < 8 or $pos + $len > $dirLen;
7930
- if ($$tagTablePtr{$index}) {
7931
- delete $$newVal{$$tagTablePtr{$index}} if $newVal;
7932
- delete $$tagTablePtr{$index};
7933
- }
7976
+ delete $$tagTablePtr{$index};
7934
7977
  my $ns = substr($$dataPt, $pos + 4, 4);
7935
7978
  my $tag = substr($$dataPt, $pos + 8, $len - 8);
7936
7979
  $tag =~ s/\0.*//s; # truncate at null
7937
- if ($ns eq 'mdta') {
7938
- $tag =~ s/^com\.apple\.quicktime\.//; # remove common apple quicktime domain
7939
- }
7980
+ $tag =~ s/^com\.apple\.quicktime\.// if $ns eq 'mdta'; # remove apple quicktime domain
7940
7981
  $tag = "Tag_$ns" unless $tag;
7941
7982
  # (I have some samples where the tag is a reversed ItemList or UserData tag ID)
7942
7983
  my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
7943
7984
  unless ($tagInfo) {
7944
- $tagInfo = $et->GetTagInfo($infoTable, $tag);
7985
+ $tagInfo = $et->GetTagInfo($itemList, $tag);
7945
7986
  unless ($tagInfo) {
7946
- $tagInfo = $et->GetTagInfo($userTable, $tag);
7987
+ $tagInfo = $et->GetTagInfo($userData, $tag);
7947
7988
  if (not $tagInfo and $tag =~ /^\w{3}\xa9$/) {
7948
7989
  $tag = pack('N', unpack('V', $tag));
7949
- $tagInfo = $et->GetTagInfo($infoTable, $tag);
7950
- $tagInfo or $tagInfo = $et->GetTagInfo($userTable, $tag);
7990
+ $tagInfo = $et->GetTagInfo($itemList, $tag);
7991
+ $tagInfo or $tagInfo = $et->GetTagInfo($userData, $tag);
7951
7992
  }
7952
7993
  }
7953
7994
  }
@@ -7960,7 +8001,6 @@ sub ProcessKeys($$$)
7960
8001
  ValueConvInv => $$tagInfo{ValueConvInv},
7961
8002
  PrintConv => $$tagInfo{PrintConv},
7962
8003
  PrintConvInv => $$tagInfo{PrintConvInv},
7963
- Permanent => 1, # (don't allow these to be deleted for now)
7964
8004
  Writable => defined $$tagInfo{Writable} ? $$tagInfo{Writable} : 1,
7965
8005
  KeysInfo => $tagInfo,
7966
8006
  };
@@ -7979,35 +8019,24 @@ sub ProcessKeys($$$)
7979
8019
  $msg = ' (Unknown)';
7980
8020
  }
7981
8021
  # substitute this tag in the ItemList table with the given index
7982
- my $id = $$et{KeyCount} . '.' . $index;
7983
- if (ref $$infoTable{$id} eq 'HASH') {
8022
+ my $id = $$et{KeysCount} . '.' . $index;
8023
+ if (ref $$itemList{$id} eq 'HASH') {
7984
8024
  # delete other languages too if they exist
7985
- my $oldInfo = $$infoTable{$id};
8025
+ my $oldInfo = $$itemList{$id};
7986
8026
  if ($$oldInfo{OtherLang}) {
7987
- foreach (@{$$oldInfo{OtherLang}}) {
7988
- delete $$newVal{$$infoTable{$_}} if $newVal and $$infoTable{$_};
7989
- delete $$infoTable{$_};
7990
- }
8027
+ delete $$itemList{$_} foreach @{$$oldInfo{OtherLang}};
7991
8028
  }
7992
- delete $$newVal{$$infoTable{$id}} if $newVal;
7993
- delete $$infoTable{$id};
8029
+ delete $$itemList{$id};
7994
8030
  }
7995
8031
  if ($newInfo) {
7996
- if ($newVal) {
7997
- # add to tag lookup so it will be writable
7998
- my $add = { $id => $newInfo };
7999
- Image::ExifTool::TagLookup::AddTags($add, 'Image::ExifTool::QuickTime::ItemList');
8000
- # set value hash if we are writing this tag now
8001
- $$newVal{$newInfo} = $$newVal{$tagInfo} if $tagInfo and $$newVal{$tagInfo};
8002
- }
8003
- AddTagToTable($infoTable, $id, $newInfo);
8032
+ AddTagToTable($itemList, $id, $newInfo);
8004
8033
  $msg or $msg = '';
8005
8034
  $out and print $out "$$et{INDENT}Added ItemList Tag $id = $tag$msg\n";
8006
8035
  }
8007
8036
  $pos += $len;
8008
8037
  ++$index;
8009
8038
  }
8010
- return $$dirInfo{OutFile} ? undef : 1;
8039
+ return 1;
8011
8040
  }
8012
8041
 
8013
8042
  #------------------------------------------------------------------------------
@@ -8033,6 +8062,7 @@ sub ProcessMOV($$;$)
8033
8062
  my $raf = $$dirInfo{RAF};
8034
8063
  my $dataPt = $$dirInfo{DataPt};
8035
8064
  my $verbose = $et->Options('Verbose');
8065
+ my $validate = $$et{OPTIONS}{Validate};
8036
8066
  my $dataPos = $$dirInfo{Base} || 0;
8037
8067
  my $dirID = $$dirInfo{DirID} || '';
8038
8068
  my $charsetQuickTime = $et->Options('CharsetQuickTime');
@@ -8043,8 +8073,8 @@ sub ProcessMOV($$;$)
8043
8073
  $$et{InQuickTime} = 1;
8044
8074
  $$et{HandlerType} = $$et{MetaFormat} = '' unless defined $$et{HandlerType};
8045
8075
 
8046
- unless (defined $$et{KeyCount}) {
8047
- $$et{KeyCount} = 0; # initialize ItemList key directory count
8076
+ unless (defined $$et{KeysCount}) {
8077
+ $$et{KeysCount} = 0; # initialize ItemList key directory count
8048
8078
  $doDefaultLang = 1; # flag to generate default language tags
8049
8079
  }
8050
8080
  # more convenient to package data as a RandomAccess file
@@ -8143,6 +8173,18 @@ sub ProcessMOV($$;$)
8143
8173
  } else {
8144
8174
  $size -= 8;
8145
8175
  }
8176
+ if ($validate) {
8177
+ $$et{ValidatePath} or $$et{ValidatePath} = { };
8178
+ my $path = join('-', @{$$et{PATH}}, $tag);
8179
+ $path =~ s/-Track-/-$$et{SET_GROUP1}-/ if $$et{SET_GROUP1};
8180
+ if ($$et{ValidatePath}{$path} and not $dupTagOK{$tag} and not $dupDirOK{$dirID}) {
8181
+ my $i = Get32u(\$tag,0);
8182
+ my $str = $i < 255 ? "index $i" : "tag '" . PrintableTagID($tag,2) . "'";
8183
+ $et->WarnOnce("Duplicate $str at " . join('-', @{$$et{PATH}}));
8184
+ $$et{ValidatePath} = { } if $path eq 'MOV-moov'; # avoid warnings for all contained dups
8185
+ }
8186
+ $$et{ValidatePath}{$path} = 1;
8187
+ }
8146
8188
  if ($isUserData and $$et{SET_GROUP1}) {
8147
8189
  my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
8148
8190
  # add track name to UserData tags inside tracks
@@ -8176,7 +8218,7 @@ sub ProcessMOV($$;$)
8176
8218
 
8177
8219
  # allow numerical tag ID's
8178
8220
  unless ($tagInfo) {
8179
- my $id = $$et{KeyCount} . '.' . unpack('N', $tag);
8221
+ my $id = $$et{KeysCount} . '.' . unpack('N', $tag);
8180
8222
  if ($$tagTablePtr{$id}) {
8181
8223
  $tagInfo = $et->GetTagInfo($tagTablePtr, $id);
8182
8224
  $tag = $id;
@@ -8380,7 +8422,7 @@ ItemID: foreach $id (keys %$items) {
8380
8422
  last if $pos + 16 > $size;
8381
8423
  my ($len, $type, $flags, $ctry, $lang) = unpack("x${pos}Na4Nnn", $val);
8382
8424
  last if $pos + $len > $size;
8383
- my $value;
8425
+ my ($value, $langInfo, $oldDir);
8384
8426
  my $format = $$tagInfo{Format};
8385
8427
  if ($type eq 'data' and $len >= 16) {
8386
8428
  $pos += 16;
@@ -8407,7 +8449,6 @@ ItemID: foreach $id (keys %$items) {
8407
8449
  }
8408
8450
  }
8409
8451
  }
8410
- my $langInfo;
8411
8452
  if ($ctry or $lang) {
8412
8453
  $lang = GetLangCode($lang, $ctry);
8413
8454
  if ($lang) {
@@ -8429,9 +8470,16 @@ ItemID: foreach $id (keys %$items) {
8429
8470
  Size => $len,
8430
8471
  Format => $format,
8431
8472
  Index => $index,
8432
- Extra => sprintf(", Type='${type}', Flags=0x%x",$flags)
8473
+ Extra => sprintf(", Type='${type}', Flags=0x%x%s",$flags,($lang ? ", Lang=$lang" : '')),
8433
8474
  ) if $verbose;
8475
+ # use "Keys" in path instead of ItemList if this was defined by a Keys tag
8476
+ my $isKey = $$tagInfo{Groups} && $$tagInfo{Groups}{1} && $$tagInfo{Groups}{1} eq 'Keys';
8477
+ if ($isKey) {
8478
+ $oldDir = $$et{PATH}[-1];
8479
+ $$et{PATH}[-1] = 'Keys';
8480
+ }
8434
8481
  $et->FoundTag($langInfo, $value) if defined $value;
8482
+ $$et{PATH}[-1] = $oldDir if $isKey;
8435
8483
  $pos += $len;
8436
8484
  }
8437
8485
  } elsif ($tag =~ /^\xa9/ or $$tagInfo{IText}) {