Skip to content

Commit 9a3bbda

Browse files
authored
playback: fix error 404 when seeking before start of segment (#4276) (#4533) (#4539)
Fixes #4276 Replaces #4533
1 parent 6c8bf4f commit 9a3bbda

File tree

5 files changed

+325
-177
lines changed

5 files changed

+325
-177
lines changed

internal/playback/muxer_fmp4.go

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66

77
"github.com/bluenviron/mediacommon/v2/pkg/formats/fmp4"
88
"github.com/bluenviron/mediacommon/v2/pkg/formats/fmp4/seekablebuffer"
9+
"github.com/bluenviron/mediamtx/internal/recordstore"
910
)
1011

1112
const (
@@ -75,7 +76,7 @@ func (w *muxerFMP4) writeSample(
7576

7677
// if sample is a IDR, remove previous GOP
7778
if !isNonSyncSample {
78-
w.curTrack.samples = nil
79+
w.curTrack.samples = w.curTrack.samples[:0]
7980
}
8081
} else {
8182
diff := dts - w.curTrack.lastDTS
@@ -103,10 +104,11 @@ func (w *muxerFMP4) writeSample(
103104
} else {
104105
if !isNonSyncSample { // sample is IDR
105106
// reset GOP
106-
w.curTrack.samples = []*fmp4.Sample{{
107+
w.curTrack.samples = w.curTrack.samples[:0]
108+
w.curTrack.samples = append(w.curTrack.samples, &fmp4.Sample{
107109
IsNonSyncSample: isNonSyncSample,
108110
Payload: pl,
109-
}}
111+
})
110112
} else { // sample is not IDR
111113
// append sample to current GOP, with PTSOffset = 0 and Duration = 0
112114
w.curTrack.samples = append(w.curTrack.samples, &fmp4.Sample{
@@ -120,7 +122,7 @@ func (w *muxerFMP4) writeSample(
120122
}
121123

122124
func (w *muxerFMP4) writeFinalDTS(dts int64) {
123-
if w.curTrack.firstDTS >= 0 {
125+
if len(w.curTrack.samples) != 0 && w.curTrack.firstDTS >= 0 {
124126
diff := dts - w.curTrack.lastDTS
125127
if diff < 0 {
126128
diff = 0
@@ -156,26 +158,20 @@ func (w *muxerFMP4) innerFlush(final bool) error {
156158
}
157159
}
158160

159-
if part.Tracks != nil {
160-
part.SequenceNumber = w.nextSequenceNumber
161-
w.nextSequenceNumber++
162-
161+
// no samples to write
162+
if part.Tracks == nil {
163+
// if no samples has been written before, return an error
163164
if w.init != nil {
164-
err := w.init.Marshal(&w.outBuf)
165-
if err != nil {
166-
return err
167-
}
168-
169-
_, err = w.w.Write(w.outBuf.Bytes())
170-
if err != nil {
171-
return err
172-
}
173-
174-
w.init = nil
175-
w.outBuf.Reset()
165+
return recordstore.ErrNoSegmentsFound
176166
}
167+
return nil
168+
}
169+
170+
part.SequenceNumber = w.nextSequenceNumber
171+
w.nextSequenceNumber++
177172

178-
err := part.Marshal(&w.outBuf)
173+
if w.init != nil {
174+
err := w.init.Marshal(&w.outBuf)
179175
if err != nil {
180176
return err
181177
}
@@ -185,9 +181,22 @@ func (w *muxerFMP4) innerFlush(final bool) error {
185181
return err
186182
}
187183

184+
w.init = nil
188185
w.outBuf.Reset()
189186
}
190187

188+
err := part.Marshal(&w.outBuf)
189+
if err != nil {
190+
return err
191+
}
192+
193+
_, err = w.w.Write(w.outBuf.Bytes())
194+
if err != nil {
195+
return err
196+
}
197+
198+
w.outBuf.Reset()
199+
191200
return nil
192201
}
193202

internal/playback/muxer_mp4.go

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55

66
"github.com/bluenviron/mediacommon/v2/pkg/formats/fmp4"
77
"github.com/bluenviron/mediacommon/v2/pkg/formats/pmp4"
8+
"github.com/bluenviron/mediamtx/internal/recordstore"
89
)
910

1011
type muxerMP4Track struct {
@@ -55,17 +56,17 @@ func (w *muxerMP4) writeSample(
5556
) error {
5657
// remove GOPs before the GOP of the first sample
5758
if (dts < 0 || (dts >= 0 && w.curTrack.lastDTS < 0)) && !isNonSyncSample {
58-
w.curTrack.Samples = nil
59+
w.curTrack.Samples = w.curTrack.Samples[:0]
5960
}
6061

61-
if w.curTrack.Samples == nil {
62+
if len(w.curTrack.Samples) == 0 {
6263
w.curTrack.TimeOffset = int32(dts)
6364
} else {
64-
diff := dts - w.curTrack.lastDTS
65-
if diff < 0 {
66-
diff = 0
65+
duration := dts - w.curTrack.lastDTS
66+
if duration < 0 {
67+
duration = 0
6768
}
68-
w.curTrack.Samples[len(w.curTrack.Samples)-1].Duration = uint32(diff)
69+
w.curTrack.Samples[len(w.curTrack.Samples)-1].Duration = uint32(duration)
6970
}
7071

7172
// prevent warning "edit list: 1 Missing key frame while searching for timestamp: 0"
@@ -85,14 +86,20 @@ func (w *muxerMP4) writeSample(
8586
}
8687

8788
func (w *muxerMP4) writeFinalDTS(dts int64) {
88-
diff := dts - w.curTrack.lastDTS
89-
if diff < 0 {
90-
diff = 0
89+
if len(w.curTrack.Samples) != 0 {
90+
duration := dts - w.curTrack.lastDTS
91+
if duration < 0 {
92+
duration = 0
93+
}
94+
w.curTrack.Samples[len(w.curTrack.Samples)-1].Duration = uint32(duration)
9195
}
92-
w.curTrack.Samples[len(w.curTrack.Samples)-1].Duration = uint32(diff)
9396
}
9497

9598
func (w *muxerMP4) flush() error {
99+
if len(w.curTrack.Samples) == 0 || w.curTrack.lastDTS < 0 {
100+
return recordstore.ErrNoSegmentsFound
101+
}
102+
96103
h := pmp4.Presentation{
97104
Tracks: make([]*pmp4.Track, len(w.tracks)),
98105
}

internal/playback/on_get.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ func seekAndMux(
6464

6565
m.writeInit(firstInit)
6666

67-
segmentStartOffset := start.Sub(segments[0].Start)
67+
segmentStartOffset := segments[0].Start.Sub(start) // this is negative
6868

69-
segmentDuration, err := segmentFMP4SeekAndMuxParts(f, segmentStartOffset, duration, firstInit, m)
69+
segmentDuration, err := segmentFMP4MuxParts(f, segmentStartOffset, duration, firstInit, m)
7070
if err != nil {
7171
return err
7272
}
@@ -90,7 +90,7 @@ func seekAndMux(
9090
break
9191
}
9292

93-
segmentStartOffset := seg.Start.Sub(start)
93+
segmentStartOffset := seg.Start.Sub(start) // this is positive
9494

9595
var segmentDuration time.Duration
9696
segmentDuration, err = segmentFMP4MuxParts(f, segmentStartOffset, duration, firstInit, m)

0 commit comments

Comments
 (0)