141 lines
3.2 KiB
Go
141 lines
3.2 KiB
Go
|
package rtmp
|
||
|
|
||
|
import (
|
||
|
"net"
|
||
|
"time"
|
||
|
"encoding/binary"
|
||
|
)
|
||
|
|
||
|
type chnk_stream struct {
|
||
|
timestamp uint32
|
||
|
last_msg_strm_id uint32
|
||
|
timedelta uint32
|
||
|
}
|
||
|
|
||
|
type message struct {
|
||
|
// msg_strm_id uint32
|
||
|
data []byte
|
||
|
curr_bytes_read uint32
|
||
|
timestamp uint32
|
||
|
msg_type uint8
|
||
|
msg_len uint32
|
||
|
}
|
||
|
|
||
|
|
||
|
func read_basic_header(conn net.Conn) (uint8, uint32, error) {
|
||
|
fmt_csid_byte := make([]byte, 1)
|
||
|
if _, err := conn.Read(fmt_csid_byte); err != nil {
|
||
|
return 0, 0, err
|
||
|
}
|
||
|
format := uint8(fmt_csid_byte[0] >> 6)
|
||
|
var csid uint32
|
||
|
switch fmt_csid_byte[0] & 0x3f {
|
||
|
case 0:
|
||
|
csid_true := make([]byte, 1)
|
||
|
if _, err := conn.Read(csid_true); err != nil {
|
||
|
return 0, 0, err
|
||
|
}
|
||
|
csid = uint32(csid_true[0]) + 64
|
||
|
case 1:
|
||
|
csid_true := make([]byte, 2)
|
||
|
if _, err := conn.Read(csid_true); err != nil {
|
||
|
return 0, 0, err
|
||
|
}
|
||
|
csid = uint32(binary.LittleEndian.Uint16(csid_true)) + 64
|
||
|
default:
|
||
|
csid = uint32(fmt_csid_byte[0] & 0x3f)
|
||
|
}
|
||
|
return format, csid, nil
|
||
|
}
|
||
|
|
||
|
func read_message_header_0(conn net.Conn, chnk_stream_ptr *chnk_stream, msg_ptr *message) (error) {
|
||
|
var extended_time bool
|
||
|
timestamp := make([]byte, 4)
|
||
|
if _, err := conn.Read(timestamp[1:]); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
chnk_stream_ptr.timestamp = binary.BigEndian.Uint32(timestamp)
|
||
|
|
||
|
if chnk_stream_ptr.timestamp ^ 0xffffff == 0 {
|
||
|
extended_time = true
|
||
|
}
|
||
|
|
||
|
msg_len := make([]byte, 4)
|
||
|
if _, err := conn.Read(msg_len[1:]); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
msg_ptr.msg_len = binary.BigEndian.Uint32(msg_len)
|
||
|
msg_ptr.data = make([]byte, msg_ptr.msg_len)
|
||
|
|
||
|
msg_typeid := make([]byte, 1)
|
||
|
if _, err := conn.Read(msg_typeid); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
msg_ptr.msg_type = msg_typeid[0]
|
||
|
|
||
|
msg_streamid := make([]byte, 4)
|
||
|
if _, err := conn.Read(msg_typeid); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
chnk_stream_ptr.last_msg_strm_id = binary.BigEndian.Uint32(msg_streamid)
|
||
|
|
||
|
if extended_time {
|
||
|
if _, err := conn.Read(timestamp); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
chnk_stream_ptr.timestamp = binary.BigEndian.Uint32(timestamp)
|
||
|
}
|
||
|
msg_ptr.timestamp = chnk_stream_ptr.timestamp
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func read_chunk_data(conn net.Conn, msg_ptr *message, chnk_size uint32) (error) {
|
||
|
bytes_left := msg_ptr.msg_len - msg_ptr.curr_bytes_read
|
||
|
var buffer_end uint32
|
||
|
if bytes_left < chnk_size {
|
||
|
buffer_end = bytes_left + msg_ptr.curr_bytes_read + 1
|
||
|
} else {
|
||
|
buffer_end = chnk_size + msg_ptr.curr_bytes_read + 1
|
||
|
}
|
||
|
n, err := conn.Read(msg_ptr.data[msg_ptr.curr_bytes_read:buffer_end])
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
msg_ptr.curr_bytes_read += uint32(n)
|
||
|
return nil
|
||
|
|
||
|
}
|
||
|
|
||
|
func ReadChunk(conn net.Conn, open_chnkstrms map[uint32]*chnk_stream, open_msgs map[uint32]*message, chnk_size uint32) (*message, error){
|
||
|
conn.SetDeadline(time.Now().Add(10 * time.Second))
|
||
|
|
||
|
format, csid, err := read_basic_header(conn)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
switch format {
|
||
|
case 0:
|
||
|
chnkstream_ptr := new(chnk_stream)
|
||
|
open_chnkstrms[csid] = chnkstream_ptr
|
||
|
msg_ptr := new(message)
|
||
|
|
||
|
if err := read_message_header_0(conn, chnkstream_ptr, msg_ptr); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if err := read_chunk_data(conn, msg_ptr, chnk_size); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if msg_ptr.msg_len > chnk_size {
|
||
|
open_msgs[chnkstream_ptr.last_msg_strm_id] = msg_ptr
|
||
|
return nil, nil
|
||
|
} else {
|
||
|
return msg_ptr, nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
conn.SetDeadline(time.Time{})
|
||
|
return nil, nil
|
||
|
}
|