live video streaming server in golang
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.
 
 
 

364 lines
6.9 KiB

package ts
import (
"io"
"github.com/gwuhaolin/livego/av"
)
const (
tsDefaultDataLen = 184
tsPacketLen = 188
h264DefaultHZ = 90
videoPID = 0x100
audioPID = 0x101
videoSID = 0xe0
audioSID = 0xc0
)
type Muxer struct {
videoCc byte
audioCc byte
patCc byte
pmtCc byte
pat [tsPacketLen]byte
pmt [tsPacketLen]byte
tsPacket [tsPacketLen]byte
}
func NewMuxer() *Muxer {
return &Muxer{}
}
func (muxer *Muxer) Mux(p *av.Packet, w io.Writer) error {
first := true
wBytes := 0
pesIndex := 0
tmpLen := byte(0)
dataLen := byte(0)
var pes pesHeader
dts := int64(p.TimeStamp) * int64(h264DefaultHZ)
pts := dts
pid := audioPID
var videoH av.VideoPacketHeader
if p.IsVideo {
pid = videoPID
videoH, _ = p.Header.(av.VideoPacketHeader)
pts = dts + int64(videoH.CompositionTime())*int64(h264DefaultHZ)
}
err := pes.packet(p, pts, dts)
if err != nil {
return err
}
pesHeaderLen := pes.len
packetBytesLen := len(p.Data) + int(pesHeaderLen)
for {
if packetBytesLen <= 0 {
break
}
if p.IsVideo {
muxer.videoCc++
if muxer.videoCc > 0xf {
muxer.videoCc = 0
}
} else {
muxer.audioCc++
if muxer.audioCc > 0xf {
muxer.audioCc = 0
}
}
i := byte(0)
//sync byte
muxer.tsPacket[i] = 0x47
i++
//error indicator, unit start indicator,ts priority,pid
muxer.tsPacket[i] = byte(pid >> 8) //pid high 5 bits
if first {
muxer.tsPacket[i] = muxer.tsPacket[i] | 0x40 //unit start indicator
}
i++
//pid low 8 bits
muxer.tsPacket[i] = byte(pid)
i++
//scram control, adaptation control, counter
if p.IsVideo {
muxer.tsPacket[i] = 0x10 | byte(muxer.videoCc&0x0f)
} else {
muxer.tsPacket[i] = 0x10 | byte(muxer.audioCc&0x0f)
}
i++
//关键帧需要加pcr
if first && p.IsVideo && videoH.IsKeyFrame() {
muxer.tsPacket[3] |= 0x20
muxer.tsPacket[i] = 7
i++
muxer.tsPacket[i] = 0x50
i++
muxer.writePcr(muxer.tsPacket[0:], i, dts)
i += 6
}
//frame data
if packetBytesLen >= tsDefaultDataLen {
dataLen = tsDefaultDataLen
if first {
dataLen -= (i - 4)
}
} else {
muxer.tsPacket[3] |= 0x20 //have adaptation
remainBytes := byte(0)
dataLen = byte(packetBytesLen)
if first {
remainBytes = tsDefaultDataLen - dataLen - (i - 4)
} else {
remainBytes = tsDefaultDataLen - dataLen
}
muxer.adaptationBufInit(muxer.tsPacket[i:], byte(remainBytes))
i += remainBytes
}
if first && i < tsPacketLen && pesHeaderLen > 0 {
tmpLen = tsPacketLen - i
if pesHeaderLen <= tmpLen {
tmpLen = pesHeaderLen
}
copy(muxer.tsPacket[i:], pes.data[pesIndex:pesIndex+int(tmpLen)])
i += tmpLen
packetBytesLen -= int(tmpLen)
dataLen -= tmpLen
pesHeaderLen -= tmpLen
pesIndex += int(tmpLen)
}
if i < tsPacketLen {
tmpLen = tsPacketLen - i
if tmpLen <= dataLen {
dataLen = tmpLen
}
copy(muxer.tsPacket[i:], p.Data[wBytes:wBytes+int(dataLen)])
wBytes += int(dataLen)
packetBytesLen -= int(dataLen)
}
if w != nil {
if _, err := w.Write(muxer.tsPacket[0:]); err != nil {
return err
}
}
first = false
}
return nil
}
//PAT return pat data
func (muxer *Muxer) PAT() []byte {
i := 0
remainByte := 0
tsHeader := []byte{0x47, 0x40, 0x00, 0x10, 0x00}
patHeader := []byte{0x00, 0xb0, 0x0d, 0x00, 0x01, 0xc1, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x01}
if muxer.patCc > 0xf {
muxer.patCc = 0
}
tsHeader[3] |= muxer.patCc & 0x0f
muxer.patCc++
copy(muxer.pat[i:], tsHeader)
i += len(tsHeader)
copy(muxer.pat[i:], patHeader)
i += len(patHeader)
crc32Value := GenCrc32(patHeader)
muxer.pat[i] = byte(crc32Value >> 24)
i++
muxer.pat[i] = byte(crc32Value >> 16)
i++
muxer.pat[i] = byte(crc32Value >> 8)
i++
muxer.pat[i] = byte(crc32Value)
i++
remainByte = int(tsPacketLen - i)
for j := 0; j < remainByte; j++ {
muxer.pat[i+j] = 0xff
}
return muxer.pat[0:]
}
// PMT return pmt data
func (muxer *Muxer) PMT(soundFormat byte, hasVideo bool) []byte {
i := int(0)
j := int(0)
var progInfo []byte
remainBytes := int(0)
tsHeader := []byte{0x47, 0x50, 0x01, 0x10, 0x00}
pmtHeader := []byte{0x02, 0xb0, 0xff, 0x00, 0x01, 0xc1, 0x00, 0x00, 0xe1, 0x00, 0xf0, 0x00}
if !hasVideo {
pmtHeader[9] = 0x01
progInfo = []byte{0x0f, 0xe1, 0x01, 0xf0, 0x00}
} else {
progInfo = []byte{0x1b, 0xe1, 0x00, 0xf0, 0x00, //h264 or h265*
0x0f, 0xe1, 0x01, 0xf0, 0x00, //mp3 or aac
}
}
pmtHeader[2] = byte(len(progInfo) + 9 + 4)
if muxer.pmtCc > 0xf {
muxer.pmtCc = 0
}
tsHeader[3] |= muxer.pmtCc & 0x0f
muxer.pmtCc++
if soundFormat == 2 ||
soundFormat == 14 {
if hasVideo {
progInfo[5] = 0x4
} else {
progInfo[0] = 0x4
}
}
copy(muxer.pmt[i:], tsHeader)
i += len(tsHeader)
copy(muxer.pmt[i:], pmtHeader)
i += len(pmtHeader)
copy(muxer.pmt[i:], progInfo[0:])
i += len(progInfo)
crc32Value := GenCrc32(muxer.pmt[5 : 5+len(pmtHeader)+len(progInfo)])
muxer.pmt[i] = byte(crc32Value >> 24)
i++
muxer.pmt[i] = byte(crc32Value >> 16)
i++
muxer.pmt[i] = byte(crc32Value >> 8)
i++
muxer.pmt[i] = byte(crc32Value)
i++
remainBytes = int(tsPacketLen - i)
for j = 0; j < remainBytes; j++ {
muxer.pmt[i+j] = 0xff
}
return muxer.pmt[0:]
}
func (muxer *Muxer) adaptationBufInit(src []byte, remainBytes byte) {
src[0] = byte(remainBytes - 1)
if remainBytes == 1 {
} else {
src[1] = 0x00
for i := 2; i < len(src); i++ {
src[i] = 0xff
}
}
return
}
func (muxer *Muxer) writePcr(b []byte, i byte, pcr int64) error {
b[i] = byte(pcr >> 25)
i++
b[i] = byte((pcr >> 17) & 0xff)
i++
b[i] = byte((pcr >> 9) & 0xff)
i++
b[i] = byte((pcr >> 1) & 0xff)
i++
b[i] = byte(((pcr & 0x1) << 7) | 0x7e)
i++
b[i] = 0x00
return nil
}
type pesHeader struct {
len byte
data [tsPacketLen]byte
}
//pesPacket return pes packet
func (header *pesHeader) packet(p *av.Packet, pts, dts int64) error {
//PES header
i := 0
header.data[i] = 0x00
i++
header.data[i] = 0x00
i++
header.data[i] = 0x01
i++
sid := audioSID
if p.IsVideo {
sid = videoSID
}
header.data[i] = byte(sid)
i++
flag := 0x80
ptslen := 5
dtslen := ptslen
headerSize := ptslen
if p.IsVideo && pts != dts {
flag |= 0x40
headerSize += 5 //add dts
}
size := len(p.Data) + headerSize + 3
if size > 0xffff {
size = 0
}
header.data[i] = byte(size >> 8)
i++
header.data[i] = byte(size)
i++
header.data[i] = 0x80
i++
header.data[i] = byte(flag)
i++
header.data[i] = byte(headerSize)
i++
header.writeTs(header.data[0:], i, flag>>6, pts)
i += ptslen
if p.IsVideo && pts != dts {
header.writeTs(header.data[0:], i, 1, dts)
i += dtslen
}
header.len = byte(i)
return nil
}
func (header *pesHeader) writeTs(src []byte, i int, fb int, ts int64) {
val := uint32(0)
if ts > 0x1ffffffff {
ts -= 0x1ffffffff
}
val = uint32(fb<<4) | ((uint32(ts>>30) & 0x07) << 1) | 1
src[i] = byte(val)
i++
val = ((uint32(ts>>15) & 0x7fff) << 1) | 1
src[i] = byte(val >> 8)
i++
src[i] = byte(val)
i++
val = (uint32(ts&0x7fff) << 1) | 1
src[i] = byte(val >> 8)
i++
src[i] = byte(val)
}