Files
plugin-ps/mpegps/mpegps.go

160 lines
3.3 KiB
Go

package mpegps
import (
"encoding/binary"
"errors"
"io"
"m7s.live/engine/v4/util"
)
const (
StartCodePS = 0x000001ba
StartCodeSYS = 0x000001bb
StartCodeMAP = 0x000001bc
StartCodeVideo = 0x000001e0
StartCodeAudio = 0x000001c0
PrivateStreamCode = 0x000001bd
MEPGProgramEndCode = 0x000001b9
)
type EsHandler interface {
ReceiveAudio(MpegPsEsStream)
ReceiveVideo(MpegPsEsStream)
ReceivePSM(util.Buffer, bool, bool)
}
type MpegPsEsStream struct {
Type byte
util.Buffer
PTS uint32
DTS uint32
}
type MpegPsStream struct {
buffer util.Buffer
EsHandler
audio MpegPsEsStream
video MpegPsEsStream
}
func (ps *MpegPsStream) Reset() {
ps.buffer.Reset()
ps.audio.Reset()
if ps.video.Buffer.CanRead() {
ps.ReceiveVideo(ps.video)
ps.video.Buffer = make(util.Buffer, 0)
} else {
ps.video.Reset()
}
}
func (ps *MpegPsStream) Feed(data util.Buffer) (err error) {
reader := &data
if ps.buffer.CanRead() {
ps.buffer.Write(data)
reader = &ps.buffer
}
var begin util.Buffer
var payload []byte
var frame MpegPsEsStream
defer func() {
if err != nil && begin.CanRead() {
ps.buffer.Reset()
ps.buffer.Write(begin)
}
}()
for err == nil && reader.CanReadN(4) {
begin = *reader
code := reader.ReadUint32()
switch code {
case StartCodePS:
if reader.CanReadN(9) {
reader.ReadN(9)
if reader.CanRead() {
psl := reader.ReadByte() & 0x07
if reader.CanReadN(int(psl)) {
reader.ReadN(int(psl))
continue
}
}
}
err = io.ErrShortBuffer
case StartCodeSYS, PrivateStreamCode:
_, err = ps.ReadPayload(reader)
case StartCodeMAP:
err = ps.decProgramStreamMap(reader)
case StartCodeVideo:
payload, err = ps.ReadPayload(reader)
if err == nil {
frame, err = ps.video.parsePESPacket(payload)
if err == nil {
ps.ReceiveVideo(frame)
}
}
case StartCodeAudio:
payload, err = ps.ReadPayload(reader)
if err == nil {
frame, err = ps.audio.parsePESPacket(payload)
if err == nil {
ps.ReceiveAudio(frame)
}
}
case MEPGProgramEndCode:
return
default:
err = errors.New("start code error")
}
}
return
}
func (ps *MpegPsStream) ReadPayload(data *util.Buffer) (payload []byte, err error) {
if !data.CanReadN(2) {
return nil, io.ErrShortBuffer
}
payloadlen := data.ReadUint16()
if data.CanReadN(int(payloadlen)) {
payload = data.ReadN(int(payloadlen))
} else {
err = io.ErrShortBuffer
}
return
}
func (ps *MpegPsStream) decProgramStreamMap(data *util.Buffer) error {
psm, err := ps.ReadPayload(data)
if err != nil {
return err
}
l := len(psm)
index := 2
programStreamInfoLen := binary.BigEndian.Uint16(psm[index:])
index += 2
index += int(programStreamInfoLen)
programStreamMapLen := binary.BigEndian.Uint16(psm[index:])
index += 2
for programStreamMapLen > 0 {
if l <= index+1 {
break
}
streamType := psm[index]
index++
elementaryStreamID := psm[index]
index++
if elementaryStreamID >= 0xe0 && elementaryStreamID <= 0xef {
ps.video.Type = streamType
} else if elementaryStreamID >= 0xc0 && elementaryStreamID <= 0xdf {
ps.audio.Type = streamType
}
if l <= index+1 {
break
}
elementaryStreamInfoLength := binary.BigEndian.Uint16(psm[index:])
index += 2
index += int(elementaryStreamInfoLength)
programStreamMapLen -= 4 + elementaryStreamInfoLength
}
return nil
}