From 3e9d19e5e3080d747cf3d70d64550301def27d27 Mon Sep 17 00:00:00 2001 From: aler9 <46489434+aler9@users.noreply.github.com> Date: Sat, 17 Sep 2022 22:21:16 +0200 Subject: [PATCH] hls: split fmp4/mpegts muxer tests --- internal/hls/fmp4/init_test.go | 318 +++++++++++++++++++ internal/hls/fmp4/part_test.go | 143 +++++++++ internal/hls/mpegts/writer_test.go | 370 ++++++++++++++++++++++ internal/hls/muxer_test.go | 480 +---------------------------- scripts/test.mk | 8 +- 5 files changed, 845 insertions(+), 474 deletions(-) create mode 100644 internal/hls/fmp4/init_test.go create mode 100644 internal/hls/fmp4/part_test.go create mode 100644 internal/hls/mpegts/writer_test.go diff --git a/internal/hls/fmp4/init_test.go b/internal/hls/fmp4/init_test.go new file mode 100644 index 00000000..9c63fd51 --- /dev/null +++ b/internal/hls/fmp4/init_test.go @@ -0,0 +1,318 @@ +//nolint:dupl +package fmp4 + +import ( + "bytes" + "testing" + + gomp4 "github.com/abema/go-mp4" + "github.com/aler9/gortsplib" + "github.com/aler9/gortsplib/pkg/mpeg4audio" + "github.com/stretchr/testify/require" +) + +func testMP4(t *testing.T, byts []byte, boxes []gomp4.BoxPath) { + i := 0 + _, err := gomp4.ReadBoxStructure(bytes.NewReader(byts), func(h *gomp4.ReadHandle) (interface{}, error) { + require.Equal(t, boxes[i], h.Path) + i++ + return h.Expand() + }) + require.NoError(t, err) +} + +var testSPS = []byte{ + 0x67, 0x42, 0xc0, 0x28, 0xd9, 0x00, 0x78, 0x02, + 0x27, 0xe5, 0x84, 0x00, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x00, 0x03, 0x00, 0xf0, 0x3c, 0x60, 0xc9, + 0x20, +} + +var testVideoTrack = &gortsplib.TrackH264{ + PayloadType: 96, + SPS: testSPS, + PPS: []byte{0x08}, +} + +var testAudioTrack = &gortsplib.TrackMPEG4Audio{ + PayloadType: 97, + Config: &mpeg4audio.Config{ + Type: 2, + SampleRate: 44100, + ChannelCount: 2, + }, + SizeLength: 13, + IndexLength: 3, + IndexDeltaLength: 3, +} + +func TestGenerateInit(t *testing.T) { + t.Run("video + audio", func(t *testing.T) { + byts, err := GenerateInit(testVideoTrack, testAudioTrack) + require.NoError(t, err) + + boxes := []gomp4.BoxPath{ + {gomp4.BoxTypeFtyp()}, + {gomp4.BoxTypeMoov()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeMvhd()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeTkhd()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMdhd()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeHdlr()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), gomp4.BoxTypeVmhd()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), gomp4.BoxTypeDinf()}, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeDinf(), gomp4.BoxTypeDref(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeDinf(), gomp4.BoxTypeDref(), gomp4.BoxTypeUrl(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), gomp4.BoxTypeAvc1(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), gomp4.BoxTypeAvc1(), gomp4.BoxTypeAvcC(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), gomp4.BoxTypeAvc1(), gomp4.BoxTypeBtrt(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStts(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStsc(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStsz(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStco(), + }, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeTkhd()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMdhd()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeHdlr()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf()}, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeSmhd(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeDinf(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeDinf(), gomp4.BoxTypeDref(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeDinf(), gomp4.BoxTypeDref(), gomp4.BoxTypeUrl(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), gomp4.BoxTypeMp4a(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), gomp4.BoxTypeMp4a(), gomp4.BoxTypeEsds(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), gomp4.BoxTypeMp4a(), gomp4.BoxTypeBtrt(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStts(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStsc(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStsz(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStco(), + }, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeMvex()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeMvex(), gomp4.BoxTypeTrex()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeMvex(), gomp4.BoxTypeTrex()}, + } + testMP4(t, byts, boxes) + }) + + t.Run("video only", func(t *testing.T) { + byts, err := GenerateInit(testVideoTrack, nil) + require.NoError(t, err) + + boxes := []gomp4.BoxPath{ + {gomp4.BoxTypeFtyp()}, + {gomp4.BoxTypeMoov()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeMvhd()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeTkhd()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMdhd()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeHdlr()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf()}, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeVmhd(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeDinf(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeDinf(), gomp4.BoxTypeDref(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeDinf(), gomp4.BoxTypeDref(), gomp4.BoxTypeUrl(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), gomp4.BoxTypeAvc1(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), gomp4.BoxTypeAvc1(), gomp4.BoxTypeAvcC(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), gomp4.BoxTypeAvc1(), gomp4.BoxTypeBtrt(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStts(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStsc(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStsz(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStco(), + }, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeMvex()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeMvex(), gomp4.BoxTypeTrex()}, + } + testMP4(t, byts, boxes) + }) + + t.Run("audio only", func(t *testing.T) { + byts, err := GenerateInit(nil, testAudioTrack) + require.NoError(t, err) + + boxes := []gomp4.BoxPath{ + {gomp4.BoxTypeFtyp()}, + {gomp4.BoxTypeMoov()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeMvhd()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeTkhd()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMdhd()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeHdlr()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf()}, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeSmhd(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeDinf(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeDinf(), gomp4.BoxTypeDref(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeDinf(), gomp4.BoxTypeDref(), gomp4.BoxTypeUrl(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), gomp4.BoxTypeMp4a(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), gomp4.BoxTypeMp4a(), gomp4.BoxTypeEsds(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), gomp4.BoxTypeMp4a(), gomp4.BoxTypeBtrt(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStts(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStsc(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStsz(), + }, + { + gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), + gomp4.BoxTypeStbl(), gomp4.BoxTypeStco(), + }, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeMvex()}, + {gomp4.BoxTypeMoov(), gomp4.BoxTypeMvex(), gomp4.BoxTypeTrex()}, + } + testMP4(t, byts, boxes) + }) +} diff --git a/internal/hls/fmp4/part_test.go b/internal/hls/fmp4/part_test.go new file mode 100644 index 00000000..18c1d46d --- /dev/null +++ b/internal/hls/fmp4/part_test.go @@ -0,0 +1,143 @@ +package fmp4 + +import ( + "testing" + "time" + + gomp4 "github.com/abema/go-mp4" + "github.com/aler9/gortsplib/pkg/h264" + "github.com/stretchr/testify/require" +) + +func TestGeneratePart(t *testing.T) { + testVideoSamples := []*VideoSample{ + { + NALUs: [][]byte{ + {0x06}, + {0x07}, + }, + PTS: 0, + DTS: 0, + }, + { + NALUs: [][]byte{ + testSPS, // SPS + {8}, // PPS + {5}, // IDR + }, + PTS: 2 * time.Second, + DTS: 2 * time.Second, + }, + + { + NALUs: [][]byte{ + {1}, // non-IDR + }, + PTS: 4 * time.Second, + DTS: 4 * time.Second, + }, + + { + NALUs: [][]byte{ + {1}, // non-IDR + }, + PTS: 6 * time.Second, + DTS: 6 * time.Second, + }, + { + NALUs: [][]byte{ + {5}, // IDR + }, + PTS: 7 * time.Second, + DTS: 7 * time.Second, + }, + } + + testAudioSamples := []*AudioSample{ + { + AU: []byte{ + 0x01, 0x02, 0x03, 0x04, + }, + PTS: 3 * time.Second, + }, + { + AU: []byte{ + 0x01, 0x02, 0x03, 0x04, + }, + PTS: 3500 * time.Millisecond, + }, + { + AU: []byte{ + 0x01, 0x02, 0x03, 0x04, + }, + PTS: 4500 * time.Millisecond, + }, + } + + for i, sample := range testVideoSamples { + sample.IDRPresent = h264.IDRPresent(sample.NALUs) + if i != len(testVideoSamples)-1 { + sample.Next = testVideoSamples[i+1] + } + } + testVideoSamples = testVideoSamples[:len(testVideoSamples)-1] + + for i, sample := range testAudioSamples { + if i != len(testAudioSamples)-1 { + sample.Next = testAudioSamples[i+1] + } + } + testAudioSamples = testAudioSamples[:len(testAudioSamples)-1] + + t.Run("video + audio", func(t *testing.T) { + byts, err := GeneratePart(testVideoTrack, testAudioTrack, testVideoSamples, testAudioSamples) + require.NoError(t, err) + + boxes := []gomp4.BoxPath{ + {gomp4.BoxTypeMoof()}, + {gomp4.BoxTypeMoof(), gomp4.BoxTypeMfhd()}, + {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf()}, + {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf(), gomp4.BoxTypeTfhd()}, + {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf(), gomp4.BoxTypeTfdt()}, + {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf(), gomp4.BoxTypeTrun()}, + {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf()}, + {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf(), gomp4.BoxTypeTfhd()}, + {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf(), gomp4.BoxTypeTfdt()}, + {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf(), gomp4.BoxTypeTrun()}, + {gomp4.BoxTypeMdat()}, + } + testMP4(t, byts, boxes) + }) + + t.Run("video only", func(t *testing.T) { + byts, err := GeneratePart(testVideoTrack, nil, testVideoSamples, nil) + require.NoError(t, err) + + boxes := []gomp4.BoxPath{ + {gomp4.BoxTypeMoof()}, + {gomp4.BoxTypeMoof(), gomp4.BoxTypeMfhd()}, + {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf()}, + {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf(), gomp4.BoxTypeTfhd()}, + {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf(), gomp4.BoxTypeTfdt()}, + {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf(), gomp4.BoxTypeTrun()}, + {gomp4.BoxTypeMdat()}, + } + testMP4(t, byts, boxes) + }) + + t.Run("audio only", func(t *testing.T) { + byts, err := GeneratePart(nil, testAudioTrack, nil, testAudioSamples) + require.NoError(t, err) + + boxes := []gomp4.BoxPath{ + {gomp4.BoxTypeMoof()}, + {gomp4.BoxTypeMoof(), gomp4.BoxTypeMfhd()}, + {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf()}, + {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf(), gomp4.BoxTypeTfhd()}, + {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf(), gomp4.BoxTypeTfdt()}, + {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf(), gomp4.BoxTypeTrun()}, + {gomp4.BoxTypeMdat()}, + } + testMP4(t, byts, boxes) + }) +} diff --git a/internal/hls/mpegts/writer_test.go b/internal/hls/mpegts/writer_test.go new file mode 100644 index 00000000..64665ff2 --- /dev/null +++ b/internal/hls/mpegts/writer_test.go @@ -0,0 +1,370 @@ +package mpegts + +import ( + "bytes" + "context" + "testing" + "time" + + "github.com/aler9/gortsplib" + "github.com/aler9/gortsplib/pkg/h264" + "github.com/aler9/gortsplib/pkg/mpeg4audio" + "github.com/asticode/go-astits" + "github.com/stretchr/testify/require" +) + +func TestWriter(t *testing.T) { + testSPS := []byte{ + 0x67, 0x42, 0xc0, 0x28, 0xd9, 0x00, 0x78, 0x02, + 0x27, 0xe5, 0x84, 0x00, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x00, 0x03, 0x00, 0xf0, 0x3c, 0x60, 0xc9, + 0x20, + } + + testVideoTrack := &gortsplib.TrackH264{ + PayloadType: 96, + SPS: testSPS, + PPS: []byte{0x08}, + } + + testAudioTrack := &gortsplib.TrackMPEG4Audio{ + PayloadType: 97, + Config: &mpeg4audio.Config{ + Type: 2, + SampleRate: 44100, + ChannelCount: 2, + }, + SizeLength: 13, + IndexLength: 3, + IndexDeltaLength: 3, + } + + type videoSample struct { + NALUs [][]byte + PTS time.Duration + DTS time.Duration + } + + type audioSample struct { + AU []byte + PTS time.Duration + } + + type sample interface{} + + testSamples := []sample{ + videoSample{ + NALUs: [][]byte{ + testSPS, // SPS + {8}, // PPS + {5}, // IDR + }, + PTS: 2 * time.Second, + DTS: 2 * time.Second, + }, + audioSample{ + AU: []byte{ + 0x01, 0x02, 0x03, 0x04, + }, + PTS: 3 * time.Second, + }, + audioSample{ + AU: []byte{ + 0x01, 0x02, 0x03, 0x04, + }, + PTS: 3500 * time.Millisecond, + }, + videoSample{ + NALUs: [][]byte{ + {1}, // non-IDR + }, + PTS: 4 * time.Second, + DTS: 4 * time.Second, + }, + audioSample{ + AU: []byte{ + 0x01, 0x02, 0x03, 0x04, + }, + PTS: 4500 * time.Millisecond, + }, + videoSample{ + NALUs: [][]byte{ + {1}, // non-IDR + }, + PTS: 6 * time.Second, + DTS: 6 * time.Second, + }, + } + + t.Run("video + audio", func(t *testing.T) { + w := NewWriter(testVideoTrack, testAudioTrack) + + for _, sample := range testSamples { + switch tsample := sample.(type) { + case videoSample: + err := w.WriteH264( + tsample.DTS-2*time.Second, + tsample.DTS, + tsample.PTS, + h264.IDRPresent(tsample.NALUs), + tsample.NALUs) + require.NoError(t, err) + + case audioSample: + err := w.WriteAAC( + tsample.PTS-2*time.Second, + tsample.PTS, + tsample.AU) + require.NoError(t, err) + } + } + + byts := w.GenerateSegment() + + dem := astits.NewDemuxer(context.Background(), bytes.NewReader(byts), + astits.DemuxerOptPacketSize(188)) + + // PMT + pkt, err := dem.NextPacket() + require.NoError(t, err) + require.Equal(t, &astits.Packet{ + Header: &astits.PacketHeader{ + HasPayload: true, + PayloadUnitStartIndicator: true, + PID: 0, + }, + Payload: append([]byte{ + 0x00, 0x00, 0xb0, 0x0d, 0x00, 0x00, 0xc1, 0x00, + 0x00, 0x00, 0x01, 0xf0, 0x00, 0x71, 0x10, 0xd8, + 0x78, + }, bytes.Repeat([]byte{0xff}, 167)...), + }, pkt) + + // PAT + pkt, err = dem.NextPacket() + require.NoError(t, err) + require.Equal(t, &astits.Packet{ + Header: &astits.PacketHeader{ + HasPayload: true, + PayloadUnitStartIndicator: true, + PID: 4096, + }, + Payload: append([]byte{ + 0x00, 0x02, 0xb0, 0x17, 0x00, 0x01, 0xc1, 0x00, + 0x00, 0xe1, 0x00, 0xf0, 0x00, 0x1b, 0xe1, 0x00, + 0xf0, 0x00, 0x0f, 0xe1, 0x01, 0xf0, 0x00, 0x2f, + 0x44, 0xb9, 0x9b, + }, bytes.Repeat([]byte{0xff}, 157)...), + }, pkt) + + // PES (H264) + pkt, err = dem.NextPacket() + require.NoError(t, err) + require.Equal(t, &astits.Packet{ + AdaptationField: &astits.PacketAdaptationField{ + Length: 124, + StuffingLength: 117, + HasPCR: true, + PCR: &astits.ClockReference{}, + RandomAccessIndicator: true, + }, + Header: &astits.PacketHeader{ + HasAdaptationField: true, + HasPayload: true, + PayloadUnitStartIndicator: true, + PID: 256, + }, + Payload: []byte{ + 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x80, + 0x05, 0x21, 0x00, 0x0d, 0x97, 0x81, 0x00, 0x00, + 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, + 0x67, 0x42, 0xc0, 0x28, 0xd9, 0x00, 0x78, 0x02, + 0x27, 0xe5, 0x84, 0x00, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x00, 0x03, 0x00, 0xf0, 0x3c, 0x60, 0xc9, + 0x20, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, + 0x00, 0x01, 0x05, + }, + }, pkt) + + // PES (AAC) + pkt, err = dem.NextPacket() + require.NoError(t, err) + require.Equal(t, &astits.Packet{ + AdaptationField: &astits.PacketAdaptationField{ + Length: 158, + StuffingLength: 157, + RandomAccessIndicator: true, + }, + Header: &astits.PacketHeader{ + HasAdaptationField: true, + HasPayload: true, + PayloadUnitStartIndicator: true, + PID: 257, + }, + Payload: []byte{ + 0x00, 0x00, 0x01, 0xc0, 0x00, 0x13, 0x80, 0x80, + 0x05, 0x21, 0x00, 0x13, 0x56, 0xa1, 0xff, 0xf1, + 0x50, 0x80, 0x01, 0x7f, 0xfc, 0x01, 0x02, 0x03, + 0x04, + }, + }, pkt) + }) + + t.Run("video only", func(t *testing.T) { + w := NewWriter(testVideoTrack, nil) + + for _, sample := range testSamples { + if tsample, ok := sample.(videoSample); ok { + err := w.WriteH264( + tsample.DTS-2*time.Second, + tsample.DTS, + tsample.PTS, + h264.IDRPresent(tsample.NALUs), + tsample.NALUs) + require.NoError(t, err) + } + } + + byts := w.GenerateSegment() + + dem := astits.NewDemuxer(context.Background(), bytes.NewReader(byts), + astits.DemuxerOptPacketSize(188)) + + // PMT + pkt, err := dem.NextPacket() + require.NoError(t, err) + require.Equal(t, &astits.Packet{ + Header: &astits.PacketHeader{ + HasPayload: true, + PayloadUnitStartIndicator: true, + PID: 0, + }, + Payload: append([]byte{ + 0x00, 0x00, 0xb0, 0x0d, 0x00, 0x00, 0xc1, 0x00, + 0x00, 0x00, 0x01, 0xf0, 0x00, 0x71, 0x10, 0xd8, + 0x78, + }, bytes.Repeat([]byte{0xff}, 167)...), + }, pkt) + + // PAT + pkt, err = dem.NextPacket() + require.NoError(t, err) + require.Equal(t, &astits.Packet{ + Header: &astits.PacketHeader{ + HasPayload: true, + PayloadUnitStartIndicator: true, + PID: 4096, + }, + Payload: append([]byte{ + 0x00, 0x02, 0xb0, 0x12, 0x00, 0x01, 0xc1, 0x00, + 0x00, 0xe1, 0x00, 0xf0, 0x00, 0x1b, 0xe1, 0x00, + 0xf0, 0x00, 0x15, 0xbd, 0x4d, 0x56, + }, bytes.Repeat([]byte{0xff}, 162)...), + }, pkt) + + // PES (H264) + pkt, err = dem.NextPacket() + require.NoError(t, err) + require.Equal(t, &astits.Packet{ + AdaptationField: &astits.PacketAdaptationField{ + Length: 124, + StuffingLength: 117, + HasPCR: true, + PCR: &astits.ClockReference{}, + RandomAccessIndicator: true, + }, + Header: &astits.PacketHeader{ + HasAdaptationField: true, + HasPayload: true, + PayloadUnitStartIndicator: true, + PID: 256, + }, + Payload: []byte{ + 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x80, + 0x05, 0x21, 0x00, 0x0d, 0x97, 0x81, 0x00, 0x00, + 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, + 0x67, 0x42, 0xc0, 0x28, 0xd9, 0x00, 0x78, 0x02, + 0x27, 0xe5, 0x84, 0x00, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x00, 0x03, 0x00, 0xf0, 0x3c, 0x60, 0xc9, + 0x20, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, + 0x00, 0x01, 0x05, + }, + }, pkt) + }) + + t.Run("audio only", func(t *testing.T) { + w := NewWriter(nil, testAudioTrack) + + for _, sample := range testSamples { + if tsample, ok := sample.(audioSample); ok { + err := w.WriteAAC( + tsample.PTS-2*time.Second, + tsample.PTS, + tsample.AU) + require.NoError(t, err) + } + } + + byts := w.GenerateSegment() + + dem := astits.NewDemuxer(context.Background(), bytes.NewReader(byts), + astits.DemuxerOptPacketSize(188)) + + // PMT + pkt, err := dem.NextPacket() + require.NoError(t, err) + require.Equal(t, &astits.Packet{ + Header: &astits.PacketHeader{ + HasPayload: true, + PayloadUnitStartIndicator: true, + PID: 0, + }, + Payload: append([]byte{ + 0x00, 0x00, 0xb0, 0x0d, 0x00, 0x00, 0xc1, 0x00, + 0x00, 0x00, 0x01, 0xf0, 0x00, 0x71, 0x10, 0xd8, + 0x78, + }, bytes.Repeat([]byte{0xff}, 167)...), + }, pkt) + + // PAT + pkt, err = dem.NextPacket() + require.NoError(t, err) + require.Equal(t, &astits.Packet{ + Header: &astits.PacketHeader{ + HasPayload: true, + PayloadUnitStartIndicator: true, + PID: 4096, + }, + Payload: append([]byte{ + 0x00, 0x02, 0xb0, 0x12, 0x00, 0x01, 0xc1, 0x00, + 0x00, 0xe1, 0x01, 0xf0, 0x00, 0x0f, 0xe1, 0x01, + 0xf0, 0x00, 0xec, 0xe2, 0xb0, 0x94, + }, bytes.Repeat([]byte{0xff}, 162)...), + }, pkt) + + // PES (AAC) + pkt, err = dem.NextPacket() + require.NoError(t, err) + require.Equal(t, &astits.Packet{ + AdaptationField: &astits.PacketAdaptationField{ + Length: 158, + StuffingLength: 151, + RandomAccessIndicator: true, + HasPCR: true, + PCR: &astits.ClockReference{Base: 90000}, + }, + Header: &astits.PacketHeader{ + HasAdaptationField: true, + HasPayload: true, + PayloadUnitStartIndicator: true, + PID: 257, + }, + Payload: []byte{ + 0x00, 0x00, 0x01, 0xc0, 0x00, 0x13, 0x80, 0x80, + 0x05, 0x21, 0x00, 0x13, 0x56, 0xa1, 0xff, 0xf1, + 0x50, 0x80, 0x01, 0x7f, 0xfc, 0x01, 0x02, 0x03, + 0x04, + }, + }, pkt) + }) +} diff --git a/internal/hls/muxer_test.go b/internal/hls/muxer_test.go index 4d82e5c3..3bd11449 100644 --- a/internal/hls/muxer_test.go +++ b/internal/hls/muxer_test.go @@ -1,17 +1,13 @@ package hls import ( - "bytes" - "context" "io" "regexp" "testing" "time" - gomp4 "github.com/abema/go-mp4" "github.com/aler9/gortsplib" "github.com/aler9/gortsplib/pkg/mpeg4audio" - "github.com/asticode/go-astits" "github.com/stretchr/testify/require" ) @@ -25,16 +21,6 @@ var testSPS = []byte{ 0x20, } -func testMP4(t *testing.T, byts []byte, boxes []gomp4.BoxPath) { - i := 0 - _, err := gomp4.ReadBoxStructure(bytes.NewReader(byts), func(h *gomp4.ReadHandle) (interface{}, error) { - require.Equal(t, boxes[i], h.Path) - i++ - return h.Expand() - }) - require.NoError(t, err) -} - func TestMuxerVideoAudio(t *testing.T) { videoTrack := &gortsplib.TrackH264{ PayloadType: 96, @@ -181,234 +167,14 @@ func TestMuxerVideoAudio(t *testing.T) { require.NotEqual(t, 0, len(ma)) if ca == "mpegts" { - dem := astits.NewDemuxer(context.Background(), m.File(ma[2], "", "", "").Body, - astits.DemuxerOptPacketSize(188)) - - // PMT - pkt, err := dem.NextPacket() + _, err := io.ReadAll(m.File(ma[2], "", "", "").Body) require.NoError(t, err) - require.Equal(t, &astits.Packet{ - Header: &astits.PacketHeader{ - HasPayload: true, - PayloadUnitStartIndicator: true, - PID: 0, - }, - Payload: append([]byte{ - 0x00, 0x00, 0xb0, 0x0d, 0x00, 0x00, 0xc1, 0x00, - 0x00, 0x00, 0x01, 0xf0, 0x00, 0x71, 0x10, 0xd8, - 0x78, - }, bytes.Repeat([]byte{0xff}, 167)...), - }, pkt) - - // PAT - pkt, err = dem.NextPacket() - require.NoError(t, err) - require.Equal(t, &astits.Packet{ - Header: &astits.PacketHeader{ - HasPayload: true, - PayloadUnitStartIndicator: true, - PID: 4096, - }, - Payload: append([]byte{ - 0x00, 0x02, 0xb0, 0x17, 0x00, 0x01, 0xc1, 0x00, - 0x00, 0xe1, 0x00, 0xf0, 0x00, 0x1b, 0xe1, 0x00, - 0xf0, 0x00, 0x0f, 0xe1, 0x01, 0xf0, 0x00, 0x2f, - 0x44, 0xb9, 0x9b, - }, bytes.Repeat([]byte{0xff}, 157)...), - }, pkt) - - // PES (H264) - pkt, err = dem.NextPacket() - require.NoError(t, err) - require.Equal(t, &astits.Packet{ - AdaptationField: &astits.PacketAdaptationField{ - Length: 124, - StuffingLength: 117, - HasPCR: true, - PCR: &astits.ClockReference{}, - RandomAccessIndicator: true, - }, - Header: &astits.PacketHeader{ - HasAdaptationField: true, - HasPayload: true, - PayloadUnitStartIndicator: true, - PID: 256, - }, - Payload: []byte{ - 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x80, - 0x05, 0x21, 0x00, 0x03, 0x19, 0x41, 0x00, 0x00, - 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, - 0x67, 0x42, 0xc0, 0x28, 0xd9, 0x00, 0x78, 0x02, - 0x27, 0xe5, 0x84, 0x00, 0x00, 0x03, 0x00, 0x04, - 0x00, 0x00, 0x03, 0x00, 0xf0, 0x3c, 0x60, 0xc9, - 0x20, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, - 0x00, 0x01, 0x05, - }, - }, pkt) - - // PES (AAC) - pkt, err = dem.NextPacket() - require.NoError(t, err) - require.Equal(t, &astits.Packet{ - AdaptationField: &astits.PacketAdaptationField{ - Length: 158, - StuffingLength: 157, - RandomAccessIndicator: true, - }, - Header: &astits.PacketHeader{ - HasAdaptationField: true, - HasPayload: true, - PayloadUnitStartIndicator: true, - PID: 257, - }, - Payload: []byte{ - 0x00, 0x00, 0x01, 0xc0, 0x00, 0x13, 0x80, 0x80, - 0x05, 0x21, 0x00, 0x07, 0xd8, 0x5f, 0xff, 0xf1, - 0x50, 0x80, 0x01, 0x7f, 0xfc, 0x01, 0x02, 0x03, - 0x04, - }, - }, pkt) } else { - byts, err := io.ReadAll(m.File("init.mp4", "", "", "").Body) + _, err := io.ReadAll(m.File("init.mp4", "", "", "").Body) require.NoError(t, err) - boxes := []gomp4.BoxPath{ - {gomp4.BoxTypeFtyp()}, - {gomp4.BoxTypeMoov()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeMvhd()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeTkhd()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMdhd()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeHdlr()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), gomp4.BoxTypeVmhd()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), gomp4.BoxTypeDinf()}, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeDinf(), gomp4.BoxTypeDref(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeDinf(), gomp4.BoxTypeDref(), gomp4.BoxTypeUrl(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), gomp4.BoxTypeAvc1(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), gomp4.BoxTypeAvc1(), gomp4.BoxTypeAvcC(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), gomp4.BoxTypeAvc1(), gomp4.BoxTypeBtrt(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStts(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStsc(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStsz(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStco(), - }, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeTkhd()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMdhd()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeHdlr()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf()}, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeSmhd(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeDinf(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeDinf(), gomp4.BoxTypeDref(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeDinf(), gomp4.BoxTypeDref(), gomp4.BoxTypeUrl(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), gomp4.BoxTypeMp4a(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), gomp4.BoxTypeMp4a(), gomp4.BoxTypeEsds(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), gomp4.BoxTypeMp4a(), gomp4.BoxTypeBtrt(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStts(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStsc(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStsz(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStco(), - }, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeMvex()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeMvex(), gomp4.BoxTypeTrex()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeMvex(), gomp4.BoxTypeTrex()}, - } - testMP4(t, byts, boxes) - - byts, err = io.ReadAll(m.File(ma[2], "", "", "").Body) + _, err = io.ReadAll(m.File(ma[2], "", "", "").Body) require.NoError(t, err) - - boxes = []gomp4.BoxPath{ - {gomp4.BoxTypeMoof()}, - {gomp4.BoxTypeMoof(), gomp4.BoxTypeMfhd()}, - {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf()}, - {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf(), gomp4.BoxTypeTfhd()}, - {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf(), gomp4.BoxTypeTfdt()}, - {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf(), gomp4.BoxTypeTrun()}, - {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf()}, - {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf(), gomp4.BoxTypeTfhd()}, - {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf(), gomp4.BoxTypeTfdt()}, - {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf(), gomp4.BoxTypeTrun()}, - {gomp4.BoxTypeMdat()}, - } - testMP4(t, byts, boxes) } }) } @@ -514,125 +280,15 @@ func TestMuxerVideoOnly(t *testing.T) { } require.NotEqual(t, 0, len(ma)) - if ca == "mpegts" { //nolint:dupl - dem := astits.NewDemuxer(context.Background(), m.File(ma[2], "", "", "").Body, - astits.DemuxerOptPacketSize(188)) - - // PMT - pkt, err := dem.NextPacket() + if ca == "mpegts" { + _, err := io.ReadAll(m.File(ma[2], "", "", "").Body) require.NoError(t, err) - require.Equal(t, &astits.Packet{ - Header: &astits.PacketHeader{ - HasPayload: true, - PayloadUnitStartIndicator: true, - PID: 0, - }, - Payload: append([]byte{ - 0x00, 0x00, 0xb0, 0x0d, 0x00, 0x00, 0xc1, 0x00, - 0x00, 0x00, 0x01, 0xf0, 0x00, 0x71, 0x10, 0xd8, - 0x78, - }, bytes.Repeat([]byte{0xff}, 167)...), - }, pkt) - - // PAT - pkt, err = dem.NextPacket() - require.NoError(t, err) - require.Equal(t, &astits.Packet{ - Header: &astits.PacketHeader{ - HasPayload: true, - PayloadUnitStartIndicator: true, - PID: 4096, - }, - Payload: append([]byte{ - 0x00, 0x02, 0xb0, 0x12, 0x00, 0x01, 0xc1, 0x00, - 0x00, 0xe1, 0x00, 0xf0, 0x00, 0x1b, 0xe1, 0x00, - 0xf0, 0x00, 0x15, 0xbd, 0x4d, 0x56, - }, bytes.Repeat([]byte{0xff}, 162)...), - }, pkt) - } else { //nolint:dupl - byts, err := io.ReadAll(m.File("init.mp4", "", "", "").Body) + } else { + _, err := io.ReadAll(m.File("init.mp4", "", "", "").Body) require.NoError(t, err) - boxes := []gomp4.BoxPath{ - {gomp4.BoxTypeFtyp()}, - {gomp4.BoxTypeMoov()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeMvhd()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeTkhd()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMdhd()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeHdlr()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf()}, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeVmhd(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeDinf(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeDinf(), gomp4.BoxTypeDref(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeDinf(), gomp4.BoxTypeDref(), gomp4.BoxTypeUrl(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), gomp4.BoxTypeAvc1(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), gomp4.BoxTypeAvc1(), gomp4.BoxTypeAvcC(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), gomp4.BoxTypeAvc1(), gomp4.BoxTypeBtrt(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStts(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStsc(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStsz(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStco(), - }, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeMvex()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeMvex(), gomp4.BoxTypeTrex()}, - } - testMP4(t, byts, boxes) - - byts, err = io.ReadAll(m.File(ma[2], "", "", "").Body) + _, err = io.ReadAll(m.File(ma[2], "", "", "").Body) require.NoError(t, err) - - boxes = []gomp4.BoxPath{ - {gomp4.BoxTypeMoof()}, - {gomp4.BoxTypeMoof(), gomp4.BoxTypeMfhd()}, - {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf()}, - {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf(), gomp4.BoxTypeTfhd()}, - {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf(), gomp4.BoxTypeTfdt()}, - {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf(), gomp4.BoxTypeTrun()}, - {gomp4.BoxTypeMdat()}, - } - testMP4(t, byts, boxes) } }) } @@ -738,125 +394,15 @@ func TestMuxerAudioOnly(t *testing.T) { } require.NotEqual(t, 0, len(ma)) - if ca == "mpegts" { //nolint:dupl - dem := astits.NewDemuxer(context.Background(), m.File(ma[2], "", "", "").Body, - astits.DemuxerOptPacketSize(188)) - - // PMT - pkt, err := dem.NextPacket() + if ca == "mpegts" { + _, err := io.ReadAll(m.File(ma[2], "", "", "").Body) require.NoError(t, err) - require.Equal(t, &astits.Packet{ - Header: &astits.PacketHeader{ - HasPayload: true, - PayloadUnitStartIndicator: true, - PID: 0, - }, - Payload: append([]byte{ - 0x00, 0x00, 0xb0, 0x0d, 0x00, 0x00, 0xc1, 0x00, - 0x00, 0x00, 0x01, 0xf0, 0x00, 0x71, 0x10, 0xd8, - 0x78, - }, bytes.Repeat([]byte{0xff}, 167)...), - }, pkt) - - // PAT - pkt, err = dem.NextPacket() - require.NoError(t, err) - require.Equal(t, &astits.Packet{ - Header: &astits.PacketHeader{ - HasPayload: true, - PayloadUnitStartIndicator: true, - PID: 4096, - }, - Payload: append([]byte{ - 0x00, 0x02, 0xb0, 0x12, 0x00, 0x01, 0xc1, 0x00, - 0x00, 0xe1, 0x01, 0xf0, 0x00, 0x0f, 0xe1, 0x01, - 0xf0, 0x00, 0xec, 0xe2, 0xb0, 0x94, - }, bytes.Repeat([]byte{0xff}, 162)...), - }, pkt) - } else { //nolint:dupl - byts, err := io.ReadAll(m.File("init.mp4", "", "", "").Body) + } else { + _, err := io.ReadAll(m.File("init.mp4", "", "", "").Body) require.NoError(t, err) - boxes := []gomp4.BoxPath{ - {gomp4.BoxTypeFtyp()}, - {gomp4.BoxTypeMoov()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeMvhd()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeTkhd()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMdhd()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeHdlr()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf()}, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeSmhd(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeDinf(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeDinf(), gomp4.BoxTypeDref(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeDinf(), gomp4.BoxTypeDref(), gomp4.BoxTypeUrl(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), gomp4.BoxTypeMp4a(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), gomp4.BoxTypeMp4a(), gomp4.BoxTypeEsds(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStsd(), gomp4.BoxTypeMp4a(), gomp4.BoxTypeBtrt(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStts(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStsc(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStsz(), - }, - { - gomp4.BoxTypeMoov(), gomp4.BoxTypeTrak(), gomp4.BoxTypeMdia(), gomp4.BoxTypeMinf(), - gomp4.BoxTypeStbl(), gomp4.BoxTypeStco(), - }, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeMvex()}, - {gomp4.BoxTypeMoov(), gomp4.BoxTypeMvex(), gomp4.BoxTypeTrex()}, - } - testMP4(t, byts, boxes) - - byts, err = io.ReadAll(m.File(ma[2], "", "", "").Body) + _, err = io.ReadAll(m.File(ma[2], "", "", "").Body) require.NoError(t, err) - - boxes = []gomp4.BoxPath{ - {gomp4.BoxTypeMoof()}, - {gomp4.BoxTypeMoof(), gomp4.BoxTypeMfhd()}, - {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf()}, - {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf(), gomp4.BoxTypeTfhd()}, - {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf(), gomp4.BoxTypeTfdt()}, - {gomp4.BoxTypeMoof(), gomp4.BoxTypeTraf(), gomp4.BoxTypeTrun()}, - {gomp4.BoxTypeMdat()}, - } - testMP4(t, byts, boxes) } }) } diff --git a/scripts/test.mk b/scripts/test.mk index cab7b107..ac8b5691 100644 --- a/scripts/test.mk +++ b/scripts/test.mk @@ -33,13 +33,7 @@ endif test-internal: go test -v $(TEST_INTERNAL_OPTS) \ - ./internal/conf \ - ./internal/confwatcher \ - ./internal/externalcmd \ - ./internal/hls \ - ./internal/logger \ - ./internal/rlimit \ - ./internal/rtmp/... + $$(go list ./internal/... | grep -v /core) test-core: $(foreach IMG,$(shell echo testimages/*/ | xargs -n1 basename), \