mediamtx/internal/rtmp/rawmessage/reader.go

217 lines
4.4 KiB
Go
Raw Normal View History

2022-06-04 23:06:40 +00:00
package rawmessage
2022-05-16 09:57:29 +00:00
import (
"bufio"
"errors"
"fmt"
2022-06-04 23:06:40 +00:00
"io"
"github.com/aler9/rtsp-simple-server/internal/rtmp/chunk"
2022-05-16 09:57:29 +00:00
)
var errMoreChunksNeeded = errors.New("more chunks are needed")
2022-06-04 23:06:40 +00:00
type readerChunkStream struct {
mr *Reader
2022-05-16 09:57:29 +00:00
curTimestamp *uint32
2022-06-04 23:06:40 +00:00
curType *chunk.MessageType
2022-05-16 09:57:29 +00:00
curMessageStreamID *uint32
curBodyLen *uint32
curBody *[]byte
}
2022-06-04 23:06:40 +00:00
func (rc *readerChunkStream) read(typ byte) (*Message, error) {
2022-05-16 09:57:29 +00:00
switch typ {
case 0:
if rc.curBody != nil {
return nil, fmt.Errorf("received type 0 chunk but expected type 3 chunk")
}
2022-06-04 23:06:40 +00:00
var c0 chunk.Chunk0
2022-05-16 09:57:29 +00:00
err := c0.Read(rc.mr.r, rc.mr.chunkSize)
if err != nil {
return nil, err
}
v1 := c0.MessageStreamID
rc.curMessageStreamID = &v1
v2 := c0.Type
rc.curType = &v2
v3 := c0.Timestamp
rc.curTimestamp = &v3
v4 := c0.BodyLen
rc.curBodyLen = &v4
if c0.BodyLen != uint32(len(c0.Body)) {
rc.curBody = &c0.Body
return nil, errMoreChunksNeeded
}
2022-06-04 23:06:40 +00:00
return &Message{
2022-05-16 09:57:29 +00:00
Timestamp: c0.Timestamp,
Type: c0.Type,
MessageStreamID: c0.MessageStreamID,
Body: c0.Body,
}, nil
case 1:
if rc.curTimestamp == nil {
return nil, fmt.Errorf("received type 1 chunk without previous chunk")
}
if rc.curBody != nil {
return nil, fmt.Errorf("received type 1 chunk but expected type 3 chunk")
}
2022-06-04 23:06:40 +00:00
var c1 chunk.Chunk1
2022-05-16 09:57:29 +00:00
err := c1.Read(rc.mr.r, rc.mr.chunkSize)
if err != nil {
return nil, err
}
v2 := c1.Type
rc.curType = &v2
v3 := *rc.curTimestamp + c1.TimestampDelta
rc.curTimestamp = &v3
v4 := c1.BodyLen
rc.curBodyLen = &v4
if c1.BodyLen != uint32(len(c1.Body)) {
rc.curBody = &c1.Body
return nil, errMoreChunksNeeded
}
2022-06-04 23:06:40 +00:00
return &Message{
2022-05-16 09:57:29 +00:00
Timestamp: *rc.curTimestamp + c1.TimestampDelta,
Type: c1.Type,
MessageStreamID: *rc.curMessageStreamID,
Body: c1.Body,
}, nil
case 2:
if rc.curTimestamp == nil {
return nil, fmt.Errorf("received type 2 chunk without previous chunk")
}
if rc.curBody != nil {
return nil, fmt.Errorf("received type 2 chunk but expected type 3 chunk")
}
chunkBodyLen := int(*rc.curBodyLen)
if chunkBodyLen > rc.mr.chunkSize {
chunkBodyLen = rc.mr.chunkSize
}
2022-06-04 23:06:40 +00:00
var c2 chunk.Chunk2
2022-05-16 09:57:29 +00:00
err := c2.Read(rc.mr.r, chunkBodyLen)
if err != nil {
return nil, err
}
v3 := *rc.curTimestamp + c2.TimestampDelta
rc.curTimestamp = &v3
if chunkBodyLen != len(c2.Body) {
rc.curBody = &c2.Body
return nil, errMoreChunksNeeded
}
2022-06-04 23:06:40 +00:00
return &Message{
2022-05-16 09:57:29 +00:00
Timestamp: *rc.curTimestamp + c2.TimestampDelta,
Type: *rc.curType,
MessageStreamID: *rc.curMessageStreamID,
Body: c2.Body,
}, nil
default: // 3
if rc.curTimestamp == nil {
return nil, fmt.Errorf("received type 3 chunk without previous chunk")
}
if rc.curBody == nil {
return nil, fmt.Errorf("unsupported")
}
chunkBodyLen := int(*rc.curBodyLen)
if chunkBodyLen > rc.mr.chunkSize {
chunkBodyLen = rc.mr.chunkSize
}
2022-06-04 23:06:40 +00:00
var c3 chunk.Chunk3
2022-05-16 09:57:29 +00:00
err := c3.Read(rc.mr.r, chunkBodyLen)
if err != nil {
return nil, err
}
*rc.curBody = append(*rc.curBody, c3.Body...)
if *rc.curBodyLen != uint32(len(*rc.curBody)) {
return nil, errMoreChunksNeeded
}
body := *rc.curBody
rc.curBody = nil
2022-06-04 23:06:40 +00:00
return &Message{
2022-05-16 09:57:29 +00:00
Timestamp: *rc.curTimestamp,
Type: *rc.curType,
MessageStreamID: *rc.curMessageStreamID,
Body: body,
}, nil
}
}
2022-06-04 23:06:40 +00:00
// Reader is a raw message reader.
type Reader struct {
2022-05-16 09:57:29 +00:00
r *bufio.Reader
chunkSize int
2022-06-04 23:06:40 +00:00
chunkStreams map[byte]*readerChunkStream
2022-05-16 09:57:29 +00:00
}
2022-06-04 23:06:40 +00:00
// NewReader allocates a Reader.
func NewReader(r io.Reader) *Reader {
return &Reader{
r: bufio.NewReader(r),
2022-05-16 09:57:29 +00:00
chunkSize: 128,
2022-06-04 23:06:40 +00:00
chunkStreams: make(map[byte]*readerChunkStream),
2022-05-16 09:57:29 +00:00
}
}
// SetChunkSize sets the maximum chunk size.
2022-06-04 23:06:40 +00:00
func (r *Reader) SetChunkSize(v int) {
r.chunkSize = v
2022-05-16 09:57:29 +00:00
}
2022-06-04 23:06:40 +00:00
// Read reads a Message.
func (r *Reader) Read() (*Message, error) {
2022-05-16 09:57:29 +00:00
for {
2022-06-04 23:06:40 +00:00
byt, err := r.r.ReadByte()
2022-05-16 09:57:29 +00:00
if err != nil {
return nil, err
}
typ := byt >> 6
chunkStreamID := byt & 0x3F
2022-06-04 23:06:40 +00:00
rc, ok := r.chunkStreams[chunkStreamID]
2022-05-16 09:57:29 +00:00
if !ok {
2022-06-04 23:06:40 +00:00
rc = &readerChunkStream{mr: r}
r.chunkStreams[chunkStreamID] = rc
2022-05-16 09:57:29 +00:00
}
2022-06-04 23:06:40 +00:00
r.r.UnreadByte()
2022-05-16 09:57:29 +00:00
msg, err := rc.read(typ)
if err != nil {
if err == errMoreChunksNeeded {
continue
}
return nil, err
}
msg.ChunkStreamID = chunkStreamID
return msg, err
}
}