mirror of
https://github.com/bluenviron/mediamtx.git
synced 2025-12-20 02:00:05 -08:00
recorder: prevent FMP4 durations from overflowing (#4711) (#5126)
Some checks are pending
code_lint / go (push) Waiting to run
code_lint / go_mod (push) Waiting to run
code_lint / docs (push) Waiting to run
code_lint / api_docs (push) Waiting to run
code_test / test_64 (push) Waiting to run
code_test / test_32 (push) Waiting to run
code_test / test_e2e (push) Waiting to run
Some checks are pending
code_lint / go (push) Waiting to run
code_lint / go_mod (push) Waiting to run
code_lint / docs (push) Waiting to run
code_lint / api_docs (push) Waiting to run
code_test / test_64 (push) Waiting to run
code_test / test_32 (push) Waiting to run
code_test / test_e2e (push) Waiting to run
The timestamp difference between two samples was put inside an unsigned integer, and, when negative, caused an overflow.
This commit is contained in:
parent
4ff80d773b
commit
c42642ac3c
2 changed files with 108 additions and 3 deletions
|
|
@ -58,7 +58,14 @@ func (t *formatFMP4Track) write(sample *sample) error {
|
||||||
if sample == nil {
|
if sample == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
sample.Duration = uint32(t.nextSample.dts - sample.dts)
|
|
||||||
|
duration := t.nextSample.dts - sample.dts
|
||||||
|
if duration < 0 {
|
||||||
|
t.nextSample.dts = sample.dts
|
||||||
|
duration = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
sample.Duration = uint32(duration)
|
||||||
|
|
||||||
dts := timestampToDuration(sample.dts, int(t.initTrack.TimeScale))
|
dts := timestampToDuration(sample.dts, int(t.initTrack.TimeScale))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -311,7 +311,7 @@ func TestRecorder(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRecorderFMP4NegativeDTS(t *testing.T) {
|
func TestRecorderFMP4NegativeInitialDTS(t *testing.T) {
|
||||||
desc := &description.Session{Medias: []*description.Media{
|
desc := &description.Session{Medias: []*description.Media{
|
||||||
{
|
{
|
||||||
Type: description.MediaTypeVideo,
|
Type: description.MediaTypeVideo,
|
||||||
|
|
@ -398,7 +398,7 @@ func TestRecorderFMP4NegativeDTS(t *testing.T) {
|
||||||
for _, part := range parts {
|
for _, part := range parts {
|
||||||
for _, track := range part.Tracks {
|
for _, track := range part.Tracks {
|
||||||
if track.ID == 2 {
|
if track.ID == 2 {
|
||||||
require.Less(t, track.BaseTime, uint64(1*90000))
|
require.Equal(t, uint64(6615), track.BaseTime)
|
||||||
found = true
|
found = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -407,6 +407,104 @@ func TestRecorderFMP4NegativeDTS(t *testing.T) {
|
||||||
require.True(t, found)
|
require.True(t, found)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRecorderFMP4NegativeDTSDiff(t *testing.T) {
|
||||||
|
desc := &description.Session{Medias: []*description.Media{
|
||||||
|
{
|
||||||
|
Type: description.MediaTypeVideo,
|
||||||
|
Formats: []rtspformat.Format{&rtspformat.MPEG4Audio{
|
||||||
|
PayloadTyp: 96,
|
||||||
|
Config: &mpeg4audio.AudioSpecificConfig{
|
||||||
|
Type: 2,
|
||||||
|
SampleRate: 44100,
|
||||||
|
ChannelCount: 2,
|
||||||
|
},
|
||||||
|
SizeLength: 13,
|
||||||
|
IndexLength: 3,
|
||||||
|
IndexDeltaLength: 3,
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
|
||||||
|
strm := &stream.Stream{
|
||||||
|
WriteQueueSize: 512,
|
||||||
|
RTPMaxPayloadSize: 1450,
|
||||||
|
Desc: desc,
|
||||||
|
GenerateRTPPackets: true,
|
||||||
|
Parent: test.NilLogger,
|
||||||
|
}
|
||||||
|
err := strm.Initialize()
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer strm.Close()
|
||||||
|
|
||||||
|
dir, err := os.MkdirTemp("", "mediamtx-agent")
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
|
recordPath := filepath.Join(dir, "%path/%Y-%m-%d_%H-%M-%S-%f")
|
||||||
|
|
||||||
|
w := &Recorder{
|
||||||
|
PathFormat: recordPath,
|
||||||
|
Format: conf.RecordFormatFMP4,
|
||||||
|
PartDuration: 100 * time.Millisecond,
|
||||||
|
MaxPartSize: 50 * 1024 * 1024,
|
||||||
|
SegmentDuration: 2 * time.Second,
|
||||||
|
PathName: "mypath",
|
||||||
|
Stream: strm,
|
||||||
|
Parent: test.NilLogger,
|
||||||
|
}
|
||||||
|
w.Initialize()
|
||||||
|
|
||||||
|
strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.Unit{
|
||||||
|
PTS: 44100,
|
||||||
|
NTP: time.Date(2008, 5, 20, 22, 15, 25, 0, time.UTC),
|
||||||
|
Payload: unit.PayloadMPEG4Audio{{1, 2}},
|
||||||
|
})
|
||||||
|
|
||||||
|
strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.Unit{
|
||||||
|
PTS: 3 * 44100,
|
||||||
|
NTP: time.Date(2008, 5, 20, 22, 15, 25, 0, time.UTC),
|
||||||
|
Payload: unit.PayloadMPEG4Audio{{1, 2}},
|
||||||
|
})
|
||||||
|
|
||||||
|
strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.Unit{
|
||||||
|
PTS: 2 * 44100,
|
||||||
|
NTP: time.Date(2008, 5, 20, 22, 15, 25, 0, time.UTC),
|
||||||
|
Payload: unit.PayloadMPEG4Audio{{1, 2}},
|
||||||
|
})
|
||||||
|
|
||||||
|
strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.Unit{
|
||||||
|
PTS: 4 * 44100,
|
||||||
|
NTP: time.Date(2008, 5, 20, 22, 15, 25, 0, time.UTC),
|
||||||
|
Payload: unit.PayloadMPEG4Audio{{1, 2}},
|
||||||
|
})
|
||||||
|
|
||||||
|
time.Sleep(50 * time.Millisecond)
|
||||||
|
|
||||||
|
w.Close()
|
||||||
|
|
||||||
|
byts, err := os.ReadFile(filepath.Join(dir, "mypath", "2008-05-20_22-15-25-000000.mp4"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var parts fmp4.Parts
|
||||||
|
err = parts.Unmarshal(byts)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, fmp4.Parts{{
|
||||||
|
Tracks: []*fmp4.PartTrack{{
|
||||||
|
ID: 1,
|
||||||
|
Samples: []*fmp4.Sample{
|
||||||
|
{
|
||||||
|
Payload: []byte{1, 2},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Duration: 44100,
|
||||||
|
Payload: []byte{1, 2},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
}}, parts)
|
||||||
|
}
|
||||||
|
|
||||||
func TestRecorderSkipTracksPartial(t *testing.T) {
|
func TestRecorderSkipTracksPartial(t *testing.T) {
|
||||||
for _, ca := range []string{"fmp4", "mpegts"} {
|
for _, ca := range []string{"fmp4", "mpegts"} {
|
||||||
t.Run(ca, func(t *testing.T) {
|
t.Run(ca, func(t *testing.T) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue