Ready-to-use SRT / WebRTC / RTSP / RTMP / LL-HLS media server and media proxy that allows to read, publish, proxy, record and playback video and audio streams.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

186 lines
3.8 KiB

package hls
import (
"fmt"
"io"
"strconv"
"time"
"github.com/aler9/gortsplib/v2/pkg/format"
)
type partsReader struct {
parts []*muxerVariantFMP4Part
curPart int
curPos int
}
func (mbr *partsReader) Read(p []byte) (int, error) {
n := 0
lenp := len(p)
for {
if mbr.curPart >= len(mbr.parts) {
return n, io.EOF
}
copied := copy(p[n:], mbr.parts[mbr.curPart].content[mbr.curPos:])
mbr.curPos += copied
n += copied
if mbr.curPos == len(mbr.parts[mbr.curPart].content) {
mbr.curPart++
mbr.curPos = 0
}
if n == lenp {
return n, nil
}
}
}
type muxerVariantFMP4Segment struct {
lowLatency bool
id uint64
startTime time.Time
startDTS time.Duration
segmentMaxSize uint64
videoTrack format.Format
audioTrack format.Format
genPartID func() uint64
onPartFinalized func(*muxerVariantFMP4Part)
name string
size uint64
parts []*muxerVariantFMP4Part
currentPart *muxerVariantFMP4Part
renderedDuration time.Duration
}
func newMuxerVariantFMP4Segment(
lowLatency bool,
id uint64,
startTime time.Time,
startDTS time.Duration,
segmentMaxSize uint64,
videoTrack format.Format,
audioTrack format.Format,
genPartID func() uint64,
onPartFinalized func(*muxerVariantFMP4Part),
) *muxerVariantFMP4Segment {
s := &muxerVariantFMP4Segment{
lowLatency: lowLatency,
id: id,
startTime: startTime,
startDTS: startDTS,
segmentMaxSize: segmentMaxSize,
videoTrack: videoTrack,
audioTrack: audioTrack,
genPartID: genPartID,
onPartFinalized: onPartFinalized,
name: "seg" + strconv.FormatUint(id, 10),
}
s.currentPart = newMuxerVariantFMP4Part(
s.videoTrack,
s.audioTrack,
s.genPartID(),
)
return s
}
func (s *muxerVariantFMP4Segment) reader() io.Reader {
return &partsReader{parts: s.parts}
}
func (s *muxerVariantFMP4Segment) getRenderedDuration() time.Duration {
return s.renderedDuration
}
func (s *muxerVariantFMP4Segment) finalize(
nextVideoSampleDTS time.Duration,
) error {
err := s.currentPart.finalize()
if err != nil {
return err
}
if s.currentPart.content != nil {
s.onPartFinalized(s.currentPart)
s.parts = append(s.parts, s.currentPart)
}
s.currentPart = nil
if s.videoTrack != nil {
s.renderedDuration = nextVideoSampleDTS - s.startDTS
} else {
s.renderedDuration = 0
for _, pa := range s.parts {
s.renderedDuration += pa.renderedDuration
}
}
return nil
}
func (s *muxerVariantFMP4Segment) writeH264(sample *augmentedVideoSample, adjustedPartDuration time.Duration) error {
size := uint64(len(sample.Payload))
if (s.size + size) > s.segmentMaxSize {
return fmt.Errorf("reached maximum segment size")
}
s.size += size
s.currentPart.writeH264(sample)
// switch part
if s.lowLatency &&
s.currentPart.duration() >= adjustedPartDuration {
err := s.currentPart.finalize()
if err != nil {
return err
}
s.parts = append(s.parts, s.currentPart)
s.onPartFinalized(s.currentPart)
s.currentPart = newMuxerVariantFMP4Part(
s.videoTrack,
s.audioTrack,
s.genPartID(),
)
}
return nil
}
func (s *muxerVariantFMP4Segment) writeAudio(sample *augmentedAudioSample, adjustedPartDuration time.Duration) error {
size := uint64(len(sample.Payload))
if (s.size + size) > s.segmentMaxSize {
return fmt.Errorf("reached maximum segment size")
}
s.size += size
s.currentPart.writeAudio(sample)
// switch part
if s.lowLatency && s.videoTrack == nil &&
s.currentPart.duration() >= adjustedPartDuration {
err := s.currentPart.finalize()
if err != nil {
return err
}
s.parts = append(s.parts, s.currentPart)
s.onPartFinalized(s.currentPart)
s.currentPart = newMuxerVariantFMP4Part(
s.videoTrack,
s.audioTrack,
s.genPartID(),
)
}
return nil
}