Skip to content

Commit d1f153d

Browse files
committed
chore: improve list command time calculations
1 parent 3831c23 commit d1f153d

File tree

1 file changed

+105
-117
lines changed

1 file changed

+105
-117
lines changed

cmd/mkc/internal/list/list.go

Lines changed: 105 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,38 @@ func run(flags *flag.FlagSet) {
8383
}
8484
}
8585

86+
type queueCallbacker struct {
87+
el ebml.Element
88+
c listCallbacker
89+
90+
queue []func(v listCallbacker, ctx context.Context) listCallbacker
91+
}
92+
93+
func (c queueCallbacker) Found(el ebml.Element, offset int64, headerSize int) ebml.Callbacker {
94+
f := func(cc listCallbacker, ctx context.Context) listCallbacker {
95+
return cc.found(el, offset, headerSize, ctx)
96+
}
97+
c.queue = append(c.queue, f)
98+
return c
99+
}
100+
101+
func (c queueCallbacker) Decoded(el ebml.Element, offset int64, headerSize int, val any) ebml.Callbacker {
102+
if c.el.ID != el.ID {
103+
f := func(cc listCallbacker, ctx context.Context) listCallbacker {
104+
return cc.decode(el, offset, headerSize, val, ctx)
105+
}
106+
107+
c.queue = append(c.queue, f)
108+
return c
109+
}
110+
ctx := context.WithValue(context.Background(), el.ID, val)
111+
112+
for _, f := range c.queue {
113+
c.c = f(c.c, ctx)
114+
}
115+
return c.c
116+
}
117+
86118
type listCallbacker struct {
87119
w io.Writer
88120
s *matroska.Scanner
@@ -93,177 +125,138 @@ type listCallbacker struct {
93125
showPosition bool
94126
showSize bool
95127
showDataSize bool
96-
97-
queueEnabled bool
98-
queue []func(v listCallbacker, ctx context.Context) listCallbacker
99128
}
100129

101-
func (v listCallbacker) Found(el ebml.Element, offset int64, headerSize int) ebml.Callbacker {
102-
callCtx := context.Background()
130+
func (c listCallbacker) Found(el ebml.Element, offset int64, headerSize int) ebml.Callbacker {
131+
startQueue := false
103132

104133
switch el.ID {
105134
case matroska.IDBlockGroup:
106-
v.queueEnabled = true
135+
startQueue = true
107136
}
108137

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())
138+
if startQueue {
139+
return queueCallbacker{el: el, c: c}.Found(el, offset, headerSize)
121140
}
122141

123-
return v
142+
return c.found(el, offset, headerSize, context.Background())
124143
}
125144

126-
func (v listCallbacker) found(el ebml.Element, offset int64, headerSize int, ctx context.Context) listCallbacker {
145+
func (c listCallbacker) found(el ebml.Element, offset int64, headerSize int, ctx context.Context) listCallbacker {
127146
sch := el.Schema
128147

129-
v.printer.Sub(offset)
130-
v.suffix.Reset()
148+
c.printer.Sub(offset)
149+
c.suffix.Reset()
131150

132-
if v.showPosition {
133-
fmt.Fprintf(&v.suffix, ", at %d", offset)
151+
if c.showPosition {
152+
fmt.Fprintf(&c.suffix, ", at %d", offset)
134153
}
135-
if v.showSize {
154+
if c.showSize {
136155
if el.DataSize == -1 {
137-
fmt.Fprint(&v.suffix, ", size unknown")
156+
fmt.Fprint(&c.suffix, ", size unknown")
138157
} else {
139-
fmt.Fprintf(&v.suffix, ", size %d", int64(headerSize)+el.DataSize)
158+
fmt.Fprintf(&c.suffix, ", size %d", int64(headerSize)+el.DataSize)
140159
}
141160
}
142-
if v.showDataSize {
161+
if c.showDataSize {
143162
if el.DataSize == -1 {
144-
fmt.Fprint(&v.suffix, ", data size unknown")
163+
fmt.Fprint(&c.suffix, ", data size unknown")
145164
} else {
146-
fmt.Fprintf(&v.suffix, ", data size %d", el.DataSize)
165+
fmt.Fprintf(&c.suffix, ", data size %d", el.DataSize)
147166
}
148167
}
149168

150169
switch el.ID {
151170
default:
152171
if sch.Type != ebml.TypeMaster {
153-
return v
172+
return c
154173
}
155-
v.printer.Printf("%s%s", sch.Name, v.suffix.String())
174+
c.printer.Printf("%s%s", sch.Name, c.suffix.String())
156175
}
157176

158177
if el.DataSize > -1 {
159178
absoluteEnd := offset + int64(headerSize) + el.DataSize
160-
v.printer.Add(absoluteEnd)
179+
c.printer.Add(absoluteEnd)
161180
} else {
162-
v.printer.Add(-1)
181+
c.printer.Add(-1)
163182
}
164183

165-
return v
184+
return c
166185
}
167186

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
187+
func (c listCallbacker) Decoded(el ebml.Element, offset int64, headerSize int, val any) ebml.Callbacker {
188+
return c.decode(el, offset, headerSize, val, context.Background())
193189
}
194190

195-
func (v listCallbacker) decode(el ebml.Element, offset int64, headerSize int, val any, ctx context.Context) listCallbacker {
191+
func (c listCallbacker) decode(el ebml.Element, offset int64, headerSize int, val any, ctx context.Context) listCallbacker {
196192
sch := el.Schema
197193
if sch.Type == ebml.TypeMaster {
198-
return v
194+
return c
199195
}
200196

201-
v.printer.Sub(offset)
202-
v.suffix.Reset()
197+
c.printer.Sub(offset)
198+
c.suffix.Reset()
203199

204-
if v.showPosition {
205-
fmt.Fprintf(&v.suffix, ", at %d", offset)
200+
if c.showPosition {
201+
fmt.Fprintf(&c.suffix, ", at %d", offset)
206202
}
207-
if v.showSize {
203+
if c.showSize {
208204
if el.DataSize == -1 {
209-
fmt.Fprint(&v.suffix, ", size unknown")
205+
fmt.Fprint(&c.suffix, ", size unknown")
210206
} else {
211-
fmt.Fprintf(&v.suffix, ", size %d", int64(headerSize)+el.DataSize)
207+
fmt.Fprintf(&c.suffix, ", size %d", int64(headerSize)+el.DataSize)
212208
}
213209
}
214-
if v.showDataSize {
210+
if c.showDataSize {
215211
if el.DataSize == -1 {
216-
fmt.Fprint(&v.suffix, ", data size unknown")
212+
fmt.Fprint(&c.suffix, ", data size unknown")
217213
} else {
218-
fmt.Fprintf(&v.suffix, ", data size %d", el.DataSize)
214+
fmt.Fprintf(&c.suffix, ", data size %d", el.DataSize)
219215
}
220216
}
221217

222218
switch el.ID {
223219
default:
224220
switch sch.Type {
225221
default:
226-
v.printer.Print("unexpected element ", el.ID)
222+
c.printer.Print("unexpected element ", el.ID)
227223
case ebml.TypeBinary:
228-
v.printer.Printf("%s%s", sch.Name, v.suffix.String())
224+
c.printer.Printf("%s%s", sch.Name, c.suffix.String())
229225
case ebml.TypeString:
230-
v.printer.Printf("%s: %s%s", sch.Name, val, v.suffix.String())
226+
c.printer.Printf("%s: %s%s", sch.Name, val, c.suffix.String())
231227
case ebml.TypeUTF8:
232-
v.printer.Printf("%s: %s%s", sch.Name, val, v.suffix.String())
228+
c.printer.Printf("%s: %s%s", sch.Name, val, c.suffix.String())
233229
case ebml.TypeUinteger:
234-
v.printer.Printf("%s: %d%s", sch.Name, val, v.suffix.String())
230+
c.printer.Printf("%s: %d%s", sch.Name, val, c.suffix.String())
235231
case ebml.TypeInteger:
236-
v.printer.Printf("%s: %d%s", sch.Name, val, v.suffix.String())
232+
c.printer.Printf("%s: %d%s", sch.Name, val, c.suffix.String())
237233
case ebml.TypeFloat:
238-
v.printer.Printf("%s: %f%s", sch.Name, val, v.suffix.String())
234+
c.printer.Printf("%s: %f%s", sch.Name, val, c.suffix.String())
239235
case ebml.TypeDate:
240-
v.printer.Printf("%s: %s%s", sch.Name, val, v.suffix.String())
236+
c.printer.Printf("%s: %s%s", sch.Name, val, c.suffix.String())
241237
}
242238

243-
case matroska.IDBlockGroup:
244-
v.queueEnabled = true
245-
246239
case matroska.IDDuration:
247240
// https://www.ietf.org/archive/id/draft-ietf-cellar-matroska-21.html#name-segment-ticks
248-
timestampScale := v.s.Info().TimestampScale
241+
timestampScale := c.s.Info().TimestampScale
249242
// Stored as a float for some reason
250243
f := val.(float64)
251244
d := time.Duration(int64(f * float64(timestampScale)))
252-
v.printer.Printf("%s: %v%s", sch.Name, d, v.suffix.String())
245+
c.printer.Printf("%s: %v%s", sch.Name, d, c.suffix.String())
253246
case matroska.IDTimestamp, matroska.IDCueDuration:
254247
// https://www.ietf.org/archive/id/draft-ietf-cellar-matroska-21.html#name-segment-ticks
255-
timestampScale := v.s.Info().TimestampScale
248+
timestampScale := c.s.Info().TimestampScale
256249
i := val.(time.Duration)
257250
d := i * timestampScale
258-
v.printer.Printf("%s: %v%s", sch.Name, d, v.suffix.String())
251+
c.printer.Printf("%s: %v%s", sch.Name, d, c.suffix.String())
259252
case matroska.IDSeekID:
260253
def, _ := ebml.Definition(matroska.DocType)
261254
i := val.(schema.ElementID)
262255
seekSch, _ := def.Get(i)
263-
v.printer.Printf("%s: %v %s%s", sch.Name, i, seekSch.Name, v.suffix.String())
256+
c.printer.Printf("%s: %v %s%s", sch.Name, i, seekSch.Name, c.suffix.String())
264257
case matroska.IDBlockDuration, matroska.IDReferenceBlock:
265258
// https://www.ietf.org/archive/id/draft-ietf-cellar-matroska-21.html#name-track-ticks
266-
timestampScale := v.s.Info().TimestampScale
259+
timestampScale := c.s.Info().TimestampScale
267260
blockGroup := ctx.Value(matroska.IDBlockGroup).(matroska.BlockGroup)
268261
block, _ := matroska.ReadBlock(blockGroup.Block, timestampScale)
269262

@@ -278,70 +271,65 @@ func (v listCallbacker) decode(el ebml.Element, offset int64, headerSize int, va
278271
}
279272
// TODO: validate if this would work. I may need the whole BlockGroup.
280273
trackTimestampScale := 1.0
281-
for _, te := range v.s.Tracks().TrackEntry {
274+
for _, te := range c.s.Tracks().TrackEntry {
282275
if te.TrackNumber == block.TrackNumber() {
283276
trackTimestampScale = te.TrackTimestampScale
284277
break
285278
}
286279
}
287280
d := time.Duration(float64(i) * float64(timestampScale) * trackTimestampScale)
288-
v.printer.Printf("%s: %s%s", sch.Name, d, v.suffix.String())
281+
c.printer.Printf("%s: %s%s", sch.Name, d, c.suffix.String())
289282
case matroska.IDBlock:
290283
// https://www.ietf.org/archive/id/draft-ietf-cellar-matroska-21.html#name-block-structure
291-
timestampScale := v.s.Info().TimestampScale
292-
blockGroup := ctx.Value(matroska.IDBlockGroup).(matroska.BlockGroup)
284+
timestampScale := c.s.Info().TimestampScale
285+
cluster := c.s.Cluster()
286+
codecDelay := time.Duration(0)
293287

294288
b := val.([]byte)
295-
block, _ := matroska.ReadBlock(b, timestampScale)
289+
block, _ := matroska.ReadBlock(b, cluster.Timestamp)
296290
frames := block.Frames()
297291

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-
}
292+
for _, te := range c.s.Tracks().TrackEntry {
293+
if te.TrackNumber == block.TrackNumber() {
294+
timestampScale = time.Duration(te.TrackTimestampScale * float64(timestampScale))
295+
codecDelay = time.Duration(te.CodecDelay)
296+
break
309297
}
310298
}
311299

312-
v.printer.Printf("%s: track number %d, %d frame(s), timestamp %v%s", sch.Name,
313-
block.TrackNumber(), len(frames), blockDuration*timestampScale, v.suffix.String())
314-
v.printer.Add(1)
300+
c.printer.Printf("%s: track number %d, %d frame(s), timestamp %v%s", sch.Name,
301+
block.TrackNumber(), len(frames), block.Timestamp(timestampScale)-codecDelay, c.suffix.String())
302+
c.printer.Add(1)
315303
frameOffset := offset + int64(headerSize) + el.DataSize
316304
for _, f := range frames {
317305
frameOffset -= int64(len(f))
318306
}
319307
for _, f := range frames {
320-
v.printer.Printf("Frame at %d size %d", frameOffset, len(f)) // TODO: incorrect at the moment
308+
c.printer.Printf("Frame at %d size %d", frameOffset, len(f)) // TODO: incorrect at the moment
321309
frameOffset += int64(len(f))
322310
}
323-
v.printer.Sub(1)
311+
c.printer.Sub(1)
324312
case matroska.IDSimpleBlock:
325313
// https://www.ietf.org/archive/id/draft-ietf-cellar-matroska-21.html#name-simpleblock-structure
326-
timestampScale := v.s.Info().TimestampScale
314+
timestampScale := c.s.Info().TimestampScale
327315
b := val.([]byte)
328316
block, _ := matroska.ReadSimpleBlock(b, timestampScale)
329317
frames := block.Frames()
330-
v.printer.Printf("%s: track number %d, %d frame(s), timestamp %v%s", sch.Name,
331-
block.TrackNumber(), len(frames), 0*timestampScale, v.suffix.String())
332-
v.printer.Add(1)
318+
c.printer.Printf("%s: track number %d, %d frame(s), timestamp %v%s", sch.Name,
319+
block.TrackNumber(), len(frames), 0*timestampScale, c.suffix.String())
320+
c.printer.Add(1)
333321
frameOffset := offset + int64(headerSize) + el.DataSize
334322
for _, f := range frames {
335323
frameOffset -= int64(len(f))
336324
}
337325
for _, f := range frames {
338-
v.printer.Printf("Frame at %d size %d", frameOffset, len(f)) // TODO: incorrect at the moment
326+
c.printer.Printf("Frame at %d size %d", frameOffset, len(f)) // TODO: incorrect at the moment
339327
frameOffset += int64(len(f))
340328
}
341-
v.printer.Sub(1)
329+
c.printer.Sub(1)
342330
}
343331

344-
return v
332+
return c
345333
}
346334

347335
type indentedPrinter struct {

0 commit comments

Comments
 (0)