|
|
|
@ -1,6 +1,9 @@
@@ -1,6 +1,9 @@
|
|
|
|
|
package hls |
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
|
"bytes" |
|
|
|
|
"net/http" |
|
|
|
|
"sync" |
|
|
|
|
"time" |
|
|
|
|
|
|
|
|
|
"github.com/aler9/gortsplib" |
|
|
|
@ -34,8 +37,15 @@ func (s fmp4AudioSample) duration() time.Duration {
@@ -34,8 +37,15 @@ func (s fmp4AudioSample) duration() time.Duration {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type muxerVariantFMP4 struct { |
|
|
|
|
playlist *muxerVariantFMP4Playlist |
|
|
|
|
segmenter *muxerVariantFMP4Segmenter |
|
|
|
|
playlist *muxerVariantFMP4Playlist |
|
|
|
|
segmenter *muxerVariantFMP4Segmenter |
|
|
|
|
videoTrack *gortsplib.TrackH264 |
|
|
|
|
audioTrack *gortsplib.TrackAAC |
|
|
|
|
|
|
|
|
|
mutex sync.Mutex |
|
|
|
|
videoLastSPS []byte |
|
|
|
|
videoLastPPS []byte |
|
|
|
|
initContent []byte |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func newMuxerVariantFMP4( |
|
|
|
@ -47,7 +57,10 @@ func newMuxerVariantFMP4(
@@ -47,7 +57,10 @@ func newMuxerVariantFMP4(
|
|
|
|
|
videoTrack *gortsplib.TrackH264, |
|
|
|
|
audioTrack *gortsplib.TrackAAC, |
|
|
|
|
) *muxerVariantFMP4 { |
|
|
|
|
v := &muxerVariantFMP4{} |
|
|
|
|
v := &muxerVariantFMP4{ |
|
|
|
|
videoTrack: videoTrack, |
|
|
|
|
audioTrack: audioTrack, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
v.playlist = newMuxerVariantFMP4Playlist( |
|
|
|
|
lowLatency, |
|
|
|
@ -84,5 +97,37 @@ func (v *muxerVariantFMP4) writeAAC(pts time.Duration, aus [][]byte) error {
@@ -84,5 +97,37 @@ func (v *muxerVariantFMP4) writeAAC(pts time.Duration, aus [][]byte) error {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (v *muxerVariantFMP4) file(name string, msn string, part string, skip string) *MuxerFileResponse { |
|
|
|
|
if name == "init.mp4" { |
|
|
|
|
v.mutex.Lock() |
|
|
|
|
defer v.mutex.Unlock() |
|
|
|
|
|
|
|
|
|
var sps []byte |
|
|
|
|
var pps []byte |
|
|
|
|
if v.videoTrack != nil { |
|
|
|
|
sps = v.videoTrack.SPS() |
|
|
|
|
pps = v.videoTrack.PPS() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if v.initContent == nil || |
|
|
|
|
(v.videoTrack != nil && (!bytes.Equal(v.videoLastSPS, sps) || !bytes.Equal(v.videoLastPPS, pps))) { |
|
|
|
|
initContent, err := mp4InitGenerate(v.videoTrack, v.audioTrack) |
|
|
|
|
if err != nil { |
|
|
|
|
return &MuxerFileResponse{Status: http.StatusInternalServerError} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
v.videoLastSPS = sps |
|
|
|
|
v.videoLastPPS = pps |
|
|
|
|
v.initContent = initContent |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return &MuxerFileResponse{ |
|
|
|
|
Status: http.StatusOK, |
|
|
|
|
Header: map[string]string{ |
|
|
|
|
"Content-Type": "video/mp4", |
|
|
|
|
}, |
|
|
|
|
Body: bytes.NewReader(v.initContent), |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return v.playlist.file(name, msn, part, skip) |
|
|
|
|
} |
|
|
|
|