|
|
@ -13,10 +13,10 @@ import ( |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
type tsFile struct { |
|
|
|
type tsFile struct { |
|
|
|
|
|
|
|
hasVideoTrack bool |
|
|
|
name string |
|
|
|
name string |
|
|
|
buf *multiAccessBuffer |
|
|
|
buf *multiAccessBuffer |
|
|
|
mux *astits.Muxer |
|
|
|
mux *astits.Muxer |
|
|
|
pcrTrackIsVideo bool |
|
|
|
|
|
|
|
pcr time.Duration |
|
|
|
pcr time.Duration |
|
|
|
firstPacketWritten bool |
|
|
|
firstPacketWritten bool |
|
|
|
minPTS time.Duration |
|
|
|
minPTS time.Duration |
|
|
@ -25,8 +25,9 @@ type tsFile struct { |
|
|
|
|
|
|
|
|
|
|
|
func newTSFile(hasVideoTrack bool, hasAudioTrack bool) *tsFile { |
|
|
|
func newTSFile(hasVideoTrack bool, hasAudioTrack bool) *tsFile { |
|
|
|
t := &tsFile{ |
|
|
|
t := &tsFile{ |
|
|
|
buf: newMultiAccessBuffer(), |
|
|
|
hasVideoTrack: hasVideoTrack, |
|
|
|
name: strconv.FormatInt(time.Now().Unix(), 10), |
|
|
|
name: strconv.FormatInt(time.Now().Unix(), 10), |
|
|
|
|
|
|
|
buf: newMultiAccessBuffer(), |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
t.mux = astits.NewMuxer(context.Background(), t.buf) |
|
|
|
t.mux = astits.NewMuxer(context.Background(), t.buf) |
|
|
@ -46,16 +47,15 @@ func newTSFile(hasVideoTrack bool, hasAudioTrack bool) *tsFile { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if hasVideoTrack { |
|
|
|
if hasVideoTrack { |
|
|
|
t.pcrTrackIsVideo = true |
|
|
|
|
|
|
|
t.mux.SetPCRPID(256) |
|
|
|
t.mux.SetPCRPID(256) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
t.pcrTrackIsVideo = false |
|
|
|
|
|
|
|
t.mux.SetPCRPID(257) |
|
|
|
t.mux.SetPCRPID(257) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// write PMT at the beginning of every segment
|
|
|
|
// WriteTable() is called automatically when WriteData() is called with
|
|
|
|
// so no packets are lost
|
|
|
|
// - PID == PCRPID
|
|
|
|
t.mux.WriteTables() |
|
|
|
// - AdaptationField != nil
|
|
|
|
|
|
|
|
// - RandomAccessIndicator = true
|
|
|
|
|
|
|
|
|
|
|
|
return t |
|
|
|
return t |
|
|
|
} |
|
|
|
} |
|
|
@ -77,18 +77,16 @@ func (t *tsFile) newReader() io.Reader { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (t *tsFile) writeH264(dts time.Duration, pts time.Duration, isIDR bool, nalus [][]byte) error { |
|
|
|
func (t *tsFile) writeH264(dts time.Duration, pts time.Duration, isIDR bool, nalus [][]byte) error { |
|
|
|
if t.pcrTrackIsVideo { |
|
|
|
if !t.firstPacketWritten { |
|
|
|
if !t.firstPacketWritten { |
|
|
|
t.firstPacketWritten = true |
|
|
|
t.firstPacketWritten = true |
|
|
|
t.minPTS = pts |
|
|
|
|
|
|
|
t.maxPTS = pts |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
if pts < t.minPTS { |
|
|
|
t.minPTS = pts |
|
|
|
t.minPTS = pts |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if pts > t.maxPTS { |
|
|
|
t.maxPTS = pts |
|
|
|
t.maxPTS = pts |
|
|
|
} else { |
|
|
|
|
|
|
|
if pts < t.minPTS { |
|
|
|
|
|
|
|
t.minPTS = pts |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if pts > t.maxPTS { |
|
|
|
|
|
|
|
t.maxPTS = pts |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -99,11 +97,8 @@ func (t *tsFile) writeH264(dts time.Duration, pts time.Duration, isIDR bool, nal |
|
|
|
|
|
|
|
|
|
|
|
af := &astits.PacketAdaptationField{ |
|
|
|
af := &astits.PacketAdaptationField{ |
|
|
|
RandomAccessIndicator: isIDR, |
|
|
|
RandomAccessIndicator: isIDR, |
|
|
|
} |
|
|
|
HasPCR: true, |
|
|
|
|
|
|
|
PCR: &astits.ClockReference{Base: int64(t.pcr.Seconds() * 90000)}, |
|
|
|
if t.pcrTrackIsVideo { |
|
|
|
|
|
|
|
af.HasPCR = true |
|
|
|
|
|
|
|
af.PCR = &astits.ClockReference{Base: int64(t.pcr.Seconds() * 90000)} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
_, err = t.mux.WriteData(&astits.MuxerData{ |
|
|
|
_, err = t.mux.WriteData(&astits.MuxerData{ |
|
|
@ -126,7 +121,7 @@ func (t *tsFile) writeH264(dts time.Duration, pts time.Duration, isIDR bool, nal |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (t *tsFile) writeAAC(sampleRate int, channelCount int, pts time.Duration, au []byte) error { |
|
|
|
func (t *tsFile) writeAAC(sampleRate int, channelCount int, pts time.Duration, au []byte) error { |
|
|
|
if !t.pcrTrackIsVideo { |
|
|
|
if !t.hasVideoTrack { |
|
|
|
if !t.firstPacketWritten { |
|
|
|
if !t.firstPacketWritten { |
|
|
|
t.firstPacketWritten = true |
|
|
|
t.firstPacketWritten = true |
|
|
|
t.minPTS = pts |
|
|
|
t.minPTS = pts |
|
|
@ -156,7 +151,7 @@ func (t *tsFile) writeAAC(sampleRate int, channelCount int, pts time.Duration, a |
|
|
|
RandomAccessIndicator: true, |
|
|
|
RandomAccessIndicator: true, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if !t.pcrTrackIsVideo { |
|
|
|
if !t.hasVideoTrack { |
|
|
|
af.HasPCR = true |
|
|
|
af.HasPCR = true |
|
|
|
af.PCR = &astits.ClockReference{Base: int64(t.pcr.Seconds() * 90000)} |
|
|
|
af.PCR = &astits.ClockReference{Base: int64(t.pcr.Seconds() * 90000)} |
|
|
|
} |
|
|
|
} |
|
|
|