mirror of
https://github.com/bluenviron/mediamtx.git
synced 2025-12-20 02:00:05 -08:00
when requesting a recording with the mp4 format, if there are two tracks and the second track has no sample, the server crashed. This fixes the issue.
109 lines
2.3 KiB
Go
109 lines
2.3 KiB
Go
package playback
|
|
|
|
import (
|
|
"io"
|
|
|
|
"github.com/bluenviron/mediacommon/v2/pkg/formats/fmp4"
|
|
"github.com/bluenviron/mediacommon/v2/pkg/formats/pmp4"
|
|
"github.com/bluenviron/mediamtx/internal/recordstore"
|
|
)
|
|
|
|
type muxerMP4Track struct {
|
|
pmp4.Track
|
|
lastDTS int64
|
|
}
|
|
|
|
func findTrackMP4(tracks []*muxerMP4Track, id int) *muxerMP4Track {
|
|
for _, track := range tracks {
|
|
if track.ID == id {
|
|
return track
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type muxerMP4 struct {
|
|
w io.Writer
|
|
|
|
tracks []*muxerMP4Track
|
|
curTrack *muxerMP4Track
|
|
}
|
|
|
|
func (w *muxerMP4) writeInit(init *fmp4.Init) {
|
|
w.tracks = make([]*muxerMP4Track, len(init.Tracks))
|
|
|
|
for i, track := range init.Tracks {
|
|
w.tracks[i] = &muxerMP4Track{
|
|
Track: pmp4.Track{
|
|
ID: track.ID,
|
|
TimeScale: track.TimeScale,
|
|
Codec: track.Codec,
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
func (w *muxerMP4) setTrack(trackID int) {
|
|
w.curTrack = findTrackMP4(w.tracks, trackID)
|
|
}
|
|
|
|
func (w *muxerMP4) writeSample(
|
|
dts int64,
|
|
ptsOffset int32,
|
|
isNonSyncSample bool,
|
|
payloadSize uint32,
|
|
getPayload func() ([]byte, error),
|
|
) error {
|
|
// remove GOPs before the GOP of the first sample
|
|
if (dts < 0 || (dts >= 0 && w.curTrack.lastDTS < 0)) && !isNonSyncSample {
|
|
w.curTrack.Samples = w.curTrack.Samples[:0]
|
|
}
|
|
|
|
if len(w.curTrack.Samples) == 0 {
|
|
w.curTrack.TimeOffset = int32(dts)
|
|
} else {
|
|
duration := max(dts-w.curTrack.lastDTS, 0)
|
|
w.curTrack.Samples[len(w.curTrack.Samples)-1].Duration = uint32(duration)
|
|
}
|
|
|
|
// prevent warning "edit list: 1 Missing key frame while searching for timestamp: 0"
|
|
if !isNonSyncSample {
|
|
ptsOffset = 0
|
|
}
|
|
|
|
w.curTrack.Samples = append(w.curTrack.Samples, &pmp4.Sample{
|
|
PTSOffset: ptsOffset,
|
|
IsNonSyncSample: isNonSyncSample,
|
|
PayloadSize: payloadSize,
|
|
GetPayload: getPayload,
|
|
})
|
|
w.curTrack.lastDTS = dts
|
|
|
|
return nil
|
|
}
|
|
|
|
func (w *muxerMP4) writeFinalDTS(dts int64) {
|
|
if len(w.curTrack.Samples) != 0 {
|
|
duration := max(dts-w.curTrack.lastDTS, 0)
|
|
w.curTrack.Samples[len(w.curTrack.Samples)-1].Duration = uint32(duration)
|
|
}
|
|
}
|
|
|
|
func (w *muxerMP4) flush() error {
|
|
if len(w.curTrack.Samples) == 0 || w.curTrack.lastDTS < 0 {
|
|
return recordstore.ErrNoSegmentsFound
|
|
}
|
|
|
|
var tracks []*pmp4.Track
|
|
for _, track := range w.tracks {
|
|
if len(track.Samples) != 0 {
|
|
tracks = append(tracks, &track.Track)
|
|
}
|
|
}
|
|
|
|
h := pmp4.Presentation{
|
|
Tracks: tracks,
|
|
}
|
|
|
|
return h.Marshal(w.w)
|
|
}
|