diff --git a/internal/playback/muxer_mp4.go b/internal/playback/muxer_mp4.go index f5b3791e..1ff669b2 100644 --- a/internal/playback/muxer_mp4.go +++ b/internal/playback/muxer_mp4.go @@ -94,12 +94,15 @@ func (w *muxerMP4) flush() error { return recordstore.ErrNoSegmentsFound } - h := pmp4.Presentation{ - Tracks: make([]*pmp4.Track, len(w.tracks)), + var tracks []*pmp4.Track + for _, track := range w.tracks { + if len(track.Samples) != 0 { + tracks = append(tracks, &track.Track) + } } - for i, track := range w.tracks { - h.Tracks[i] = &track.Track + h := pmp4.Presentation{ + Tracks: tracks, } return h.Marshal(w.w) diff --git a/internal/playback/muxer_mp4_test.go b/internal/playback/muxer_mp4_test.go new file mode 100644 index 00000000..1b23a2df --- /dev/null +++ b/internal/playback/muxer_mp4_test.go @@ -0,0 +1,59 @@ +package playback + +import ( + "bytes" + "testing" + + "github.com/bluenviron/mediacommon/v2/pkg/formats/fmp4" + "github.com/bluenviron/mediacommon/v2/pkg/formats/mp4" + "github.com/bluenviron/mediamtx/internal/test" + "github.com/stretchr/testify/require" +) + +// Test that tracks with no samples are not included in the output +func TestMuxerMP4EmptyTracks(t *testing.T) { + var buf bytes.Buffer + + mux := &muxerMP4{ + w: &buf, + } + + init := &fmp4.Init{ + Tracks: []*fmp4.InitTrack{ + { + ID: 1, + TimeScale: 90000, + Codec: &mp4.CodecH264{ + SPS: test.FormatH264.SPS, + PPS: test.FormatH264.PPS, + }, + }, + { + ID: 2, + TimeScale: 48000, + Codec: &mp4.CodecOpus{}, + }, + }, + } + + mux.writeInit(init) + + // Only write samples to the first track + mux.setTrack(1) + err := mux.writeSample(0, 0, false, 5, func() ([]byte, error) { + return []byte{0x01, 0x02, 0x03, 0x04, 0x05}, nil + }) + require.NoError(t, err) + + err = mux.writeSample(90000, 0, true, 5, func() ([]byte, error) { + return []byte{0x06, 0x07, 0x08, 0x09, 0x0a}, nil + }) + require.NoError(t, err) + + mux.writeFinalDTS(180000) + + err = mux.flush() + require.NoError(t, err) + + require.Greater(t, buf.Len(), 0) +}