Skip to content

Commit 457efb6

Browse files
committed
chore: Refactor SegmentTimeline to use one mode to signal all variants
1 parent 873e8d6 commit 457efb6

File tree

6 files changed

+36
-57
lines changed

6 files changed

+36
-57
lines changed

cmd/livesim2/app/configurl.go

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const (
3434
SegTimelineModeNone SegTimelineMode = ""
3535
SegTimelineModeTime SegTimelineMode = "time"
3636
SegTimelineModePattern SegTimelineMode = "pattern"
37+
SegTimelineModeNr SegTimelineMode = "nr"
3738
SegTimelineModeNrPattern SegTimelineMode = "nrpattern"
3839
)
3940

@@ -105,7 +106,6 @@ type ResponseConfig struct {
105106
InsertAdFlag bool `json:"InsertAdFlag,omitempty"`
106107
ContMultiPeriodFlag bool `json:"ContMultiPeriodFlag,omitempty"`
107108
SegTimelineMode SegTimelineMode `json:"SegTimelineMode,omitempty"`
108-
SegTimelineNrFlag bool `json:"SegTimelineNrFlag,omitempty"`
109109
SidxFlag bool `json:"SidxFlag,omitempty"`
110110
SegTimelineLossFlag bool `json:"SegTimelineLossFlag,omitempty"`
111111
AvailabilityTimeCompleteFlag bool `json:"AvailabilityTimeCompleteFlag,omitempty"`
@@ -258,10 +258,10 @@ func NewResponseConfig() *ResponseConfig {
258258
}
259259

260260
func (rc *ResponseConfig) liveMPDType() liveMPDType {
261-
switch {
262-
case rc.SegTimelineMode == SegTimelineModeTime || rc.SegTimelineMode == SegTimelineModePattern:
261+
switch rc.SegTimelineMode {
262+
case SegTimelineModeTime, SegTimelineModePattern:
263263
return timeLineTime
264-
case rc.SegTimelineNrFlag || rc.SegTimelineMode == SegTimelineModeNrPattern:
264+
case SegTimelineModeNr, SegTimelineModeNrPattern:
265265
return timeLineNumber
266266
default:
267267
return segmentNumber
@@ -361,16 +361,22 @@ cfgLoop:
361361
case "continuous": // Only valid when periods_per_hour is set
362362
cfg.ContMultiPeriodFlag = true
363363
case "segtimeline":
364+
if cfg.SegTimelineMode != SegTimelineModeNone {
365+
return nil, fmt.Errorf("SegmentTimeline mode already set to %q", cfg.SegTimelineMode)
366+
}
364367
if val == "pattern" {
365368
cfg.SegTimelineMode = SegTimelineModePattern
366369
} else {
367370
cfg.SegTimelineMode = SegTimelineModeTime
368371
}
369372
case "segtimelinenr":
373+
if cfg.SegTimelineMode != SegTimelineModeNone {
374+
return nil, fmt.Errorf("SegmentTimeline mode already set to %q", cfg.SegTimelineMode)
375+
}
370376
if val == "pattern" {
371377
cfg.SegTimelineMode = SegTimelineModeNrPattern
372378
} else {
373-
cfg.SegTimelineNrFlag = true
379+
cfg.SegTimelineMode = SegTimelineModeNr
374380
}
375381
case "peroff": // Set the period offset
376382
cfg.PeriodOffset = sc.AtoiPtr(key, val)
@@ -440,9 +446,6 @@ func verifyAndFillConfig(cfg *ResponseConfig, nowMS int) error {
440446
if nowMS < 0 {
441447
return fmt.Errorf("nowMS must be >= 0")
442448
}
443-
if cfg.SegTimelineNrFlag && cfg.SegTimelineMode != SegTimelineModeNone {
444-
return fmt.Errorf("SegmentTimelineTime and SegmentTimelineNr cannot be used at same time")
445-
}
446449
if cfg.TimeSubsRegion < 0 || cfg.TimeSubsRegion > 1 {
447450
return fmt.Errorf("timesubsreg number must be 0 or 1")
448451
}

cmd/livesim2/app/configurl_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ func TestProcessURLCfg(t *testing.T) {
168168
nowMS: 0,
169169
contentPart: "",
170170
wantedCfg: nil,
171-
err: "url config: SegmentTimelineTime and SegmentTimelineNr cannot be used at same time",
171+
err: "SegmentTimeline mode already set to \"time\"",
172172
},
173173
{
174174
url: "/livesim2/periods_60/asset.mpd",

cmd/livesim2/app/livempd.go

Lines changed: 15 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -272,15 +272,15 @@ func LiveMPD(a *asset, mpdName string, cfg *ResponseConfig, drmCfg *drm.DrmConfi
272272
}
273273
switch templateType {
274274
case timeLineTime:
275-
err := adjustAdaptationSetForTimelineTime(cfg, se, as)
275+
err := adjustAdaptationSetForTimeline(cfg, se, as)
276276
if err != nil {
277277
return nil, fmt.Errorf("adjustASForTimelineTime: %w", err)
278278
}
279279
if asIdx == 0 {
280280
mpd.PublishTime = m.ConvertToDateTime(calcPublishTime(cfg, se.lsi))
281281
}
282282
case timeLineNumber:
283-
err := adjustAdaptationSetForTimelineNr(cfg, se, as)
283+
err := adjustAdaptationSetForTimeline(cfg, se, as)
284284
if err != nil {
285285
return nil, fmt.Errorf("adjustASForTimelineNr: %w", err)
286286
}
@@ -588,64 +588,41 @@ func setOffsetInAdaptationSet(cfg *ResponseConfig, as *m.AdaptationSetType) (ato
588588
return atoMS, nil
589589
}
590590

591-
func adjustAdaptationSetForTimelineTime(cfg *ResponseConfig, se segEntries, as *m.AdaptationSetType) error {
591+
func adjustAdaptationSetForTimeline(cfg *ResponseConfig, se segEntries, as *m.AdaptationSetType) error {
592592
if as.SegmentTemplate.SegmentTimeline == nil {
593593
as.SegmentTemplate.SegmentTimeline = &m.SegmentTimelineType{}
594594
}
595-
as.SegmentTemplate.StartNumber = nil
595+
596596
as.SegmentTemplate.Duration = nil
597-
as.SegmentTemplate.Media = strings.ReplaceAll(as.SegmentTemplate.Media, "$Number$", "$Time$")
598597
as.SegmentTemplate.Timescale = Ptr(se.mediaTimescale)
599598

600-
// Check if pattern mode is enabled and this is audio
601-
if cfg.SegTimelineMode == SegTimelineModePattern && as.ContentType == "audio" {
602-
// Try to detect and apply pattern based on cyclic alignment
603-
if patternSTL := detectAndApplyPattern(se); patternSTL != nil {
604-
as.SegmentTemplate.SegmentTimeline = patternSTL
605-
// Add EssentialProperty for pattern support
606-
as.EssentialProperties = append(as.EssentialProperties, &m.DescriptorType{
607-
SchemeIdUri: "urn:mpeg:dash:pattern:2024",
608-
})
609-
return nil
610-
}
611-
}
599+
isNumberBased := cfg.SegTimelineMode == SegTimelineModeNr || cfg.SegTimelineMode == SegTimelineModeNrPattern
600+
isPatternBased := cfg.SegTimelineMode == SegTimelineModePattern || cfg.SegTimelineMode == SegTimelineModeNrPattern
612601

613-
// Default: use regular segment entries
614-
as.SegmentTemplate.SegmentTimeline.S = se.entries
615-
return nil
616-
}
617-
618-
func adjustAdaptationSetForTimelineNr(cfg *ResponseConfig, se segEntries, as *m.AdaptationSetType) error {
619-
if as.SegmentTemplate.SegmentTimeline == nil {
620-
as.SegmentTemplate.SegmentTimeline = &m.SegmentTimelineType{}
602+
if isNumberBased {
603+
as.SegmentTemplate.Media = strings.ReplaceAll(as.SegmentTemplate.Media, "$Time$", "$Number$")
604+
if se.startNr >= 0 {
605+
as.SegmentTemplate.StartNumber = Ptr(uint32(se.startNr))
606+
}
607+
} else {
608+
as.SegmentTemplate.Media = strings.ReplaceAll(as.SegmentTemplate.Media, "$Number$", "$Time$")
609+
as.SegmentTemplate.StartNumber = nil
621610
}
622-
as.SegmentTemplate.StartNumber = nil
623-
as.SegmentTemplate.Duration = nil
624-
as.SegmentTemplate.Media = strings.ReplaceAll(as.SegmentTemplate.Media, "$Time$", "$Number$")
625-
as.SegmentTemplate.Timescale = Ptr(se.mediaTimescale)
626611

627-
// Check if pattern mode is enabled and this is audio
628-
if cfg.SegTimelineMode == SegTimelineModeNrPattern && as.ContentType == "audio" {
612+
if as.ContentType == "audio" && isPatternBased {
629613
// Try to detect and apply pattern based on cyclic alignment
630614
if patternSTL := detectAndApplyPattern(se); patternSTL != nil {
631615
as.SegmentTemplate.SegmentTimeline = patternSTL
632616
// Add EssentialProperty for pattern support
633617
as.EssentialProperties = append(as.EssentialProperties, &m.DescriptorType{
634618
SchemeIdUri: "urn:mpeg:dash:pattern:2024",
635619
})
636-
if se.startNr >= 0 {
637-
as.SegmentTemplate.StartNumber = Ptr(uint32(se.startNr))
638-
}
639620
return nil
640621
}
641622
}
642623

643624
// Default: use regular segment entries
644625
as.SegmentTemplate.SegmentTimeline.S = se.entries
645-
646-
if se.startNr >= 0 {
647-
as.SegmentTemplate.StartNumber = Ptr(uint32(se.startNr))
648-
}
649626
return nil
650627
}
651628

cmd/livesim2/app/livempd_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ func TestSegmentTimes(t *testing.T) {
227227
if tc.useTime {
228228
cfg.SegTimelineMode = SegTimelineModeTime
229229
} else {
230-
cfg.SegTimelineNrFlag = true
230+
cfg.SegTimelineMode = SegTimelineModeNr
231231
}
232232
for nowS := tc.startTimeS; nowS < tc.endTimeS; nowS++ {
233233
nowMS := nowS * 1000
@@ -342,7 +342,7 @@ func TestLastAvailableSegment(t *testing.T) {
342342
if tc.segTimelineTime {
343343
cfg.SegTimelineMode = SegTimelineModeTime
344344
} else {
345-
cfg.SegTimelineNrFlag = true
345+
cfg.SegTimelineMode = SegTimelineModeNr
346346
}
347347
cfg.AvailabilityTimeOffsetS = tc.availabilityTimeOffset
348348
if tc.availabilityTimeOffset > 0 && !tc.availabilityTimeComplete {
@@ -759,7 +759,7 @@ func TestAudioSegmentTimeFollowsVideo(t *testing.T) {
759759
case "timelineTime":
760760
cfg.SegTimelineMode = SegTimelineModeTime
761761
case "timelineNumber":
762-
cfg.SegTimelineNrFlag = true
762+
cfg.SegTimelineMode = SegTimelineModeNr
763763
default: // $Number$
764764
// no flag
765765
}
@@ -879,7 +879,7 @@ func TestMultiPeriod(t *testing.T) {
879879
case "timelineTime":
880880
cfg.SegTimelineMode = SegTimelineModeTime
881881
case "timelineNumber":
882-
cfg.SegTimelineNrFlag = true
882+
cfg.SegTimelineMode = SegTimelineModeNr
883883
default: // $Number$
884884
// no flag
885885
}

cmd/livesim2/app/livesegment_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func TestLiveSegment(t *testing.T) {
7575
case "TimelineTime":
7676
cfg.SegTimelineMode = SegTimelineModeTime
7777
case "TimelineNumber":
78-
cfg.SegTimelineNrFlag = true
78+
cfg.SegTimelineMode = SegTimelineModeNr
7979
}
8080
nowMS := 100_000
8181
rr := httptest.NewRecorder()
@@ -171,7 +171,7 @@ func TestCheckAudioSegmentTimeAddressing(t *testing.T) {
171171
case "TimelineTime":
172172
cfg.SegTimelineMode = SegTimelineModeTime
173173
case "TimelineNumber":
174-
cfg.SegTimelineNrFlag = true
174+
cfg.SegTimelineMode = SegTimelineModeNr
175175
}
176176
for nr := c.segNrStart; nr <= c.segNrEnd; nr++ {
177177
mediaTime := calcAudioTimeFromRef(uint64(nr)*c.refSegDur, c.refTimescale, 1024, 48000)
@@ -229,7 +229,7 @@ func TestLiveThumbSegment(t *testing.T) {
229229
case "TimelineTime":
230230
cfg.SegTimelineMode = SegTimelineModeTime
231231
case "TimelineNumber":
232-
cfg.SegTimelineNrFlag = true
232+
cfg.SegTimelineMode = SegTimelineModeNr
233233
}
234234
nowMS := 100_000
235235
media := tc.media
@@ -590,7 +590,7 @@ func TestLLSegmentAvailability(t *testing.T) {
590590
case "TimelineTime":
591591
cfg.SegTimelineMode = SegTimelineModeTime
592592
case "TimelineNumber":
593-
cfg.SegTimelineNrFlag = true
593+
cfg.SegTimelineMode = SegTimelineModeNr
594594
case "Number":
595595
// Nothing
596596
default:
@@ -716,7 +716,7 @@ func TestSegmentStatusCodeResponse(t *testing.T) {
716716
case "TimelineTime":
717717
cfg.SegTimelineMode = SegTimelineModeTime
718718
case "TimelineNumber":
719-
cfg.SegTimelineNrFlag = true
719+
cfg.SegTimelineMode = SegTimelineModeNr
720720
}
721721
cfg.SegStatusCodes = tc.ss
722722
media := strings.ReplaceAll(tc.media, "$NrOrTime$", fmt.Sprintf("%d", tc.nrOrTime))

go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ require (
1818
github.com/prometheus/client_golang v1.21.1
1919
github.com/spf13/pflag v1.0.6
2020
github.com/stretchr/testify v1.10.0
21-
2221
)
2322

2423
require (

0 commit comments

Comments
 (0)