@@ -2,6 +2,7 @@ package list
22
33import (
44 "bytes"
5+ "context"
56 "errors"
67 "fmt"
78 "github.com/charmbracelet/huh"
@@ -60,7 +61,7 @@ func run(flags *flag.FlagSet) {
6061 r := io .MultiReader (f ) // remove seeking capability
6162 s := matroska .NewScanner (r )
6263
63- v := printVisitor {
64+ v := listCallbacker {
6465 w : os .Stdout ,
6566 s : s ,
6667
@@ -70,7 +71,7 @@ func run(flags *flag.FlagSet) {
7071 showSize : * flagSize || * flagVerbose ,
7172 showDataSize : * flagDataSize || * flagVerbose ,
7273 }
73- s .Decoder ().SetVisitor (v )
74+ s .Decoder ().SetCallback (v )
7475
7576 if err := s .Init (); err != nil {
7677 fmt .Fprint (os .Stderr , err )
@@ -82,7 +83,7 @@ func run(flags *flag.FlagSet) {
8283 }
8384}
8485
85- type printVisitor struct {
86+ type listCallbacker struct {
8687 w io.Writer
8788 s * matroska.Scanner
8889
@@ -92,13 +93,40 @@ type printVisitor struct {
9293 showPosition bool
9394 showSize bool
9495 showDataSize bool
96+
97+ queueEnabled bool
98+ queue []func (v listCallbacker , ctx context.Context ) listCallbacker
99+ }
100+
101+ func (v listCallbacker ) Found (el ebml.Element , offset int64 , headerSize int ) ebml.Callbacker {
102+ callCtx := context .Background ()
103+
104+ switch el .ID {
105+ case matroska .IDBlockGroup :
106+ v .queueEnabled = true
107+ }
108+
109+ f := func (v listCallbacker , ctx context.Context ) listCallbacker {
110+ return v .found (el , offset , headerSize , ctx )
111+ }
112+
113+ if v .queueEnabled {
114+ v .queue = append (v .queue , f )
115+ } else {
116+ for _ , ff := range v .queue {
117+ v = ff (v , callCtx )
118+ }
119+ v .queue = nil
120+ v = f (v , context .Background ())
121+ }
122+
123+ return v
95124}
96125
97- func (v printVisitor ) Visit (el ebml.Element , offset int64 , headerSize int , val any ) ( w ebml. Visitor ) {
126+ func (v listCallbacker ) found (el ebml.Element , offset int64 , headerSize int , ctx context. Context ) listCallbacker {
98127 sch := el .Schema
99128
100129 v .printer .Sub (offset )
101-
102130 v .suffix .Reset ()
103131
104132 if v .showPosition {
@@ -119,15 +147,83 @@ func (v printVisitor) Visit(el ebml.Element, offset int64, headerSize int, val a
119147 }
120148 }
121149
122- var lastTrackNumber uint = 0
150+ switch el .ID {
151+ default :
152+ if sch .Type != ebml .TypeMaster {
153+ return v
154+ }
155+ v .printer .Printf ("%s%s" , sch .Name , v .suffix .String ())
156+ }
157+
158+ if el .DataSize > - 1 {
159+ absoluteEnd := offset + int64 (headerSize ) + el .DataSize
160+ v .printer .Add (absoluteEnd )
161+ } else {
162+ v .printer .Add (- 1 )
163+ }
164+
165+ return v
166+ }
167+
168+ func (v listCallbacker ) Decoded (el ebml.Element , offset int64 , headerSize int , val any ) ebml.Callbacker {
169+ callCtx := context .Background ()
170+
171+ switch el .ID {
172+ case matroska .IDBlockGroup :
173+ v .queueEnabled = false
174+
175+ callCtx = context .WithValue (callCtx , el .ID , val )
176+ }
177+
178+ f := func (v listCallbacker , ctx context.Context ) listCallbacker {
179+ return v .decode (el , offset , headerSize , val , ctx )
180+ }
181+
182+ if v .queueEnabled {
183+ v .queue = append (v .queue , f )
184+ } else {
185+ for _ , ff := range v .queue {
186+ v = ff (v , callCtx )
187+ }
188+ v .queue = nil
189+ v = f (v , callCtx )
190+ }
191+
192+ return v
193+ }
194+
195+ func (v listCallbacker ) decode (el ebml.Element , offset int64 , headerSize int , val any , ctx context.Context ) listCallbacker {
196+ sch := el .Schema
197+ if sch .Type == ebml .TypeMaster {
198+ return v
199+ }
200+
201+ v .printer .Sub (offset )
202+ v .suffix .Reset ()
203+
204+ if v .showPosition {
205+ fmt .Fprintf (& v .suffix , ", at %d" , offset )
206+ }
207+ if v .showSize {
208+ if el .DataSize == - 1 {
209+ fmt .Fprint (& v .suffix , ", size unknown" )
210+ } else {
211+ fmt .Fprintf (& v .suffix , ", size %d" , int64 (headerSize )+ el .DataSize )
212+ }
213+ }
214+ if v .showDataSize {
215+ if el .DataSize == - 1 {
216+ fmt .Fprint (& v .suffix , ", data size unknown" )
217+ } else {
218+ fmt .Fprintf (& v .suffix , ", data size %d" , el .DataSize )
219+ }
220+ }
123221
124222 switch el .ID {
125223 default :
126224 switch sch .Type {
127225 default :
128226 v .printer .Print ("unexpected element " , el .ID )
129- case ebml .TypeMaster :
130- v .printer .Printf ("%s%s" , sch .Name , v .suffix .String ())
131227 case ebml .TypeBinary :
132228 v .printer .Printf ("%s%s" , sch .Name , v .suffix .String ())
133229 case ebml .TypeString :
@@ -143,6 +239,10 @@ func (v printVisitor) Visit(el ebml.Element, offset int64, headerSize int, val a
143239 case ebml .TypeDate :
144240 v .printer .Printf ("%s: %s%s" , sch .Name , val , v .suffix .String ())
145241 }
242+
243+ case matroska .IDBlockGroup :
244+ v .queueEnabled = true
245+
146246 case matroska .IDDuration :
147247 // https://www.ietf.org/archive/id/draft-ietf-cellar-matroska-21.html#name-segment-ticks
148248 timestampScale := v .s .Info ().TimestampScale
@@ -164,6 +264,9 @@ func (v printVisitor) Visit(el ebml.Element, offset int64, headerSize int, val a
164264 case matroska .IDBlockDuration , matroska .IDReferenceBlock :
165265 // https://www.ietf.org/archive/id/draft-ietf-cellar-matroska-21.html#name-track-ticks
166266 timestampScale := v .s .Info ().TimestampScale
267+ blockGroup := ctx .Value (matroska .IDBlockGroup ).(matroska.BlockGroup )
268+ block , _ := matroska .ReadBlock (blockGroup .Block , timestampScale )
269+
167270 var i int64
168271 switch v := val .(type ) {
169272 default :
@@ -176,7 +279,7 @@ func (v printVisitor) Visit(el ebml.Element, offset int64, headerSize int, val a
176279 // TODO: validate if this would work. I may need the whole BlockGroup.
177280 trackTimestampScale := 1.0
178281 for _ , te := range v .s .Tracks ().TrackEntry {
179- if te .TrackNumber == lastTrackNumber {
282+ if te .TrackNumber == block . TrackNumber () {
180283 trackTimestampScale = te .TrackTimestampScale
181284 break
182285 }
@@ -186,10 +289,26 @@ func (v printVisitor) Visit(el ebml.Element, offset int64, headerSize int, val a
186289 case matroska .IDBlock :
187290 // https://www.ietf.org/archive/id/draft-ietf-cellar-matroska-21.html#name-block-structure
188291 timestampScale := v .s .Info ().TimestampScale
292+ blockGroup := ctx .Value (matroska .IDBlockGroup ).(matroska.BlockGroup )
293+
189294 b := val .([]byte )
190295 block , _ := matroska .ReadBlock (b , timestampScale )
191296 frames := block .Frames ()
192- blockDuration := time .Second // TODO: get proper value
297+
298+ blockDuration := time .Second
299+ if blockGroup .BlockDuration != nil {
300+ blockDuration = time .Duration (* blockGroup .BlockDuration )
301+ } else {
302+ for _ , te := range v .s .Tracks ().TrackEntry {
303+ if te .TrackNumber == block .TrackNumber () {
304+ if te .DefaultDuration != nil {
305+ blockDuration = time .Duration (* te .DefaultDuration )
306+ }
307+ break
308+ }
309+ }
310+ }
311+
193312 v .printer .Printf ("%s: track number %d, %d frame(s), timestamp %v%s" , sch .Name ,
194313 block .TrackNumber (), len (frames ), blockDuration * timestampScale , v .suffix .String ())
195314 v .printer .Add (1 )
@@ -202,8 +321,6 @@ func (v printVisitor) Visit(el ebml.Element, offset int64, headerSize int, val a
202321 frameOffset += int64 (len (f ))
203322 }
204323 v .printer .Sub (1 )
205-
206- lastTrackNumber = block .TrackNumber ()
207324 case matroska .IDSimpleBlock :
208325 // https://www.ietf.org/archive/id/draft-ietf-cellar-matroska-21.html#name-simpleblock-structure
209326 timestampScale := v .s .Info ().TimestampScale
@@ -224,15 +341,6 @@ func (v printVisitor) Visit(el ebml.Element, offset int64, headerSize int, val a
224341 v .printer .Sub (1 )
225342 }
226343
227- if sch .Type == ebml .TypeMaster {
228- if el .DataSize > - 1 {
229- absoluteEnd := offset + int64 (headerSize ) + el .DataSize
230- v .printer .Add (absoluteEnd )
231- } else {
232- v .printer .Add (- 1 )
233- }
234- }
235-
236344 return v
237345}
238346
0 commit comments