Rewrite support MPEG-TS client

This commit is contained in:
Alexey Khit
2023-08-17 05:41:27 +03:00
parent 4a82eb3503
commit b3def6cfa2
11 changed files with 569 additions and 367 deletions
+87 -40
View File
@@ -1,79 +1,126 @@
package mpegts
import (
"bytes"
"io"
"time"
"github.com/AlexxIT/go2rtc/pkg/aac"
"github.com/AlexxIT/go2rtc/pkg/core"
"net/http"
"github.com/AlexxIT/go2rtc/pkg/h264"
"github.com/AlexxIT/go2rtc/pkg/h265"
)
type Client struct {
core.Listener
URL string
rd *core.ReadSeeker
medias []*core.Media
receivers []*core.Receiver
res *http.Response
recv int
}
func NewClient(res *http.Response) *Client {
return &Client{res: res}
func Open(rd io.Reader) (*Client, error) {
client := &Client{rd: core.NewReadSeeker(rd)}
if err := client.describe(); err != nil {
return nil, err
}
return client, nil
}
func (c *Client) Handle() error {
reader := NewReader()
func (c *Client) describe() error {
c.rd.BufferSize = core.ProbeSize
defer c.rd.Rewind()
b := make([]byte, 1024*256) // 256K
rd := NewReader()
probe := core.NewProbe(c.medias == nil)
for probe == nil || probe.Active() {
n, err := c.res.Body.Read(b)
// Strategy:
// 1. Wait packet with metadata, init other packets for wait
// 2. Wait other packets
// 3. Stop after timeout
waitType := []byte{metadataType}
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
}
c.recv += n
// check if we wait this type
if i := bytes.IndexByte(waitType, pkt.PayloadType); i < 0 {
continue
} else {
waitType = append(waitType[:i], waitType[i+1:]...)
}
reader.AppendBuffer(b[:n])
reading:
for {
packet := reader.GetPacket()
if packet == nil {
break
}
for _, receiver := range c.receivers {
if receiver.ID == packet.PayloadType {
receiver.WriteRTP(packet)
continue reading
switch pkt.PayloadType {
case metadataType:
for _, streamType := range pkt.Payload {
switch streamType {
case StreamTypeH264, StreamTypeH265, StreamTypeAAC:
waitType = append(waitType, streamType)
}
}
// count track on probe state even if not support it
probe.Append(packet.PayloadType)
media := GetMedia(packet)
if media == nil {
continue // unsupported codec
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)
receiver := core.NewReceiver(media, media.Codecs[0])
receiver.ID = packet.PayloadType
c.receivers = append(c.receivers, receiver)
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)
receiver.WriteRTP(packet)
//log.Printf("[AVC] %v, len: %d, pts: %d ts: %10d", h264.Types(packet.Payload), len(packet.Payload), pkt.PTS, packet.Timestamp)
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)
}
}
return nil
}
func (c *Client) play() error {
rd := NewReader()
for {
pkt, err := rd.ReadPacket(c.rd)
if err != nil {
return err
}
//log.Printf("[mpegts] size: %6d, ts: %10d, pt: %2d", len(pkt.Payload), pkt.Timestamp, pkt.PayloadType)
for _, receiver := range c.receivers {
if receiver.ID == pkt.PayloadType {
pkt.Timestamp = PTSToTimestamp(pkt.Timestamp, receiver.Codec.ClockRate)
receiver.WriteRTP(pkt)
break
}
}
}
}
func (c *Client) Close() error {
_ = c.res.Body.Close()
if closer, ok := c.rd.Reader.(io.Closer); ok {
return closer.Close()
}
return nil
}