Ready-to-use SRT / WebRTC / RTSP / RTMP / LL-HLS media server and media proxy that allows to read, publish, proxy, record and playback video and audio streams.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

189 lines
3.3 KiB

package amf0
import (
"errors"
"fmt"
"math"
)
const (
markerNumber = 0x00
markerBoolean = 0x01
markerString = 0x02
markerObject = 0x03
markerMovieclip = 0x04
markerNull = 0x05
markerUndefined = 0x06
markerReference = 0x07
markerECMAArray = 0x08
markerObjectEnd = 0x09
markerStrictArray = 0x0A
markerDate = 0x0B
markerLongString = 0x0C
markerUnsupported = 0x0D
markerRecordset = 0x0E
markerXMLDocument = 0xF
markerTypedObject = 0x10
)
var errBufferTooShort = errors.New("buffer is too short")
// Unmarshal decodes AMF0 data.
func Unmarshal(buf []byte) ([]interface{}, error) {
var out []interface{}
for len(buf) != 0 {
var item interface{}
var err error
item, buf, err = unmarshal(buf)
if err != nil {
return nil, err
}
out = append(out, item)
}
return out, nil
}
func unmarshal(buf []byte) (interface{}, []byte, error) {
if len(buf) < 1 {
return nil, nil, errBufferTooShort
}
var marker byte
marker, buf = buf[0], buf[1:]
switch marker {
case markerNumber:
if len(buf) < 8 {
return nil, nil, errBufferTooShort
}
return math.Float64frombits(uint64(buf[0])<<56 | uint64(buf[1])<<48 | uint64(buf[2])<<40 | uint64(buf[3])<<32 |
uint64(buf[4])<<24 | uint64(buf[5])<<16 | uint64(buf[6])<<8 | uint64(buf[7])), buf[8:], nil
case markerBoolean:
if len(buf) < 1 {
return nil, nil, errBufferTooShort
}
return (buf[0] != 0), buf[1:], nil
case markerString:
if len(buf) < 2 {
return nil, nil, errBufferTooShort
}
le := uint16(buf[0])<<8 | uint16(buf[1])
buf = buf[2:]
if len(buf) < int(le) {
return nil, nil, errBufferTooShort
}
return string(buf[:le]), buf[le:], nil
case markerECMAArray:
if len(buf) < 4 {
return nil, nil, errBufferTooShort
}
buf = buf[4:]
out := ECMAArray{}
for {
if len(buf) < 2 {
return nil, nil, errBufferTooShort
}
keyLen := uint16(buf[0])<<8 | uint16(buf[1])
buf = buf[2:]
if keyLen == 0 {
break
}
if len(buf) < int(keyLen) {
return nil, nil, errBufferTooShort
}
key := string(buf[:keyLen])
buf = buf[keyLen:]
var value interface{}
var err error
value, buf, err = unmarshal(buf)
if err != nil {
return nil, nil, err
}
out = append(out, ObjectEntry{
Key: key,
Value: value,
})
}
if len(buf) < 1 {
return nil, nil, errBufferTooShort
}
if buf[0] != markerObjectEnd {
return nil, nil, fmt.Errorf("object end not found")
}
return out, buf[1:], nil
case markerObject:
out := Object{}
for {
if len(buf) < 2 {
return nil, nil, errBufferTooShort
}
keyLen := uint16(buf[0])<<8 | uint16(buf[1])
buf = buf[2:]
if keyLen == 0 {
break
}
if len(buf) < int(keyLen) {
return nil, nil, errBufferTooShort
}
key := string(buf[:keyLen])
buf = buf[keyLen:]
var value interface{}
var err error
value, buf, err = unmarshal(buf)
if err != nil {
return nil, nil, err
}
out = append(out, ObjectEntry{
Key: key,
Value: value,
})
}
if len(buf) < 1 {
return nil, nil, errBufferTooShort
}
if buf[0] != markerObjectEnd {
return nil, nil, fmt.Errorf("object end not found")
}
return out, buf[1:], nil
case markerNull:
return nil, buf, nil
default:
return nil, nil, fmt.Errorf("unsupported marker 0x%.2x", marker)
}
}