diff --git a/internal/hls/muxer_test.go b/internal/hls/muxer_test.go index 0dc819dc..61b36356 100644 --- a/internal/hls/muxer_test.go +++ b/internal/hls/muxer_test.go @@ -566,3 +566,30 @@ func TestMuxerDoubleRead(t *testing.T) { require.NoError(t, err) require.Equal(t, byts1, byts2) } + +func TestMuxerFMP4ZeroDuration(t *testing.T) { + videoTrack := &format.H264{ + PayloadTyp: 96, + SPS: testSPS, + PPS: []byte{0x08}, + PacketizationMode: 1, + } + + m, err := NewMuxer(MuxerVariantLowLatency, 3, 1*time.Second, 0, 50*1024*1024, videoTrack, nil) + require.NoError(t, err) + defer m.Close() + + err = m.WriteH26x(time.Now(), 0, [][]byte{ + testSPS, // SPS + {8}, // PPS + {5}, // IDR + }) + require.NoError(t, err) + + err = m.WriteH26x(time.Now(), 1*time.Nanosecond, [][]byte{ + testSPS, // SPS + {8}, // PPS + {5}, // IDR + }) + require.NoError(t, err) +} diff --git a/internal/hls/muxer_variant_fmp4_segmenter.go b/internal/hls/muxer_variant_fmp4_segmenter.go index 6a3b254c..8ea8496d 100644 --- a/internal/hls/muxer_variant_fmp4_segmenter.go +++ b/internal/hls/muxer_variant_fmp4_segmenter.go @@ -25,21 +25,22 @@ func partDurationIsCompatible(partDuration time.Duration, sampleDuration time.Du return partDuration > ((f * 85) / 100) } +func partDurationIsCompatibleWithAll(partDuration time.Duration, sampleDurations map[time.Duration]struct{}) bool { + for sd := range sampleDurations { + if !partDurationIsCompatible(partDuration, sd) { + return false + } + } + return true +} + func findCompatiblePartDuration( minPartDuration time.Duration, sampleDurations map[time.Duration]struct{}, ) time.Duration { i := minPartDuration for ; i < 5*time.Second; i += 5 * time.Millisecond { - isCompatible := func() bool { - for sd := range sampleDurations { - if !partDurationIsCompatible(i, sd) { - return false - } - } - return true - }() - if isCompatible { + if partDurationIsCompatibleWithAll(i, sampleDurations) { break } } @@ -147,6 +148,11 @@ func (m *muxerVariantFMP4Segmenter) adjustPartDuration(du time.Duration) { return } + // avoid a crash by skipping invalid durations + if du == 0 { + return + } + if _, ok := m.sampleDurations[du]; !ok { m.sampleDurations[du] = struct{}{} m.adjustedPartDuration = findCompatiblePartDuration(