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.
 
 
 

336 lines
9.1 KiB

package amf
import (
"encoding/binary"
"fmt"
"io"
)
// amf0 polymorphic router
func (d *Decoder) DecodeAmf0(r io.Reader) (interface{}, error) {
marker, err := ReadMarker(r)
if err != nil {
return nil, err
}
switch marker {
case AMF0_NUMBER_MARKER:
return d.DecodeAmf0Number(r, false)
case AMF0_BOOLEAN_MARKER:
return d.DecodeAmf0Boolean(r, false)
case AMF0_STRING_MARKER:
return d.DecodeAmf0String(r, false)
case AMF0_OBJECT_MARKER:
return d.DecodeAmf0Object(r, false)
case AMF0_MOVIECLIP_MARKER:
return nil, fmt.Errorf("decode amf0: unsupported type movieclip")
case AMF0_NULL_MARKER:
return d.DecodeAmf0Null(r, false)
case AMF0_UNDEFINED_MARKER:
return d.DecodeAmf0Undefined(r, false)
case AMF0_REFERENCE_MARKER:
return nil, fmt.Errorf("decode amf0: unsupported type reference")
case AMF0_ECMA_ARRAY_MARKER:
return d.DecodeAmf0EcmaArray(r, false)
case AMF0_STRICT_ARRAY_MARKER:
return d.DecodeAmf0StrictArray(r, false)
case AMF0_DATE_MARKER:
return d.DecodeAmf0Date(r, false)
case AMF0_LONG_STRING_MARKER:
return d.DecodeAmf0LongString(r, false)
case AMF0_UNSUPPORTED_MARKER:
return d.DecodeAmf0Unsupported(r, false)
case AMF0_RECORDSET_MARKER:
return nil, fmt.Errorf("decode amf0: unsupported type recordset")
case AMF0_XML_DOCUMENT_MARKER:
return d.DecodeAmf0XmlDocument(r, false)
case AMF0_TYPED_OBJECT_MARKER:
return d.DecodeAmf0TypedObject(r, false)
case AMF0_ACMPLUS_OBJECT_MARKER:
return d.DecodeAmf3(r)
}
return nil, fmt.Errorf("decode amf0: unsupported type %d", marker)
}
// marker: 1 byte 0x00
// format: 8 byte big endian float64
func (d *Decoder) DecodeAmf0Number(r io.Reader, decodeMarker bool) (result float64, err error) {
if err = AssertMarker(r, decodeMarker, AMF0_NUMBER_MARKER); err != nil {
return
}
err = binary.Read(r, binary.BigEndian, &result)
if err != nil {
return float64(0), fmt.Errorf("amf0 decode: unable to read number: %s", err)
}
return
}
// marker: 1 byte 0x01
// format: 1 byte, 0x00 = false, 0x01 = true
func (d *Decoder) DecodeAmf0Boolean(r io.Reader, decodeMarker bool) (result bool, err error) {
if err = AssertMarker(r, decodeMarker, AMF0_BOOLEAN_MARKER); err != nil {
return
}
var b byte
if b, err = ReadByte(r); err != nil {
return
}
if b == AMF0_BOOLEAN_FALSE {
return false, nil
} else if b == AMF0_BOOLEAN_TRUE {
return true, nil
}
return false, fmt.Errorf("decode amf0: unexpected value %v for boolean", b)
}
// marker: 1 byte 0x02
// format:
// - 2 byte big endian uint16 header to determine size
// - n (size) byte utf8 string
func (d *Decoder) DecodeAmf0String(r io.Reader, decodeMarker bool) (result string, err error) {
if err = AssertMarker(r, decodeMarker, AMF0_STRING_MARKER); err != nil {
return
}
var length uint16
err = binary.Read(r, binary.BigEndian, &length)
if err != nil {
return "", fmt.Errorf("decode amf0: unable to decode string length: %s", err)
}
var bytes = make([]byte, length)
if bytes, err = ReadBytes(r, int(length)); err != nil {
return "", fmt.Errorf("decode amf0: unable to decode string value: %s", err)
}
return string(bytes), nil
}
// marker: 1 byte 0x03
// format:
// - loop encoded string followed by encoded value
// - terminated with empty string followed by 1 byte 0x09
func (d *Decoder) DecodeAmf0Object(r io.Reader, decodeMarker bool) (Object, error) {
if err := AssertMarker(r, decodeMarker, AMF0_OBJECT_MARKER); err != nil {
return nil, err
}
result := make(Object)
d.refCache = append(d.refCache, result)
for {
key, err := d.DecodeAmf0String(r, false)
if err != nil {
return nil, err
}
if key == "" {
if err = AssertMarker(r, true, AMF0_OBJECT_END_MARKER); err != nil {
return nil, fmt.Errorf("decode amf0: expected object end marker: %s", err)
}
break
}
value, err := d.DecodeAmf0(r)
if err != nil {
return nil, fmt.Errorf("decode amf0: unable to decode object value: %s", err)
}
result[key] = value
}
return result, nil
}
// marker: 1 byte 0x05
// no additional data
func (d *Decoder) DecodeAmf0Null(r io.Reader, decodeMarker bool) (result interface{}, err error) {
err = AssertMarker(r, decodeMarker, AMF0_NULL_MARKER)
return
}
// marker: 1 byte 0x06
// no additional data
func (d *Decoder) DecodeAmf0Undefined(r io.Reader, decodeMarker bool) (result interface{}, err error) {
err = AssertMarker(r, decodeMarker, AMF0_UNDEFINED_MARKER)
return
}
// marker: 1 byte 0x07
// format: 2 byte big endian uint16
/*
func (d *Decoder) DecodeAmf0Reference(r io.Reader, decodeMarker bool) (interface{}, error) {
if err := AssertMarker(r, decodeMarker, AMF0_REFERENCE_MARKER); err != nil {
return nil, err
}
var err error
var ref uint16
err = binary.Read(r, binary.BigEndian, &ref)
if err != nil {
return nil, fmt.Errorf("decode amf0: unable to decode reference id: %s", err)
}
if int(ref) > len(d.refCache) {
return nil, fmt.Errorf("decode amf0: bad reference %d (current length %d)", ref, len(d.refCache))
}
result := d.refCache[ref]
return result, nil
}
*/
// marker: 1 byte 0x08
// format:
// - 4 byte big endian uint32 with length of associative array
// - normal object format:
// - loop encoded string followed by encoded value
// - terminated with empty string followed by 1 byte 0x09
func (d *Decoder) DecodeAmf0EcmaArray(r io.Reader, decodeMarker bool) (Object, error) {
if err := AssertMarker(r, decodeMarker, AMF0_ECMA_ARRAY_MARKER); err != nil {
return nil, err
}
var length uint32
err := binary.Read(r, binary.BigEndian, &length)
result, err := d.DecodeAmf0Object(r, false)
if err != nil {
return nil, fmt.Errorf("decode amf0: unable to decode ecma array object: %s", err)
}
return result, nil
}
// marker: 1 byte 0x0a
// format:
// - 4 byte big endian uint32 to determine length of associative array
// - n (length) encoded values
func (d *Decoder) DecodeAmf0StrictArray(r io.Reader, decodeMarker bool) (result Array, err error) {
if err := AssertMarker(r, decodeMarker, AMF0_STRICT_ARRAY_MARKER); err != nil {
return nil, err
}
var length uint32
err = binary.Read(r, binary.BigEndian, &length)
if err != nil {
return nil, fmt.Errorf("decode amf0: unable to decode strict array length: %s", err)
}
d.refCache = append(d.refCache, result)
for i := uint32(0); i < length; i++ {
tmp, err := d.DecodeAmf0(r)
if err != nil {
return nil, fmt.Errorf("decode amf0: unable to decode strict array object: %s", err)
}
result = append(result, tmp)
}
return result, nil
}
// marker: 1 byte 0x0b
// format:
// - normal number format:
// - 8 byte big endian float64
// - 2 byte unused
func (d *Decoder) DecodeAmf0Date(r io.Reader, decodeMarker bool) (result float64, err error) {
if err = AssertMarker(r, decodeMarker, AMF0_DATE_MARKER); err != nil {
return
}
if result, err = d.DecodeAmf0Number(r, false); err != nil {
return float64(0), fmt.Errorf("decode amf0: unable to decode float in date: %s", err)
}
if _, err = ReadBytes(r, 2); err != nil {
return float64(0), fmt.Errorf("decode amf0: unable to read 2 trail bytes in date: %s", err)
}
return
}
// marker: 1 byte 0x0c
// format:
// - 4 byte big endian uint32 header to determine size
// - n (size) byte utf8 string
func (d *Decoder) DecodeAmf0LongString(r io.Reader, decodeMarker bool) (result string, err error) {
if err = AssertMarker(r, decodeMarker, AMF0_LONG_STRING_MARKER); err != nil {
return
}
var length uint32
err = binary.Read(r, binary.BigEndian, &length)
if err != nil {
return "", fmt.Errorf("decode amf0: unable to decode long string length: %s", err)
}
var bytes = make([]byte, length)
if bytes, err = ReadBytes(r, int(length)); err != nil {
return "", fmt.Errorf("decode amf0: unable to decode long string value: %s", err)
}
return string(bytes), nil
}
// marker: 1 byte 0x0d
// no additional data
func (d *Decoder) DecodeAmf0Unsupported(r io.Reader, decodeMarker bool) (result interface{}, err error) {
err = AssertMarker(r, decodeMarker, AMF0_UNSUPPORTED_MARKER)
return
}
// marker: 1 byte 0x0f
// format:
// - normal long string format
// - 4 byte big endian uint32 header to determine size
// - n (size) byte utf8 string
func (d *Decoder) DecodeAmf0XmlDocument(r io.Reader, decodeMarker bool) (result string, err error) {
if err = AssertMarker(r, decodeMarker, AMF0_XML_DOCUMENT_MARKER); err != nil {
return
}
return d.DecodeAmf0LongString(r, false)
}
// marker: 1 byte 0x10
// format:
// - normal string format:
// - 2 byte big endian uint16 header to determine size
// - n (size) byte utf8 string
// - normal object format:
// - loop encoded string followed by encoded value
// - terminated with empty string followed by 1 byte 0x09
func (d *Decoder) DecodeAmf0TypedObject(r io.Reader, decodeMarker bool) (TypedObject, error) {
result := *new(TypedObject)
err := AssertMarker(r, decodeMarker, AMF0_TYPED_OBJECT_MARKER)
if err != nil {
return result, err
}
d.refCache = append(d.refCache, result)
result.Type, err = d.DecodeAmf0String(r, false)
if err != nil {
return result, fmt.Errorf("decode amf0: typed object unable to determine type: %s", err)
}
result.Object, err = d.DecodeAmf0Object(r, false)
if err != nil {
return result, fmt.Errorf("decode amf0: typed object unable to determine object: %s", err)
}
return result, nil
}