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.
 
 
 
 
 
 

171 lines
2.6 KiB

// Package amf0 contains an AMF0 marshaler and unmarshaler.
package amf0
import (
"fmt"
"math"
)
// Marshal encodes AMF0 data.
func Marshal(data []interface{}) ([]byte, error) {
n, err := marshalSize(data)
if err != nil {
return nil, err
}
buf := make([]byte, n)
n = 0
for _, item := range data {
n += marshalItem(item, buf[n:])
}
return buf, nil
}
func marshalSize(data []interface{}) (int, error) {
n := 0
for _, item := range data {
in, err := marshalSizeItem(item)
if err != nil {
return 0, err
}
n += in
}
return n, nil
}
func marshalSizeItem(item interface{}) (int, error) {
switch item := item.(type) {
case float64:
return 9, nil
case bool:
return 2, nil
case string:
return 3 + len(item), nil
case ECMAArray:
n := 5
for _, entry := range item {
en, err := marshalSizeItem(entry.Value)
if err != nil {
return 0, err
}
n += 2 + len(entry.Key) + en
}
n += 3
return n, nil
case Object:
n := 1
for _, entry := range item {
en, err := marshalSizeItem(entry.Value)
if err != nil {
return 0, err
}
n += 2 + len(entry.Key) + en
}
n += 3
return n, nil
case nil:
return 1, nil
default:
return 0, fmt.Errorf("unsupported data type: %T", item)
}
}
func marshalItem(item interface{}, buf []byte) int {
switch item := item.(type) {
case float64:
v := math.Float64bits(item)
buf[0] = markerNumber
buf[1] = byte(v >> 56)
buf[2] = byte(v >> 48)
buf[3] = byte(v >> 40)
buf[4] = byte(v >> 32)
buf[5] = byte(v >> 24)
buf[6] = byte(v >> 16)
buf[7] = byte(v >> 8)
buf[8] = byte(v)
return 9
case bool:
buf[0] = markerBoolean
if item {
buf[1] = 1
}
return 2
case string:
le := len(item)
buf[0] = markerString
buf[1] = byte(le >> 8)
buf[2] = byte(le)
copy(buf[3:], item)
return 3 + le
case ECMAArray:
le := len(item)
buf[0] = markerECMAArray
buf[1] = byte(le >> 24)
buf[2] = byte(le >> 16)
buf[3] = byte(le >> 8)
buf[4] = byte(le)
n := 5
for _, entry := range item {
le := len(entry.Key)
buf[n] = byte(le >> 8)
buf[n+1] = byte(le)
copy(buf[n+2:], entry.Key)
n += 2 + le
n += marshalItem(entry.Value, buf[n:])
}
buf[n] = 0
buf[n+1] = 0
buf[n+2] = markerObjectEnd
return n + 3
case Object:
buf[0] = markerObject
n := 1
for _, entry := range item {
le := len(entry.Key)
buf[n] = byte(le >> 8)
buf[n+1] = byte(le)
copy(buf[n+2:], entry.Key)
n += 2 + le
n += marshalItem(entry.Value, buf[n:])
}
buf[n] = 0
buf[n+1] = 0
buf[n+2] = markerObjectEnd
return n + 3
default:
buf[0] = markerNull
return 1
}
}