exiftool_vendored 12.50.0 → 12.52.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,6 +6,7 @@
6
6
  # Revisions: 05/26/2010 - P. Harvey Created
7
7
  #
8
8
  # References: 1) http://www.matroska.org/technical/specs/index.html
9
+ # 2) https://www.matroska.org/technical/tagging.html
9
10
  #------------------------------------------------------------------------------
10
11
 
11
12
  package Image::ExifTool::Matroska;
@@ -14,10 +15,26 @@ use strict;
14
15
  use vars qw($VERSION);
15
16
  use Image::ExifTool qw(:DataAccess :Utils);
16
17
 
17
- $VERSION = '1.12';
18
+ $VERSION = '1.13';
19
+
20
+ sub HandleStruct($$;$$$$);
18
21
 
19
22
  my %noYes = ( 0 => 'No', 1 => 'Yes' );
20
23
 
24
+ my %dateInfo = (
25
+ Groups => { 2 => 'Time' },
26
+ # the spec says to use "-" as a date separator, but my only sample uses ":", so
27
+ # convert to ":" if necessary, and avoid translating all "-" in case someone wants
28
+ # to include a negative time zone (although the spec doesn't mention time zones)
29
+ ValueConv => '$val =~ s/^(\d{4})-(\d{2})-/$1:$2:/; $val',
30
+ PrintConv => '$self->ConvertDateTime($val)',
31
+ );
32
+
33
+ my %uidInfo = (
34
+ Format => 'string',
35
+ ValueConv => 'unpack("H*",$val)'
36
+ );
37
+
21
38
  # Matroska tags
22
39
  # Note: The tag ID's in the Matroska documentation include the length designation
23
40
  # (the upper bits), which is not included in the tag ID's below
@@ -58,7 +75,7 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' );
58
75
  #
59
76
  # General
60
77
  #
61
- 0x3f => { Name => 'CRC-32', Binary => 1, Unknown => 1 },
78
+ 0x3f => { Name => 'CRC-32', Format => 'unsigned', Unknown => 1 },
62
79
  0x6c => { Name => 'Void', NoSave => 1, Unknown => 1 },
63
80
  #
64
81
  # Signature
@@ -104,18 +121,18 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' );
104
121
  Name => 'Info',
105
122
  SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
106
123
  },
107
- 0x33a4 => { Name => 'SegmentUID', Binary => 1, Unknown => 1 },
124
+ 0x33a4 => { Name => 'SegmentUID', %uidInfo, Unknown => 1 },
108
125
  0x3384 => { Name => 'SegmentFileName', Format => 'utf8' },
109
- 0x1cb923 => { Name => 'PrevUID', Binary => 1, Unknown => 1 },
126
+ 0x1cb923 => { Name => 'PrevUID', %uidInfo, Unknown => 1 },
110
127
  0x1c83ab => { Name => 'PrevFileName', Format => 'utf8' },
111
- 0x1eb923 => { Name => 'NextUID', Binary => 1, Unknown => 1 },
128
+ 0x1eb923 => { Name => 'NextUID', %uidInfo, Unknown => 1 },
112
129
  0x1e83bb => { Name => 'NextFileName', Format => 'utf8' },
113
130
  0x0444 => { Name => 'SegmentFamily', Binary => 1, Unknown => 1 },
114
131
  0x2924 => {
115
132
  Name => 'ChapterTranslate',
116
133
  SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
117
134
  },
118
- 0x29fc => { Name => 'ChapterTranslateEditionUID',Format => 'unsigned', Unknown => 1 },
135
+ 0x29fc => { Name => 'ChapterTranslateEditionUID', %uidInfo, Unknown => 1 },
119
136
  0x29bf => {
120
137
  Name => 'ChapterTranslateCodec',
121
138
  Format => 'unsigned',
@@ -228,7 +245,7 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' );
228
245
  SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
229
246
  },
230
247
  0x57 => { Name => 'TrackNumber', Format => 'unsigned' },
231
- 0x33c5 => { Name => 'TrackUID', Format => 'unsigned', Unknown => 1 },
248
+ 0x33c5 => { Name => 'TrackUID', %uidInfo },
232
249
  0x03 => {
233
250
  Name => 'TrackType',
234
251
  Format => 'unsigned',
@@ -305,7 +322,7 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' );
305
322
  Format => 'utf8',
306
323
  }
307
324
  ],
308
- 0x3446 => { Name => 'TrackAttachmentUID',Format => 'unsigned' },
325
+ 0x3446 => { Name => 'TrackAttachmentUID',%uidInfo },
309
326
  0x1a9697=>{ Name => 'CodecSettings', Format => 'utf8' },
310
327
  0x1b4040=>{ Name => 'CodecInfoURL', Format => 'string' },
311
328
  0x6b240 =>{ Name => 'CodecDownloadURL', Format => 'string' },
@@ -315,7 +332,7 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' );
315
332
  Name => 'TrackTranslate',
316
333
  SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
317
334
  },
318
- 0x26fc => { Name => 'TrackTranslateEditionUID',Format => 'unsigned', Unknown => 1 },
335
+ 0x26fc => { Name => 'TrackTranslateEditionUID', %uidInfo, Unknown => 1 },
319
336
  0x26bf => {
320
337
  Name => 'TrackTranslateCodec',
321
338
  Format => 'unsigned',
@@ -362,6 +379,8 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' );
362
379
  0 => 'Pixels',
363
380
  1 => 'cm',
364
381
  2 => 'inches',
382
+ 3 => 'Display Aspect Ratio',
383
+ 4 => 'Unknown',
365
384
  },
366
385
  },
367
386
  0x14b3 => {
@@ -517,7 +536,7 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' );
517
536
  0x66e => { Name => 'AttachedFileName', Format => 'utf8' },
518
537
  0x660 => { Name => 'AttachedFileMIMEType', Format => 'string' },
519
538
  0x65c => { Name => 'AttachedFileData', Binary => 1 },
520
- 0x6ae => { Name => 'AttachedFileUID', Format => 'unsigned' },
539
+ 0x6ae => { Name => 'AttachedFileUID', %uidInfo },
521
540
  0x675 => { Name => 'AttachedFileReferral', Binary => 1, Unknown => 1 },
522
541
  #
523
542
  # Chapters
@@ -530,7 +549,7 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' );
530
549
  Name => 'EditionEntry',
531
550
  SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
532
551
  },
533
- 0x5bc => { Name => 'EditionUID', Format => 'unsigned', Unknown => 1 },
552
+ 0x5bc => { Name => 'EditionUID', %uidInfo, Unknown => 1 },
534
553
  0x5bd => { Name => 'EditionFlagHidden', Format => 'unsigned', Unknown => 1 },
535
554
  0x5db => { Name => 'EditionFlagDefault',Format => 'unsigned', Unknown => 1 },
536
555
  0x5dd => { Name => 'EditionFlagOrdered',Format => 'unsigned', Unknown => 1 },
@@ -538,7 +557,7 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' );
538
557
  Name => 'ChapterAtom',
539
558
  SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
540
559
  },
541
- 0x33c4 => { Name => 'ChapterUID', Format => 'unsigned', Unknown => 1 },
560
+ 0x33c4 => { Name => 'ChapterUID', %uidInfo, Unknown => 1 },
542
561
  0x11 => {
543
562
  Name => 'ChapterTimeStart',
544
563
  Groups => { 1 => 'Chapter#' },
@@ -554,8 +573,8 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' );
554
573
  },
555
574
  0x18 => { Name => 'ChapterFlagHidden', Format => 'unsigned', Unknown => 1 },
556
575
  0x598 => { Name => 'ChapterFlagEnabled',Format => 'unsigned', Unknown => 1 },
557
- 0x2e67=> { Name => 'ChapterSegmentUID', Binary => 1, Unknown => 1 },
558
- 0x2ebc=> { Name => 'ChapterSegmentEditionUID', Binary => 1, Unknown => 1 },
576
+ 0x2e67=> { Name => 'ChapterSegmentUID', %uidInfo, Unknown => 1 },
577
+ 0x2ebc=> { Name => 'ChapterSegmentEditionUID', %uidInfo, Unknown => 1 },
559
578
  0x23c3 => {
560
579
  Name => 'ChapterPhysicalEquivalent',
561
580
  Format => 'unsigned',
@@ -622,21 +641,24 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' );
622
641
  Name => 'Targets',
623
642
  SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
624
643
  },
625
- 0x28ca => { Name => 'TargetTypeValue', Format => 'unsigned' },
626
- 0x23ca => { Name => 'TargetType', Format => 'string' },
627
- 0x23c5 => { Name => 'TagTrackUID', Format => 'unsigned', Unknown => 1 },
628
- 0x23c9 => { Name => 'TagEditionUID', Format => 'unsigned', Unknown => 1 },
629
- 0x23c4 => { Name => 'TagChapterUID', Format => 'unsigned', Unknown => 1 },
630
- 0x23c6 => { Name => 'TagAttachmentUID', Format => 'unsigned', Unknown => 1 },
644
+ # Targets elements
645
+ 0x28ca => { Name => 'TargetTypeValue', Format => 'unsigned' },
646
+ 0x23ca => { Name => 'TargetType', Format => 'string' },
647
+ 0x23c5 => { Name => 'TagTrackUID', %uidInfo },
648
+ 0x23c9 => { Name => 'TagEditionUID', %uidInfo },
649
+ 0x23c4 => { Name => 'TagChapterUID', %uidInfo },
650
+ 0x23c6 => { Name => 'TagAttachmentUID', %uidInfo },
631
651
  0x27c8 => {
632
652
  Name => 'SimpleTag',
633
653
  SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' },
634
654
  },
635
- 0x5a3 => { Name => 'TagName', Format => 'utf8' },
636
- 0x47a => { Name => 'TagLanguage', Format => 'string' },
637
- 0x484 => { Name => 'TagDefault', Format => 'unsigned', PrintConv => \%noYes },
638
- 0x487 => { Name => 'TagString', Format => 'utf8' },
639
- 0x485 => { Name => 'TagBinary', Binary => 1 },
655
+ # SimpleTag elements
656
+ 0x5a3 => { Name => 'TagName', Format => 'utf8' },
657
+ 0x47a => { Name => 'TagLanguage', Format => 'string' },
658
+ 0x47a => { Name => 'TagLanguageBCP47', Format => 'string' },
659
+ 0x484 => { Name => 'TagDefault', Format => 'unsigned', PrintConv => \%noYes },
660
+ 0x487 => { Name => 'TagString', Format => 'utf8' },
661
+ 0x485 => { Name => 'TagBinary', Binary => 1 },
640
662
  #
641
663
  # Spherical Video V2 (untested)
642
664
  #
@@ -685,6 +707,172 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' );
685
707
  0x7675 => { Name => 'ProjectionPoseRoll', Format => 'float' },
686
708
  );
687
709
 
710
+ # standardized tag names (ref 2)
711
+ %Image::ExifTool::Matroska::Tags = (
712
+ GROUPS => { 2 => 'Video' },
713
+ VARS => { LONG_TAGS => 1 },
714
+ NOTES => q{
715
+ Standardized Matroska tags (see
716
+ L<https://www.matroska.org/technical/tagging.html>).
717
+ },
718
+ ORIGINAL => 'Original', # struct
719
+ SAMPLE => 'Sample', # struct
720
+ COUNTRY => 'Country', # struct (should deal with this properly!)
721
+ TOTAL_PARTS => 'TotalParts',
722
+ PART_NUMBER => 'PartNumber',
723
+ PART_OFFSET => 'PartOffset',
724
+ TITLE => 'Title',
725
+ SUBTITLE => 'Subtitle',
726
+ URL => 'URL', # nested
727
+ SORT_WITH => 'SortWith', # nested
728
+ INSTRUMENTS => 'Instruments', # nested
729
+ EMAIL => 'Email', # nested
730
+ ADDRESS => 'Address', # nested
731
+ FAX => 'FAX', # nested
732
+ PHONE => 'Phone', # nested
733
+ ARTIST => 'Artist',
734
+ LEAD_PERFORMER => 'LeadPerformer',
735
+ ACCOMPANIMENT => 'Accompaniment',
736
+ COMPOSER => 'Composer',
737
+ ARRANGER => 'Arranger',
738
+ LYRICS => 'Lyrics',
739
+ LYRICIST => 'Lyricist',
740
+ CONDUCTOR => 'Conductor',
741
+ DIRECTOR => 'Director',
742
+ ASSISTANT_DIRECTOR => 'AssistantDirector',
743
+ DIRECTOR_OF_PHOTOGRAPHY => 'DirectorOfPhotography',
744
+ SOUND_ENGINEER => 'SoundEngineer',
745
+ ART_DIRECTOR => 'ArtDirector',
746
+ PRODUCTION_DESIGNER => 'ProductionDesigner',
747
+ CHOREGRAPHER => 'Choregrapher',
748
+ COSTUME_DESIGNER => 'CostumeDesigner',
749
+ ACTOR => 'Actor',
750
+ CHARACTER => 'Character',
751
+ WRITTEN_BY => 'WrittenBy',
752
+ SCREENPLAY_BY => 'ScreenplayBy',
753
+ EDITED_BY => 'EditedBy',
754
+ PRODUCER => 'Producer',
755
+ COPRODUCER => 'Coproducer',
756
+ EXECUTIVE_PRODUCER => 'ExecutiveProducer',
757
+ DISTRIBUTED_BY => 'DistributedBy',
758
+ MASTERED_BY => 'MasteredBy',
759
+ ENCODED_BY => 'EncodedBy',
760
+ MIXED_BY => 'MixedBy',
761
+ REMIXED_BY => 'RemixedBy',
762
+ PRODUCTION_STUDIO => 'ProductionStudio',
763
+ THANKS_TO => 'ThanksTo',
764
+ PUBLISHER => 'Publisher',
765
+ LABEL => 'Label',
766
+ GENRE => 'Genre',
767
+ MOOD => 'Mood',
768
+ ORIGINAL_MEDIA_TYPE => 'OriginalMediaType',
769
+ CONTENT_TYPE => 'ContentType',
770
+ SUBJECT => 'Subject',
771
+ DESCRIPTION => 'Description',
772
+ KEYWORDS => 'Keywords',
773
+ SUMMARY => 'Summary',
774
+ SYNOPSIS => 'Synopsis',
775
+ INITIAL_KEY => 'InitialKey',
776
+ PERIOD => 'Period',
777
+ LAW_RATING => 'LawRating',
778
+ DATE_RELEASED => { Name => 'DateReleased', %dateInfo },
779
+ DATE_RECORDED => { Name => 'DateTimeOriginal', %dateInfo, Description => 'Date/Time Original' },
780
+ DATE_ENCODED => { Name => 'DateEncoded', %dateInfo },
781
+ DATE_TAGGED => { Name => 'DateTagged', %dateInfo },
782
+ DATE_DIGITIZED => { Name => 'CreateDate', %dateInfo },
783
+ DATE_WRITTEN => { Name => 'DateWritten', %dateInfo },
784
+ DATE_PURCHASED => { Name => 'DatePurchased', %dateInfo },
785
+ RECORDING_LOCATION => 'RecordingLocation',
786
+ COMPOSITION_LOCATION => 'CompositionLocation',
787
+ COMPOSER_NATIONALITY => 'ComposerNationality',
788
+ COMMENT => 'Comment',
789
+ PLAY_COUNTER => 'PlayCounter',
790
+ RATING => 'Rating',
791
+ ENCODER => 'Encoder',
792
+ ENCODER_SETTINGS => 'EncoderSettings',
793
+ BPS => 'BPS',
794
+ FPS => 'FPS',
795
+ BPM => 'BPM',
796
+ MEASURE => 'Measure',
797
+ TUNING => 'Tuning',
798
+ REPLAYGAIN_GAIN => 'ReplaygainGain',
799
+ REPLAYGAIN_PEAK => 'ReplaygainPeak',
800
+ ISRC => 'ISRC',
801
+ MCDI => 'MCDI',
802
+ ISBN => 'ISBN',
803
+ BARCODE => 'Barcode',
804
+ CATALOG_NUMBER => 'CatalogNumber',
805
+ LABEL_CODE => 'LabelCode',
806
+ LCCN => 'Lccn',
807
+ IMDB => 'IMDB',
808
+ TMDB => 'TMDB',
809
+ TVDB => 'TVDB',
810
+ PURCHASE_ITEM => 'PurchaseItem',
811
+ PURCHASE_INFO => 'PurchaseInfo',
812
+ PURCHASE_OWNER => 'PurchaseOwner',
813
+ PURCHASE_PRICE => 'PurchasePrice',
814
+ PURCHASE_CURRENCY => 'PurchaseCurrency',
815
+ COPYRIGHT => 'Copyright',
816
+ PRODUCTION_COPYRIGHT => 'ProductionCopyright',
817
+ LICENSE => 'License',
818
+ TERMS_OF_USE => 'TermsOfUse',
819
+ );
820
+
821
+ #------------------------------------------------------------------------------
822
+ # Handle MKV SimpleTag structure
823
+ # Inputs: 0) ExifTool ref, 1) structure ref, 2) parent tag ID, 3) parent tag Name,
824
+ # 4) language code, 5) country code
825
+ sub HandleStruct($$;$$$$)
826
+ {
827
+ local $_;
828
+ my ($et, $struct, $pid, $pname, $lang, $ctry) = @_;
829
+ my $tagTbl = GetTagTable('Image::ExifTool::Matroska::Tags');
830
+ my $tag = $$struct{TagName};
831
+ my $tagInfo = $$tagTbl{$tag};
832
+ # create tag if necessary
833
+ unless (ref $tagInfo eq 'HASH') {
834
+ my $name = ucfirst lc $tag;
835
+ $name =~ tr/0-9a-zA-Z_//dc;
836
+ $name =~ s/_([a-z])/\U$1/g;
837
+ $name = "Tag_$name" if length $name < 2;
838
+ $tagInfo = AddTagToTable($tagTbl, $tag, { Name => $name });
839
+ }
840
+ my ($id, $nm);
841
+ if ($pid) {
842
+ $id = "$pid/$tag";
843
+ $nm = "$pname/$$tagInfo{Name}";
844
+ unless ($$tagTbl{$id}) {
845
+ my %copy = %$tagInfo;
846
+ $copy{Name} = $nm;
847
+ $tagInfo = AddTagToTable($tagTbl, $id, \%copy);
848
+ }
849
+ } else {
850
+ ($id, $nm) = ($tag, $$tagInfo{Name});
851
+ }
852
+ if (defined $$struct{TagString} or defined $$struct{TagBinary}) {
853
+ my $val = defined $$struct{TagString} ? $$struct{TagString} : \$$struct{TagBinary};
854
+ $lang = $$struct{TagLanguageBCP47} || $$struct{TagLanguage} || $lang;
855
+ # (Note: not currently handling TagDefault attribute)
856
+ my $code = $lang;
857
+ $code = $lang ? "${lang}-${ctry}" : "eng-${ctry}" if $ctry; # ('eng' is default lang)
858
+ if ($code) {
859
+ $tagInfo = Image::ExifTool::GetLangInfo($tagInfo, $code);
860
+ $et->HandleTag($tagTbl, $$tagInfo{TagID}, $val);
861
+ } else {
862
+ $et->HandleTag($tagTbl, $id, $val);
863
+ }
864
+ # COUNTRY is handled as an attribute for contained tags
865
+ if ($tag eq 'COUNTRY') {
866
+ $ctry = $val;
867
+ ($id, $nm) = ($pid, $pname);
868
+ }
869
+ }
870
+ if ($$struct{struct}) {
871
+ # step into each contained structure
872
+ HandleStruct($et, $_, $id, $nm, $lang, $ctry) foreach @{$$struct{struct}};
873
+ }
874
+ }
875
+
688
876
  #------------------------------------------------------------------------------
689
877
  # Get variable-length Matroska integer
690
878
  # Inputs: 0) data buffer, 1) position in data
@@ -726,7 +914,7 @@ sub ProcessMKV($$)
726
914
  {
727
915
  my ($et, $dirInfo) = @_;
728
916
  my $raf = $$dirInfo{RAF};
729
- my ($buff, $buf2, @dirEnd, $trackIndent, %trackTypes);
917
+ my ($buff, $buf2, @dirEnd, $trackIndent, %trackTypes, $struct);
730
918
 
731
919
  $raf->Read($buff, 4) == 4 or return 0;
732
920
  return 0 unless $buff =~ /^\x1a\x45\xdf\xa3/;
@@ -751,14 +939,33 @@ sub ProcessMKV($$)
751
939
  $$et{TrackTypes} = \%trackTypes; # store Track types reference
752
940
  my $oldIndent = $$et{INDENT};
753
941
  my $chapterNum = 0;
942
+ my $dirName = 'MKV';
754
943
 
755
944
  # loop over all Matroska elements
756
945
  for (;;) {
757
- while (@dirEnd and $pos + $dataPos >= $dirEnd[-1][0]) {
758
- pop @dirEnd;
759
- # use INDENT to decide whether or not we are done this Track element
760
- delete $$et{SET_GROUP1} if $trackIndent and $trackIndent eq $$et{INDENT};
761
- $$et{INDENT} = substr($$et{INDENT}, 0, -2);
946
+ while (@dirEnd) {
947
+ if ($pos + $dataPos >= $dirEnd[-1][0]) {
948
+ pop @dirEnd;
949
+ if ($struct) {
950
+ if (@dirEnd and $dirEnd[-1][2]) {
951
+ # save this nested structure
952
+ $dirEnd[-1][2]{struct} or $dirEnd[-1][2]{struct} = [ ];
953
+ push @{$dirEnd[-1][2]{struct}}, $struct;
954
+ $struct = $dirEnd[-1][2];
955
+ } else {
956
+ # handle completed structures now
957
+ HandleStruct($et, $struct);
958
+ undef $struct;
959
+ }
960
+ }
961
+ $dirName = @dirEnd ? $dirEnd[-1][1] : 'MKV';
962
+ # use INDENT to decide whether or not we are done this Track element
963
+ delete $$et{SET_GROUP1} if $trackIndent and $trackIndent eq $$et{INDENT};
964
+ $$et{INDENT} = substr($$et{INDENT}, 0, -2);
965
+ } else {
966
+ $dirName = $dirEnd[-1][1];
967
+ last;
968
+ }
762
969
  }
763
970
  # read more if we are getting close to the end of our buffer
764
971
  # (24 more bytes should be enough to read this element header)
@@ -789,21 +996,27 @@ sub ProcessMKV($$)
789
996
  }
790
997
  my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
791
998
  # just fall through into the contained EBML elements
792
- if ($tagInfo and $$tagInfo{SubDirectory}) {
793
- # stop processing at first cluster unless we are using -v -U or -ee
794
- if ($$tagInfo{Name} eq 'Cluster' and $processAll < 2) {
795
- last unless $processAll;
796
- undef $tagInfo; # just skip the Cluster when -ee is used
797
- } else {
798
- $$et{INDENT} .= '| ';
799
- $et->VerboseDir($$tagTablePtr{$tag}{Name}, undef, $size);
800
- push @dirEnd, [ $pos + $dataPos + $size, $$tagInfo{Name} ];
801
- if ($$tagInfo{Name} eq 'ChapterAtom') {
802
- $$et{SET_GROUP1} = 'Chapter' . (++$chapterNum);
803
- $trackIndent = $$et{INDENT};
999
+ if ($tagInfo) {
1000
+ if ($$tagInfo{SubDirectory}) {
1001
+ # stop processing at first cluster unless we are using -v -U or -ee
1002
+ if ($$tagInfo{Name} eq 'Cluster' and $processAll < 2) {
1003
+ last unless $processAll;
1004
+ undef $tagInfo; # just skip the Cluster when -ee is used
1005
+ } else {
1006
+ $$et{INDENT} .= '| ';
1007
+ $et->VerboseDir($$tagTablePtr{$tag}{Name}, undef, $size);
1008
+ $dirName = $$tagInfo{Name};
1009
+ push @dirEnd, [ $pos + $dataPos + $size, $dirName, $struct ];
1010
+ $struct = { } if $dirName eq 'SimpleTag'; # keep track of SimpleTag elements
1011
+ if ($$tagInfo{Name} eq 'ChapterAtom') {
1012
+ $$et{SET_GROUP1} = 'Chapter' . (++$chapterNum);
1013
+ $trackIndent = $$et{INDENT};
1014
+ }
1015
+ next;
804
1016
  }
805
- next;
806
1017
  }
1018
+ } elsif ($verbose) {
1019
+ $et->VPrint(0,sprintf("$$et{INDENT}- Tag 0x%x (Unknown, %d bytes)\n", $tag, $size));
807
1020
  }
808
1021
  last if $unknownSize;
809
1022
  if ($pos + $size > $dataLen) {
@@ -887,8 +1100,9 @@ sub ProcessMKV($$)
887
1100
  Start => $pos,
888
1101
  Size => $size,
889
1102
  );
890
- if ($$tagInfo{NoSave}) {
1103
+ if ($$tagInfo{NoSave} or $struct) {
891
1104
  $et->VerboseInfo($tag, $tagInfo, Value => $val, %parms) if $verbose;
1105
+ $$struct{$$tagInfo{Name}} = $val if $struct;
892
1106
  } else {
893
1107
  $et->HandleTag($tagTablePtr, $tag, $val, %parms);
894
1108
  }
@@ -937,6 +1151,8 @@ under the same terms as Perl itself.
937
1151
 
938
1152
  =item L<http://www.matroska.org/technical/specs/index.html>
939
1153
 
1154
+ =item L<https://www.matroska.org/technical/tagging.html>
1155
+
940
1156
  =back
941
1157
 
942
1158
  =head1 SEE ALSO