Rewrite support MPEG-TS client
This commit is contained in:
+87
-40
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user