install go2rtc on bob
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
package mpegts
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/AlexxIT/go2rtc/pkg/aac"
|
||||
"github.com/AlexxIT/go2rtc/pkg/core"
|
||||
"github.com/AlexxIT/go2rtc/pkg/h264"
|
||||
"github.com/AlexxIT/go2rtc/pkg/h265"
|
||||
"github.com/pion/rtp"
|
||||
)
|
||||
|
||||
type Producer struct {
|
||||
core.Connection
|
||||
rd *core.ReadBuffer
|
||||
}
|
||||
|
||||
func Open(rd io.Reader) (*Producer, error) {
|
||||
prod := &Producer{
|
||||
Connection: core.Connection{
|
||||
ID: core.NewID(),
|
||||
FormatName: "mpegts",
|
||||
Transport: rd,
|
||||
},
|
||||
rd: core.NewReadBuffer(rd),
|
||||
}
|
||||
if err := prod.probe(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return prod, nil
|
||||
}
|
||||
|
||||
func (c *Producer) GetTrack(media *core.Media, codec *core.Codec) (*core.Receiver, error) {
|
||||
receiver, _ := c.Connection.GetTrack(media, codec)
|
||||
receiver.ID = StreamType(codec)
|
||||
return receiver, nil
|
||||
}
|
||||
|
||||
func (c *Producer) Start() error {
|
||||
rd := NewDemuxer()
|
||||
|
||||
for {
|
||||
pkt, err := rd.ReadPacket(c.rd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.Recv += len(pkt.Payload)
|
||||
|
||||
//log.Printf("[mpegts] size: %6d, muxer: %10d, pt: %2d", len(pkt.Payload), pkt.Timestamp, pkt.PayloadType)
|
||||
|
||||
for _, receiver := range c.Receivers {
|
||||
if receiver.ID == pkt.PayloadType {
|
||||
TimestampToRTP(pkt, receiver.Codec)
|
||||
receiver.WriteRTP(pkt)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Producer) probe() error {
|
||||
c.rd.BufferSize = core.ProbeSize
|
||||
defer c.rd.Reset()
|
||||
|
||||
rd := NewDemuxer()
|
||||
|
||||
// Strategy:
|
||||
// 1. Wait packet with metadata, init other packets for wait
|
||||
// 2. Wait other packets
|
||||
// 3. Stop after timeout
|
||||
waitType := []byte{StreamTypeMetadata}
|
||||
timeout := time.Now().Add(core.ProbeTimeout)
|
||||
|
||||
for len(waitType) != 0 && time.Now().Before(timeout) {
|
||||
pkt, err := rd.ReadPacket(c.rd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if we wait this type
|
||||
if i := bytes.IndexByte(waitType, pkt.PayloadType); i < 0 {
|
||||
continue
|
||||
} else {
|
||||
waitType = append(waitType[:i], waitType[i+1:]...)
|
||||
}
|
||||
|
||||
switch pkt.PayloadType {
|
||||
case StreamTypeMetadata:
|
||||
for _, streamType := range pkt.Payload {
|
||||
switch streamType {
|
||||
case StreamTypeH264, StreamTypeH265, StreamTypeAAC, StreamTypePrivateOPUS, StreamTypePCMATapo:
|
||||
waitType = append(waitType, streamType)
|
||||
}
|
||||
}
|
||||
|
||||
case StreamTypeH264:
|
||||
codec := h264.AVCCToCodec(pkt.Payload)
|
||||
media := &core.Media{
|
||||
Kind: core.KindVideo,
|
||||
Direction: core.DirectionRecvonly,
|
||||
Codecs: []*core.Codec{codec},
|
||||
}
|
||||
c.Medias = append(c.Medias, media)
|
||||
|
||||
case StreamTypeH265:
|
||||
codec := h265.AVCCToCodec(pkt.Payload)
|
||||
media := &core.Media{
|
||||
Kind: core.KindVideo,
|
||||
Direction: core.DirectionRecvonly,
|
||||
Codecs: []*core.Codec{codec},
|
||||
}
|
||||
c.Medias = append(c.Medias, media)
|
||||
|
||||
case StreamTypeAAC:
|
||||
codec := aac.RTPToCodec(pkt.Payload)
|
||||
media := &core.Media{
|
||||
Kind: core.KindAudio,
|
||||
Direction: core.DirectionRecvonly,
|
||||
Codecs: []*core.Codec{codec},
|
||||
}
|
||||
c.Medias = append(c.Medias, media)
|
||||
|
||||
case StreamTypePrivateOPUS:
|
||||
codec := &core.Codec{
|
||||
Name: core.CodecOpus,
|
||||
ClockRate: 48000,
|
||||
Channels: 2,
|
||||
}
|
||||
media := &core.Media{
|
||||
Kind: core.KindAudio,
|
||||
Direction: core.DirectionRecvonly,
|
||||
Codecs: []*core.Codec{codec},
|
||||
}
|
||||
c.Medias = append(c.Medias, media)
|
||||
|
||||
case StreamTypePCMATapo:
|
||||
codec := &core.Codec{
|
||||
Name: core.CodecPCMA,
|
||||
ClockRate: 8000,
|
||||
}
|
||||
media := &core.Media{
|
||||
Kind: core.KindAudio,
|
||||
Direction: core.DirectionRecvonly,
|
||||
Codecs: []*core.Codec{codec},
|
||||
}
|
||||
c.Medias = append(c.Medias, media)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func StreamType(codec *core.Codec) uint8 {
|
||||
switch codec.Name {
|
||||
case core.CodecH264:
|
||||
return StreamTypeH264
|
||||
case core.CodecH265:
|
||||
return StreamTypeH265
|
||||
case core.CodecAAC:
|
||||
return StreamTypeAAC
|
||||
case core.CodecPCMA:
|
||||
return StreamTypePCMATapo
|
||||
case core.CodecOpus:
|
||||
return StreamTypePrivateOPUS
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func TimestampToRTP(rtp *rtp.Packet, codec *core.Codec) {
|
||||
if codec.ClockRate == ClockRate {
|
||||
return
|
||||
}
|
||||
rtp.Timestamp = uint32(float64(rtp.Timestamp) * float64(codec.ClockRate) / ClockRate)
|
||||
}
|
||||
Reference in New Issue
Block a user