Update MPEG-TS consumer compatibility

This commit is contained in:
Alexey Khit
2023-08-20 18:43:12 +03:00
parent da02a97a00
commit 2ffd859f0e
6 changed files with 71 additions and 36 deletions
+2
View File
@@ -12,6 +12,8 @@ const (
TypeAACMain = 1
TypeAACLC = 2
TypeESCAPE = 31
AUTime = 1024
)
// streamtype=5 - audio stream
+10
View File
@@ -70,6 +70,16 @@ func WriteADTSSize(b []byte, size uint16) {
return
}
func ADTSTimeSize(b []byte) uint32 {
var units uint32
for len(b) > ADTSHeaderSize {
auSize := ReadADTSSize(b)
b = b[auSize:]
units++
}
return units * AUTime
}
func CodecToADTS(codec *core.Codec) []byte {
s := core.Between(codec.FmtpLine, "config=", ";")
conf, err := hex.DecodeString(s)
+2 -2
View File
@@ -32,7 +32,7 @@ func RTPDepay(handler core.HandlerFunc) core.HandlerFunc {
headers = headers[2:]
units = units[unitSize:]
timestamp += 1024
timestamp += AUTime
clone := *packet
clone.Version = RTPPacketVersionAAC
@@ -92,7 +92,7 @@ func ADTStoRTP(src []byte) (dst []byte) {
func RTPTimeSize(b []byte) uint32 {
// convert RTP header size to units count
units := binary.BigEndian.Uint16(b) >> 4
return 1024 * uint32(units)
return uint32(units) * AUTime
}
func RTPToADTS(codec *core.Codec, handler core.HandlerFunc) core.HandlerFunc {
+15 -5
View File
@@ -7,7 +7,8 @@ import (
)
const StartCode = "\x00\x00\x00\x01"
const startAUD = StartCode + "\x09\xF0" + StartCode
const startAUD = StartCode + "\x09\xF0"
const startAUDstart = startAUD + StartCode
// EncodeToAVCC
// will change original slice data!
@@ -19,12 +20,12 @@ func EncodeToAVCC(b []byte, safeAppend bool) []byte {
const minSize = len(StartCode) + 1
// 1. Check frist "start code"
if len(b) < len(startAUD) || string(b[:len(StartCode)]) != StartCode {
if len(b) < len(startAUDstart) || string(b[:len(StartCode)]) != StartCode {
return nil
}
// 2. Skip Access unit delimiter (AUD) from FFmpeg
if string(b[:len(startAUD)]) == startAUD {
if string(b[:len(startAUDstart)]) == startAUDstart {
b = b[6:]
}
@@ -85,6 +86,15 @@ func DecodeAVCC(b []byte, safeClone bool) []byte {
return b
}
// DecodeAVCCWithAUD - AUD doesn't important for FFmpeg, but important for Safari
func DecodeAVCCWithAUD(src []byte) []byte {
dst := make([]byte, len(startAUD)+len(src))
copy(dst, startAUD)
copy(dst[len(startAUD):], src)
DecodeAVCC(dst[len(startAUD):], false)
return dst
}
const (
h264PFrame = 1
h264IFrame = 5
@@ -97,11 +107,11 @@ const (
// IndexFrame - get new frame start position in the AnnexB stream
func IndexFrame(b []byte) int {
if len(b) < len(startAUD) {
if len(b) < len(startAUDstart) {
return -1
}
for i := len(startAUD); ; {
for i := len(startAUDstart); ; {
if di := bytes.Index(b[i:], []byte(StartCode)); di < 0 {
break
} else {
+6 -2
View File
@@ -1,6 +1,7 @@
package mpegts
import (
"errors"
"io"
"github.com/AlexxIT/go2rtc/pkg/aac"
@@ -78,8 +79,11 @@ func (c *Consumer) AddTrack(media *core.Media, codec *core.Codec, track *core.Re
case core.CodecAAC:
pid := c.muxer.AddTrack(StreamTypeAAC)
// convert timestamp to 90000Hz clock
dt := 90000 / float64(track.Codec.ClockRate)
sender.Handler = func(pkt *rtp.Packet) {
pts := pkt.Timestamp * 90000 / track.Codec.ClockRate
pts := uint32(float64(pkt.Timestamp) * dt)
b := c.muxer.GetPayload(pid, pts, pkt.Payload)
if n, err := c.wr.Write(b); err == nil {
c.Send += n
@@ -89,7 +93,7 @@ func (c *Consumer) AddTrack(media *core.Media, codec *core.Codec, track *core.Re
if track.Codec.IsRTP() {
sender.Handler = aac.RTPToADTS(track.Codec, sender.Handler)
} else {
panic("todo")
return errors.New("mpegts: aac not supported")
}
}
+36 -27
View File
@@ -28,7 +28,7 @@ func (m *Muxer) AddTrack(streamType byte) (pid uint16) {
pes.StreamID = 0xC0
}
pid = startPID + 1 + uint16(len(m.pes))
pid = pes0PID + uint16(len(m.pes))
m.pes[pid] = pes
return
@@ -42,37 +42,41 @@ func (m *Muxer) GetHeader() []byte {
}
// GetPayload - safe to run concurently with different pid
func (m *Muxer) GetPayload(pid uint16, pts uint32, payload []byte) []byte {
func (m *Muxer) GetPayload(pid uint16, timestamp uint32, payload []byte) []byte {
pes := m.pes[pid]
size := 8 + len(payload)
switch pes.StreamType {
case StreamTypeH264, StreamTypeH265:
payload = annexb.DecodeAVCCWithAUD(payload)
}
b := make([]byte, 14+len(payload))
_ = b[14] // bounds
if pes.Timestamp != 0 {
pes.PTS += timestamp - pes.Timestamp
}
//log.Print(pid, pes.PTS, timestamp, pes.Timestamp)
pes.Timestamp = timestamp
b[0] = 0
b[1] = 0
b[2] = 1
b[3] = pes.StreamID
b[6] = 0x80 // Marker bits (binary)
b[7] = 0x80 // PTS indicator
b[8] = 5 // PES header length
// min header size (3 byte) + adv header size (PES)
size := 3 + 5 + len(payload)
// zero size is OK for video stream
b := make([]byte, 6+3+5)
b[0], b[1], b[2] = 0, 0, 1 // Packet start code prefix
b[3] = pes.StreamID // Stream ID
// PES Packet length (zero value OK for video)
if size <= 0xFFFF {
binary.BigEndian.PutUint16(b[4:], uint16(size))
}
WriteTime(b[9:], pts)
// Optional PES header:
b[6] = 0x80 // Marker bits (binary)
b[7] = 0x80 // PTS indicator
b[8] = 5 // PES header length
copy(b[14:], payload)
WriteTime(b[9:], pes.PTS)
switch pes.StreamType {
case StreamTypeH264, StreamTypeH265:
annexb.DecodeAVCC(b[14:], false) // no need to safe clone after copy
}
pes.Payload = b
pes.Payload = append(b, payload...)
pes.Size = 1 // set PUSI in first PES
if pes.wr == nil {
@@ -91,16 +95,17 @@ func (m *Muxer) GetPayload(pid uint16, pts uint32, payload []byte) []byte {
}
const patPID = 0
const startPID = 0x20
const pmtPID = 0x1000
const pes0PID = 0x100
func (m *Muxer) writePAT(wr *bits.Writer) {
m.writeHeader(wr, patPID)
i := wr.Len() + 1 // start for CRC32
m.writePSIHeader(wr, 0, 4)
wr.WriteUint16(1) // Program num
wr.WriteBits8(0b111, 3) // Reserved bits (all to 1)
wr.WriteBits16(startPID, 13) // Program map PID
wr.WriteUint16(1) // Program num
wr.WriteBits8(0b111, 3) // Reserved bits (all to 1)
wr.WriteBits16(pmtPID, 13) // Program map PID
crc := checksum(wr.Bytes()[i:])
wr.WriteBytes(byte(crc), byte(crc>>8), byte(crc>>16), byte(crc>>24)) // CRC32 (little endian)
@@ -109,7 +114,7 @@ func (m *Muxer) writePAT(wr *bits.Writer) {
}
func (m *Muxer) writePMT(wr *bits.Writer) {
m.writeHeader(wr, startPID)
m.writeHeader(wr, pmtPID)
i := wr.Len() + 1 // start for CRC32
m.writePSIHeader(wr, 2, 4+uint16(len(m.pes))*5) // 4 bytes below + 5 bytes each PES
@@ -120,7 +125,11 @@ func (m *Muxer) writePMT(wr *bits.Writer) {
wr.WriteBits8(0, 2) // Program info length unused bits (all to 0)
wr.WriteBits16(0, 10) // Program info length
for pid, pes := range m.pes {
for pid := uint16(pes0PID); ; pid++ {
pes, ok := m.pes[pid]
if !ok {
break
}
wr.WriteByte(pes.StreamType) // Stream type
wr.WriteBits8(0b111, 3) // Reserved bits (all to 1)
wr.WriteBits16(pid, 13) // Elementary PID