live video streaming server in golang
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.
 
 
 

432 lines
9.4 KiB

package amf
import (
"encoding/binary"
"fmt"
"io"
"reflect"
"sort"
"time"
)
// amf3 polymorphic router
func (e *Encoder) EncodeAmf3(w io.Writer, val interface{}) (int, error) {
if val == nil {
return e.EncodeAmf3Null(w, true)
}
v := reflect.ValueOf(val)
if !v.IsValid() {
return e.EncodeAmf3Null(w, true)
}
switch v.Kind() {
case reflect.String:
return e.EncodeAmf3String(w, v.String(), true)
case reflect.Bool:
if v.Bool() {
return e.EncodeAmf3True(w, true)
} else {
return e.EncodeAmf3False(w, true)
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32:
n := v.Int()
if n >= 0 && n <= AMF3_INTEGER_MAX {
return e.EncodeAmf3Integer(w, uint32(n), true)
} else {
return e.EncodeAmf3Double(w, float64(n), true)
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
n := v.Uint()
if n <= AMF3_INTEGER_MAX {
return e.EncodeAmf3Integer(w, uint32(n), true)
} else {
return e.EncodeAmf3Double(w, float64(n), true)
}
case reflect.Int64:
return e.EncodeAmf3Double(w, float64(v.Int()), true)
case reflect.Uint64:
return e.EncodeAmf3Double(w, float64(v.Uint()), true)
case reflect.Float32, reflect.Float64:
return e.EncodeAmf3Double(w, float64(v.Float()), true)
case reflect.Array, reflect.Slice:
length := v.Len()
arr := make(Array, length)
for i := 0; i < length; i++ {
arr[i] = v.Index(int(i)).Interface()
}
return e.EncodeAmf3Array(w, arr, true)
case reflect.Map:
obj, ok := val.(Object)
if ok != true {
return 0, fmt.Errorf("encode amf3: unable to create object from map")
}
to := *new(TypedObject)
to.Object = obj
return e.EncodeAmf3Object(w, to, true)
}
if tm, ok := val.(time.Time); ok {
return e.EncodeAmf3Date(w, tm, true)
}
if to, ok := val.(TypedObject); ok {
return e.EncodeAmf3Object(w, to, true)
}
return 0, fmt.Errorf("encode amf3: unsupported type %s", v.Type())
}
// marker: 1 byte 0x00
// no additional data
func (e *Encoder) EncodeAmf3Undefined(w io.Writer, encodeMarker bool) (n int, err error) {
if encodeMarker {
if err = WriteMarker(w, AMF3_UNDEFINED_MARKER); err != nil {
return
}
n += 1
}
return
}
// marker: 1 byte 0x01
// no additional data
func (e *Encoder) EncodeAmf3Null(w io.Writer, encodeMarker bool) (n int, err error) {
if encodeMarker {
if err = WriteMarker(w, AMF3_NULL_MARKER); err != nil {
return
}
n += 1
}
return
}
// marker: 1 byte 0x02
// no additional data
func (e *Encoder) EncodeAmf3False(w io.Writer, encodeMarker bool) (n int, err error) {
if encodeMarker {
if err = WriteMarker(w, AMF3_FALSE_MARKER); err != nil {
return
}
n += 1
}
return
}
// marker: 1 byte 0x03
// no additional data
func (e *Encoder) EncodeAmf3True(w io.Writer, encodeMarker bool) (n int, err error) {
if encodeMarker {
if err = WriteMarker(w, AMF3_TRUE_MARKER); err != nil {
return
}
n += 1
}
return
}
// marker: 1 byte 0x04
func (e *Encoder) EncodeAmf3Integer(w io.Writer, val uint32, encodeMarker bool) (n int, err error) {
if encodeMarker {
if err = WriteMarker(w, AMF3_INTEGER_MARKER); err != nil {
return
}
n += 1
}
var m int
m, err = e.encodeAmf3Uint29(w, val)
if err != nil {
return
}
n += m
return
}
// marker: 1 byte 0x05
func (e *Encoder) EncodeAmf3Double(w io.Writer, val float64, encodeMarker bool) (n int, err error) {
if encodeMarker {
if err = WriteMarker(w, AMF3_DOUBLE_MARKER); err != nil {
return
}
n += 1
}
err = binary.Write(w, binary.BigEndian, &val)
if err != nil {
return
}
n += 8
return
}
// marker: 1 byte 0x06
// format:
// - u29 reference int. if reference, no more data. if not reference,
// length value of bytes to read to complete string.
func (e *Encoder) EncodeAmf3String(w io.Writer, val string, encodeMarker bool) (n int, err error) {
if encodeMarker {
if err = WriteMarker(w, AMF3_STRING_MARKER); err != nil {
return
}
n += 1
}
var m int
m, err = e.encodeAmf3Utf8(w, val)
if err != nil {
return
}
n += m
return
}
// marker: 1 byte 0x08
// format:
// - u29 reference int, if reference, no more data
// - timestamp double
func (e *Encoder) EncodeAmf3Date(w io.Writer, val time.Time, encodeMarker bool) (n int, err error) {
if encodeMarker {
if err = WriteMarker(w, AMF3_DATE_MARKER); err != nil {
return
}
n += 1
}
if err = WriteMarker(w, 0x01); err != nil {
return n, fmt.Errorf("amf3 encode: cannot encode u29 for array: %s", err)
}
n += 1
u64 := float64(val.Unix()) * 1000.0
err = binary.Write(w, binary.BigEndian, &u64)
if err != nil {
return n, fmt.Errorf("amf3 encode: unable to write date double: %s", err)
}
n += 8
return
}
// marker: 1 byte 0x09
// format:
// - u29 reference int. if reference, no more data.
// - string representing associative array if present
// - n values (length of u29)
func (e *Encoder) EncodeAmf3Array(w io.Writer, val Array, encodeMarker bool) (n int, err error) {
if encodeMarker {
if err = WriteMarker(w, AMF3_ARRAY_MARKER); err != nil {
return
}
n += 1
}
var m int
length := uint32(len(val))
u29 := uint32(length<<1) | 0x01
m, err = e.encodeAmf3Uint29(w, u29)
if err != nil {
return n, fmt.Errorf("amf3 encode: cannot encode u29 for array: %s", err)
}
n += m
m, err = e.encodeAmf3Utf8(w, "")
if err != nil {
return n, fmt.Errorf("amf3 encode: cannot encode empty string for array: %s", err)
}
n += m
for _, v := range val {
m, err := e.EncodeAmf3(w, v)
if err != nil {
return n, fmt.Errorf("amf3 encode: cannot encode array element: %s", err)
}
n += m
}
return
}
// marker: 1 byte 0x0a
// format: ugh
func (e *Encoder) EncodeAmf3Object(w io.Writer, val TypedObject, encodeMarker bool) (n int, err error) {
if encodeMarker {
if err = WriteMarker(w, AMF3_OBJECT_MARKER); err != nil {
return
}
n += 1
}
m := 0
trait := *NewTrait()
trait.Type = val.Type
trait.Dynamic = false
trait.Externalizable = false
for k, _ := range val.Object {
trait.Properties = append(trait.Properties, k)
}
sort.Strings(trait.Properties)
var u29 uint32 = 0x03
if trait.Dynamic {
u29 |= 0x02 << 2
}
if trait.Externalizable {
u29 |= 0x01 << 2
}
u29 |= uint32(len(trait.Properties)) << 4
m, err = e.encodeAmf3Uint29(w, u29)
if err != nil {
return n, fmt.Errorf("amf3 encode: cannot encode trait header for object: %s", err)
}
n += m
m, err = e.encodeAmf3Utf8(w, trait.Type)
if err != nil {
return n, fmt.Errorf("amf3 encode: cannot encode trait type for object: %s", err)
}
n += m
for _, prop := range trait.Properties {
m, err = e.encodeAmf3Utf8(w, prop)
if err != nil {
return n, fmt.Errorf("amf3 encode: cannot encode trait property for object: %s", err)
}
n += m
}
if trait.Externalizable {
return n, fmt.Errorf("amf3 encode: cannot encode externalizable object")
}
for _, prop := range trait.Properties {
m, err = e.EncodeAmf3(w, val.Object[prop])
if err != nil {
return n, fmt.Errorf("amf3 encode: cannot encode sealed object value: %s", err)
}
n += m
}
if trait.Dynamic {
for k, v := range val.Object {
var foundProp bool = false
for _, prop := range trait.Properties {
if prop == k {
foundProp = true
break
}
}
if foundProp != true {
m, err = e.encodeAmf3Utf8(w, k)
if err != nil {
return n, fmt.Errorf("amf3 encode: cannot encode dynamic object property key: %s", err)
}
n += m
m, err = e.EncodeAmf3(w, v)
if err != nil {
return n, fmt.Errorf("amf3 encode: cannot encode dynamic object value: %s", err)
}
n += m
}
m, err = e.encodeAmf3Utf8(w, "")
if err != nil {
return n, fmt.Errorf("amf3 encode: cannot encode dynamic object ending marker string: %s", err)
}
n += m
}
}
return
}
// marker: 1 byte 0x0c
// format:
// - u29 reference int. if reference, no more data. if not reference,
// length value of bytes to read .
func (e *Encoder) EncodeAmf3ByteArray(w io.Writer, val []byte, encodeMarker bool) (n int, err error) {
if encodeMarker {
if err = WriteMarker(w, AMF3_BYTEARRAY_MARKER); err != nil {
return
}
n += 1
}
var m int
length := uint32(len(val))
u29 := (length << 1) | 1
m, err = e.encodeAmf3Uint29(w, u29)
if err != nil {
return n, fmt.Errorf("amf3 encode: cannot encode u29 for bytearray: %s", err)
}
n += m
m, err = w.Write(val)
if err != nil {
return n, fmt.Errorf("encode amf3: unable to encode bytearray value: %s", err)
}
n += m
return
}
func (e *Encoder) encodeAmf3Utf8(w io.Writer, val string) (n int, err error) {
length := uint32(len(val))
u29 := uint32(length<<1) | 0x01
var m int
m, err = e.encodeAmf3Uint29(w, u29)
if err != nil {
return n, fmt.Errorf("amf3 encode: cannot encode u29 for string: %s", err)
}
n += m
m, err = w.Write([]byte(val))
if err != nil {
return n, fmt.Errorf("encode amf3: unable to encode string value: %s", err)
}
n += m
return
}
func (e *Encoder) encodeAmf3Uint29(w io.Writer, val uint32) (n int, err error) {
if val <= 0x0000007F {
err = WriteByte(w, byte(val))
if err == nil {
n += 1
}
} else if val <= 0x00003FFF {
n, err = w.Write([]byte{byte(val>>7 | 0x80), byte(val & 0x7F)})
} else if val <= 0x001FFFFF {
n, err = w.Write([]byte{byte(val>>14 | 0x80), byte(val>>7&0x7F | 0x80), byte(val & 0x7F)})
} else if val <= 0x1FFFFFFF {
n, err = w.Write([]byte{byte(val>>22 | 0x80), byte(val>>15&0x7F | 0x80), byte(val>>8&0x7F | 0x80), byte(val)})
} else {
return n, fmt.Errorf("amf3 encode: cannot encode u29 with value %d (out of range)", val)
}
return
}