mirror of
https://github.com/AlexxIT/go2rtc.git
synced 2026-04-22 23:57:20 +08:00
166 lines
2.4 KiB
Go
166 lines
2.4 KiB
Go
package httpflv
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"math"
|
|
)
|
|
|
|
const (
|
|
TypeNumber byte = iota
|
|
TypeBoolean
|
|
TypeString
|
|
TypeObject
|
|
TypeEcmaArray = 8
|
|
TypeObjectEnd = 9
|
|
)
|
|
|
|
var Err = errors.New("amf0 read error")
|
|
|
|
// AMF0 spec: http://download.macromedia.com/pub/labs/amf/amf0_spec_121207.pdf
|
|
type AMF0 struct {
|
|
buf []byte
|
|
pos int
|
|
}
|
|
|
|
func NewReader(b []byte) *AMF0 {
|
|
return &AMF0{buf: b}
|
|
}
|
|
|
|
func (a *AMF0) ReadMetaData() map[string]any {
|
|
if b, _ := a.ReadByte(); b != TypeString {
|
|
return nil
|
|
}
|
|
if s, _ := a.ReadString(); s != "onMetaData" {
|
|
return nil
|
|
}
|
|
|
|
b, _ := a.ReadByte()
|
|
switch b {
|
|
case TypeObject:
|
|
v, _ := a.ReadObject()
|
|
return v
|
|
case TypeEcmaArray:
|
|
v, _ := a.ReadEcmaArray()
|
|
return v
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (a *AMF0) ReadMap() (map[any]any, error) {
|
|
dict := make(map[any]any)
|
|
|
|
for a.pos < len(a.buf) {
|
|
k, err := a.ReadItem()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
v, err := a.ReadItem()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
dict[k] = v
|
|
}
|
|
|
|
return dict, nil
|
|
}
|
|
|
|
func (a *AMF0) ReadItem() (any, error) {
|
|
dataType, err := a.ReadByte()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
switch dataType {
|
|
case TypeNumber:
|
|
return a.ReadNumber()
|
|
|
|
case TypeBoolean:
|
|
v, err := a.ReadByte()
|
|
return v != 0, err
|
|
|
|
case TypeString:
|
|
return a.ReadString()
|
|
|
|
case TypeObject:
|
|
return a.ReadObject()
|
|
|
|
case TypeObjectEnd:
|
|
return nil, nil
|
|
}
|
|
|
|
return nil, Err
|
|
}
|
|
|
|
func (a *AMF0) ReadByte() (byte, error) {
|
|
if a.pos >= len(a.buf) {
|
|
return 0, Err
|
|
}
|
|
|
|
v := a.buf[a.pos]
|
|
a.pos++
|
|
return v, nil
|
|
}
|
|
|
|
func (a *AMF0) ReadNumber() (float64, error) {
|
|
if a.pos+8 >= len(a.buf) {
|
|
return 0, Err
|
|
}
|
|
|
|
v := binary.BigEndian.Uint64(a.buf[a.pos : a.pos+8])
|
|
a.pos += 8
|
|
return math.Float64frombits(v), nil
|
|
}
|
|
|
|
func (a *AMF0) ReadString() (string, error) {
|
|
if a.pos+2 >= len(a.buf) {
|
|
return "", Err
|
|
}
|
|
|
|
size := int(binary.BigEndian.Uint16(a.buf[a.pos:]))
|
|
a.pos += 2
|
|
|
|
if a.pos+size >= len(a.buf) {
|
|
return "", Err
|
|
}
|
|
|
|
s := string(a.buf[a.pos : a.pos+size])
|
|
a.pos += size
|
|
|
|
return s, nil
|
|
}
|
|
|
|
func (a *AMF0) ReadObject() (map[string]any, error) {
|
|
obj := make(map[string]any)
|
|
|
|
for {
|
|
k, err := a.ReadString()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
v, err := a.ReadItem()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if k == "" {
|
|
break
|
|
}
|
|
|
|
obj[k] = v
|
|
}
|
|
|
|
return obj, nil
|
|
}
|
|
|
|
func (a *AMF0) ReadEcmaArray() (map[string]any, error) {
|
|
if a.pos+4 >= len(a.buf) {
|
|
return nil, Err
|
|
}
|
|
a.pos += 4 // skip size
|
|
|
|
return a.ReadObject()
|
|
}
|