AMF

  AMF是Action Message Format(动作消息格式)的简写,它是一种二进制的数据格式。它的设计是为了把actionscript里面的数据(包括Object, Array, Boolean, Number等)序列化成二进制数据,然后把这段数据随意发送给其他接收方程序,比如发给远程的服务器,在远程服务器那边,可以把这段数据给还原出来,以此达到一个数据传输的作用。

为什么要用AMF

  通常情况下我们使用JSON或者XML来做数据的传输,他们的好处是文本数据易读、容易修改,坏处在于文本数据体积较大,而且数据的组织有其局限性。那么二进制协议是不是只有AMF一个呢? 答案明显是否定的,你完全可以自定义自己的二进制数据格式,用AMF只是由于它是现成的,拿来即可用,不用重新去发明轮子。

AMFObject详解

AMF分成两种: 1. AMF0,基本的数据转换规则; 2. AMF3,是AMF0的扩展。

    // AMF0数据类型;
typedef enum
{
AMF_NUMBER = 0, // 数字(double);
AMF_BOOLEAN, // 布尔;
AMF_STRING, // 字符串;
AMF_OBJECT, // 对象;
AMF_MOVIECLIP, // 保留,未使用;
AMF_NULL, // null;
AMF_UNDEFINED, // 未定义;
AMF_REFERENCE, // 引用;
AMF_ECMA_ARRAY, // 数组;
AMF_OBJECT_END, // 对象结束;
AMF_STRICT_ARRAY, // 严格的数组;
AMF_DATE, // 日期;
AMF_LONG_STRING, // 长字符串;
AMF_UNSUPPORTED, // 未支持;
AMF_RECORDSET, // 保留,未使用;
AMF_XML_DOC, // xml文档;
AMF_TYPED_OBJECT, // 有类型的对象;
AMF_AVMPLUS, // 需要扩展到AMF3;
AMF_INVALID = 0xff // 无效的;
}AMFDataType;    // AMF3数据类型;
typedef enum
{
AMF3_UNDEFINED = 0, // 未定义;
AMF3_NULL, // null;
AMF3_FALSE, // false;
AMF3_TRUE, // true;
AMF3_INTEGER, // 数字int;
AMF3_DOUBLE, // double;
AMF3_STRING, // 字符串;
AMF3_XML_DOC, // xml文档;
AMF3_DATE, // 日期;
AMF3_ARRAY, // 数组;
AMF3_OBJECT, // 对象;
AMF3_XML, // xml;
AMF3_BYTE_ARRAY // 字节数组;
} AMF3DataType;

AMF定义了自己的字符串类型:

  // AMF自定义的字符串;
typedef struct AVal
{
char *av_val;
int av_len;
} AVal; // AVal的快速初始化;
#define AVC(str) {str, sizeof(str)-1}
// 比较AVal字符串;
#define AVMATCH(a1,a2) ((a1)->av_len == (a2)->av_len && !memcmp((a1)->av_val,(a2)->av_val,(a1)->av_len))

AMFObject表示AMF对象,o_num 代表 o_props的个数, 一个对象内部可以包含N个对象属性;

    // AMF对象, 就是由一系列的属性构成的;
typedef struct AMFObject
{
int o_num; // 属性数目;
struct AMFObjectProperty *o_props; // 属性数组;
} AMFObject;

AMFObject表示AMF对象属性,即key-value键值对。p_name表示key;p_type表示value的类型;p_vu表示value的数值。

    // AMF对象的属性;
typedef struct AMFObjectProperty
{
AVal p_name; // 属性名称;
AMFDataType p_type; // 属性类型;
union
{
double p_number;
AVal p_aval;
AMFObject p_object;
} p_vu; // 属性数值;
int16_t p_UTCoffset; // UTC偏移;
} AMFObjectProperty;

p_vu设置为联合体的目的:

当p_type为number时, m_vu取值double类型 p_number;

当p_type为string时,    m_vu取值AVal类型 p_aval;

当p_type为object时,   m_vu取值AMFObject类型 p_object。

AMF编码、解码的具体实现

#include "rtmp_sys.h"
#include "amf.h"
#include "log.h"
#include "bytes.h" static const AMFObjectProperty AMFProp_Invalid = { {0, 0}, AMF_INVALID };
static const AVal AV_empty = { 0, 0 }; /* Data is Big-Endian */
/************************************************************************************************************
* 解码int16(这个整数占用两个字节);
*
* c[0]左移8位(就是乘以256)+c[1];
************************************************************************************************************/
unsigned short AMF_DecodeInt16(const char* data)
{
unsigned char* c = (unsigned char* ) data;
unsigned short val;
val = (c[0] << 8) | c[1];
return val;
} /************************************************************************************************************
* 解码int24(这个整数占用三个字节);
*
* c[0]左移16位+c[1]左移8位+c[2];
************************************************************************************************************/
unsigned int AMF_DecodeInt24(const char* data)
{
unsigned char* c = (unsigned char* ) data;
unsigned int val;
val = (c[0] << 16) | (c[1] << 8) | c[2];
return val;
} /************************************************************************************************************
* 解码int32(这个整数占用四个字节);
*
* c[0]左移24位+c[1]左移16位+c[2]左移8位+c[3];
************************************************************************************************************/
unsigned int AMF_DecodeInt32(const char* data)
{
unsigned char* c = (unsigned char* )data;
unsigned int val;
val = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
return val;
} /************************************************************************************************************
* 解码String;
*
* 前两个字节是长度,后面是内容;
************************************************************************************************************/
void AMF_DecodeString(const char* data, AVal* bv)
{
bv->av_len = AMF_DecodeInt16(data);
bv->av_val = (bv->av_len > 0) ? (char* )data + 2 : NULL;
} /************************************************************************************************************
* 解码LongString;
*
* 前四个字节是长度,后面是内容;
************************************************************************************************************/
void AMF_DecodeLongString(const char* data, AVal* bv)
{
bv->av_len = AMF_DecodeInt32(data);
bv->av_val = (bv->av_len > 0) ? (char* )data + 4 : NULL;
} /************************************************************************************************************
* 解码数值double;
*
* float字的存储顺序等于字节顺序;
* 大端字节顺序,直接赋值; 小端字节顺序,反转赋值;
*
* float字的存储顺序不等字节顺序;
* 大端字节顺序,反转赋值; 小端字节顺序,直接赋值;
************************************************************************************************************/
double AMF_DecodeNumber(const char* data)
{
double dVal;
#if __FLOAT_WORD_ORDER == __BYTE_ORDER // 如果float字的存储顺序等于字节顺序;
#if __BYTE_ORDER == __BIG_ENDIAN // 如果是大端字节顺序;
memcpy(&dVal, data, 8); // 直接复制;
#elif __BYTE_ORDER == __LITTLE_ENDIAN // 如果是小端字节顺序;
unsigned char* ci, *co;
ci = (unsigned char* )data;
co = (unsigned char* )&dVal;
co[0] = ci[7];
co[1] = ci[6];
co[2] = ci[5];
co[3] = ci[4];
co[4] = ci[3];
co[5] = ci[2];
co[6] = ci[1];
co[7] = ci[0];
#endif
#else
#if __BYTE_ORDER == __LITTLE_ENDIAN /* __FLOAT_WORD_ORER == __BIG_ENDIAN */
unsigned char* ci, *co;
ci = (unsigned char* )data;
co = (unsigned char* )&dVal;
co[0] = ci[3];
co[1] = ci[2];
co[2] = ci[1];
co[3] = ci[0];
co[4] = ci[7];
co[5] = ci[6];
co[6] = ci[5];
co[7] = ci[4];
#else /* __BYTE_ORDER == __BIG_ENDIAN && __FLOAT_WORD_ORER == __LITTLE_ENDIAN */
unsigned char* ci, *co;
ci = (unsigned char* )data;
co = (unsigned char* )&dVal;
co[0] = ci[4];
co[1] = ci[5];
co[2] = ci[6];
co[3] = ci[7];
co[4] = ci[0];
co[5] = ci[1];
co[6] = ci[2];
co[7] = ci[3];
#endif
#endif
return dVal;
} /************************************************************************************************************
* 解码布尔;
*
* 判断内容是否为0;
************************************************************************************************************/
int AMF_DecodeBoolean(const char* data)
{
return *data != 0;
} /************************************************************************************************************
* 编码int16(这个整数占用两个字节);
*
* 依次截取1个字节进行赋值;
************************************************************************************************************/
char* AMF_EncodeInt16(char* output, char* outend, short nVal)
{
if (output + 2 > outend)
{
return NULL;
} output[1] = nVal & 0xff; // output[1] = nVal; 两者等价;
output[0] = nVal >> 8;
return output+2;
} /************************************************************************************************************
* 编码int24(这个整数占用三个字节);
*
* 依次截取1个字节进行赋值;
************************************************************************************************************/
char* AMF_EncodeInt24(char* output, char* outend, int nVal)
{
if (output+3 > outend)
return NULL; output[2] = nVal & 0xff;
output[1] = nVal >> 8;
output[0] = nVal >> 16;
return output+3;
} /************************************************************************************************************
* 编码int32(这个整数占用四个字节);
*
* 依次截取1个字节进行赋值;
************************************************************************************************************/
char* AMF_EncodeInt32(char* output, char* outend, int nVal)
{
if (output+4 > outend)
return NULL; output[3] = nVal & 0xff;
output[2] = nVal >> 8;
output[1] = nVal >> 16;
output[0] = nVal >> 24;
return output+4;
} /************************************************************************************************************
* 编码字符串bv;
*
* 第一个字节存字符串类型;
* 若字节小于65536,用两个字节存储长度; 否则用4个字节存储长度;
************************************************************************************************************/
char* AMF_EncodeString(char* output, char* outend, const AVal* bv)
{
if ((bv->av_len < 65536 && output + 1 + 2 + bv->av_len > outend) || (output + 1 + 4 + bv->av_len > outend))
{
return NULL;
} // 第一个字节存字符串类型;
// 若字节小于65536, 用两个字节存储长度; 否则用4个字节存储长度;
if (bv->av_len < 65536)
{
*output++ = AMF_STRING;
output = AMF_EncodeInt16(output, outend, bv->av_len);
}
else
{
*output++ = AMF_LONG_STRING;
output = AMF_EncodeInt32(output, outend, bv->av_len);
} // 然后将avl内容赋值即可;
memcpy(output, bv->av_val, bv->av_len);
output += bv->av_len; return output;
} /************************************************************************************************************
* 编码数值double;
*
* float字的存储顺序等于字节顺序;
* 大端字节顺序,直接赋值; 小端字节顺序,反转赋值;
*
* float字的存储顺序不等字节顺序;
* 大端字节顺序,反转赋值; 小端字节顺序,直接赋值;
************************************************************************************************************/
char* AMF_EncodeNumber(char* output, char* outend, double dVal)
{
if (output + 1 + 8 > outend)
{
return NULL;
} *output++ = AMF_NUMBER; /* type: Number */ #if __FLOAT_WORD_ORDER == __BYTE_ORDER
#if __BYTE_ORDER == __BIG_ENDIAN
memcpy(output, &dVal, 8);
#elif __BYTE_ORDER == __LITTLE_ENDIAN
{
unsigned char* ci, *co;
ci = (unsigned char* )&dVal;
co = (unsigned char* )output;
co[0] = ci[7];
co[1] = ci[6];
co[2] = ci[5];
co[3] = ci[4];
co[4] = ci[3];
co[5] = ci[2];
co[6] = ci[1];
co[7] = ci[0];
}
#endif
#else
#if __BYTE_ORDER == __LITTLE_ENDIAN /* __FLOAT_WORD_ORER == __BIG_ENDIAN */
{
unsigned char* ci, *co;
ci = (unsigned char* )&dVal;
co = (unsigned char* )output;
co[0] = ci[3];
co[1] = ci[2];
co[2] = ci[1];
co[3] = ci[0];
co[4] = ci[7];
co[5] = ci[6];
co[6] = ci[5];
co[7] = ci[4];
}
#else /* __BYTE_ORDER == __BIG_ENDIAN && __FLOAT_WORD_ORER == __LITTLE_ENDIAN */
{
unsigned char* ci, *co;
ci = (unsigned char* )&dVal;
co = (unsigned char* )output;
co[0] = ci[4];
co[1] = ci[5];
co[2] = ci[6];
co[3] = ci[7];
co[4] = ci[0];
co[5] = ci[1];
co[6] = ci[2];
co[7] = ci[3];
}
#endif
#endif return output+8;
} /************************************************************************************************************
* 编码布尔;
*
* 第一个字节存字符串类型;
* 若二个字节: bVal若为真存1 为假存0;
************************************************************************************************************/
char* AMF_EncodeBoolean(char* output, char* outend, int bVal)
{
if (output + 2 > outend)
{
return NULL;
} *output++ = AMF_BOOLEAN; *output++ = bVal ? 0x01 : 0x00; return output;
} /************************************************************************************************************
* 编码strName+strValue;
*
* name : 长度+内容;
: value: string编码;
************************************************************************************************************/
char* AMF_EncodeNamedString(char* output, char* outend, const AVal* strName, const AVal* strValue)
{
if (output + 2 + strName->av_len > outend)
{
return NULL;
}
output = AMF_EncodeInt16(output, outend, strName->av_len); memcpy(output, strName->av_val, strName->av_len);
output += strName->av_len; return AMF_EncodeString(output, outend, strValue);
} /************************************************************************************************************
* 编码strName+dVal;
*
* name : 长度+内容;
: value: double编码;
************************************************************************************************************/
char* AMF_EncodeNamedNumber(char* output, char* outend, const AVal* strName, double dVal)
{
if (output + 2 + strName->av_len > outend)
{
return NULL;
}
output = AMF_EncodeInt16(output, outend, strName->av_len); memcpy(output, strName->av_val, strName->av_len);
output += strName->av_len; return AMF_EncodeNumber(output, outend, dVal);
} /************************************************************************************************************
* 编码strName+dVal;
*
* name : 长度+内容;
: value: bool编码;
************************************************************************************************************/
char* AMF_EncodeNamedBoolean(char* output, char* outend, const AVal* strName, int bVal)
{
if (output + 2 + strName->av_len > outend)
{
return NULL;
}
output = AMF_EncodeInt16(output, outend, strName->av_len); memcpy(output, strName->av_val, strName->av_len);
output += strName->av_len; return AMF_EncodeBoolean(output, outend, bVal);
} /************************************************************************************************************
* 获取对象属性的name;
*
************************************************************************************************************/
void AMFProp_GetName(AMFObjectProperty* prop, AVal* name)
{
*name = prop->p_name;
} /************************************************************************************************************
* 设置对象属性的name;
*
************************************************************************************************************/
void AMFProp_SetName(AMFObjectProperty* prop, AVal* name)
{
prop->p_name = *name;
} /************************************************************************************************************
* 获取对象属性的type;
*
************************************************************************************************************/
AMFDataType AMFProp_GetType(AMFObjectProperty* prop)
{
return prop->p_type;
} /************************************************************************************************************
* 设置对象属性的数值(double);
*
************************************************************************************************************/
double AMFProp_GetNumber(AMFObjectProperty* prop)
{
return prop->p_vu.p_number;
} /************************************************************************************************************
* 获取对象属性的数值(bool);
*
************************************************************************************************************/
int AMFProp_GetBoolean(AMFObjectProperty* prop)
{
return prop->p_vu.p_number != 0;
} /************************************************************************************************************
* 获取对象属性的数值(string);
*
************************************************************************************************************/
void AMFProp_GetString(AMFObjectProperty* prop, AVal* str)
{
*str = prop->p_vu.p_aval;
} /************************************************************************************************************
* 获取对象属性的数值(object);
*
************************************************************************************************************/
void AMFProp_GetObject(AMFObjectProperty* prop, AMFObject* obj)
{
*obj = prop->p_vu.p_object;
} /************************************************************************************************************
* 判断对象属性的类型是否有效;
*
************************************************************************************************************/
int AMFProp_IsValid(AMFObjectProperty* prop)
{
return prop->p_type != AMF_INVALID;
} /************************************************************************************************************
* 编码: 对象的属性prop;
*
************************************************************************************************************/
char* AMFProp_Encode(AMFObjectProperty* prop, char* pBuffer, char* pBufEnd)
{
if (prop->p_type == AMF_INVALID)
{
return NULL;
} if (prop->p_type != AMF_NULL && pBuffer + prop->p_name.av_len + 2 + 1 >= pBufEnd)
{
return NULL;
} // 编码对象的name,两个字节存长度;
// 之所以不直接调用AMF_EncodeString 是因为会多存一个字节(表示数据类型);
if (prop->p_type != AMF_NULL && prop->p_name.av_len)
{
*pBuffer++ = prop->p_name.av_len >> 8;
*pBuffer++ = prop->p_name.av_len & 0xff;
memcpy(pBuffer, prop->p_name.av_val, prop->p_name.av_len);
pBuffer += prop->p_name.av_len;
} // 编码对象的value, 不同类型不同处理;
switch (prop->p_type)
{
case AMF_NUMBER:
{
pBuffer = AMF_EncodeNumber(pBuffer, pBufEnd, prop->p_vu.p_number);
}
break;
case AMF_BOOLEAN:
{
pBuffer = AMF_EncodeBoolean(pBuffer, pBufEnd, prop->p_vu.p_number != 0);
}
break;
case AMF_STRING:
{
pBuffer = AMF_EncodeString(pBuffer, pBufEnd, &prop->p_vu.p_aval);
}
break;
case AMF_NULL:
{
if (pBuffer+1 >= pBufEnd)
{
return NULL;
}
*pBuffer++ = AMF_NULL;
}
break;
case AMF_OBJECT:
{
pBuffer = AMF_Encode(&prop->p_vu.p_object, pBuffer, pBufEnd);
}
break;
case AMF_ECMA_ARRAY:
{
pBuffer = AMF_EncodeEcmaArray(&prop->p_vu.p_object, pBuffer, pBufEnd);
}
break;
case AMF_STRICT_ARRAY:
{
pBuffer = AMF_EncodeArray(&prop->p_vu.p_object, pBuffer, pBufEnd);
}
break;
default:
{
RTMP_Log(RTMP_LOGERROR, "%s, invalid type. %d", __FUNCTION__, prop->p_type);
pBuffer = NULL;
}
break;
}; return pBuffer;
} #define AMF3_INTEGER_MAX 268435455
#define AMF3_INTEGER_MIN -268435456 /************************************************************************************************************
* AMF读取数值;
*
************************************************************************************************************/
int AMF3ReadInteger(const char* data, int32_t* valp)
{
int i = 0;
int32_t val = 0; while (i <= 2)
{
/* handle first 3 bytes */
if (data[i] & 0x80)
{
/* byte used */
val <<= 7; /* shift up */
val |= (data[i] & 0x7f); /* add bits */
i++;
}
else
{
break;
}
} if (i > 2)
{
/* use 4th byte, all 8bits */
val <<= 8;
val |= data[3]; /* range check */
if (val > AMF3_INTEGER_MAX)
{
val -= (1 << 29);
}
}
else
{
/* use 7bits of last unparsed byte (0xxxxxxx) */
val <<= 7;
val |= data[i];
} *valp = val; return i > 2 ? 4 : i + 1;
} int AMF3ReadString(const char* data, AVal* str)
{
int32_t ref = 0;
int len;
assert(str != 0); len = AMF3ReadInteger(data, &ref);
data += len; if ((ref & 0x1) == 0)
{
/* reference: 0xxx */
uint32_t refIndex = (ref >> 1);
RTMP_Log(RTMP_LOGDEBUG, "%s, string reference, index: %d, not supported, ignoring!", __FUNCTION__, refIndex);
return len;
}
else
{
uint32_t nSize = (ref >> 1); str->av_val = (char* )data;
str->av_len = nSize; return len + nSize;
}
return len;
} int AMF3Prop_Decode(AMFObjectProperty* prop, const char* pBuffer, int nSize,
int bDecodeName)
{
int nOriginalSize = nSize;
AMF3DataType type; prop->p_name.av_len = 0;
prop->p_name.av_val = NULL; if (nSize == 0 || !pBuffer)
{
RTMP_Log(RTMP_LOGDEBUG, "empty buffer/no buffer pointer!");
return -1;
} /* decode name */
if (bDecodeName)
{
AVal name = AV_empty;
int nRes = AMF3ReadString(pBuffer, &name); if (name.av_len <= 0)
return nRes; prop->p_name = name;
pBuffer += nRes;
nSize -= nRes;
} /* decode */
type = *pBuffer++;
nSize--; switch (type)
{
case AMF3_UNDEFINED:
case AMF3_NULL:
prop->p_type = AMF_NULL;
break;
case AMF3_FALSE:
prop->p_type = AMF_BOOLEAN;
prop->p_vu.p_number = 0.0;
break;
case AMF3_TRUE:
prop->p_type = AMF_BOOLEAN;
prop->p_vu.p_number = 1.0;
break;
case AMF3_INTEGER:
{
int32_t res = 0;
int len = AMF3ReadInteger(pBuffer, &res);
prop->p_vu.p_number = (double)res;
prop->p_type = AMF_NUMBER;
nSize -= len;
break;
}
case AMF3_DOUBLE:
if (nSize < 8)
return -1;
prop->p_vu.p_number = AMF_DecodeNumber(pBuffer);
prop->p_type = AMF_NUMBER;
nSize -= 8;
break;
case AMF3_STRING:
case AMF3_XML_DOC:
case AMF3_XML:
{
int len = AMF3ReadString(pBuffer, &prop->p_vu.p_aval);
prop->p_type = AMF_STRING;
nSize -= len;
break;
}
case AMF3_DATE:
{
int32_t res = 0;
int len = AMF3ReadInteger(pBuffer, &res); nSize -= len;
pBuffer += len; if ((res & 0x1) == 0)
{
/* reference */
uint32_t nIndex = (res >> 1);
RTMP_Log(RTMP_LOGDEBUG, "AMF3_DATE reference: %d, not supported!", nIndex);
}
else
{
if (nSize < 8)
return -1; prop->p_vu.p_number = AMF_DecodeNumber(pBuffer);
nSize -= 8;
prop->p_type = AMF_NUMBER;
}
break;
}
case AMF3_OBJECT:
{
int nRes = AMF3_Decode(&prop->p_vu.p_object, pBuffer, nSize, TRUE);
if (nRes == -1)
return -1;
nSize -= nRes;
prop->p_type = AMF_OBJECT;
break;
}
case AMF3_ARRAY:
case AMF3_BYTE_ARRAY:
default:
RTMP_Log(RTMP_LOGDEBUG, "%s - AMF3 unknown/unsupported datatype 0x%02x, @%p",
__FUNCTION__, (unsigned char)(*pBuffer), pBuffer);
return -1;
} return nOriginalSize - nSize;
} /************************************************************************************************************
* 解码: pBuffer->prop;
*
************************************************************************************************************/
int AMFProp_Decode(AMFObjectProperty* prop, const char* pBuffer, int nSize,
int bDecodeName)
{
int nOriginalSize = nSize;
int nRes; prop->p_name.av_len = 0;
prop->p_name.av_val = NULL; if (nSize == 0 || !pBuffer)
{
RTMP_Log(RTMP_LOGDEBUG, "%s: Empty buffer/no buffer pointer!", __FUNCTION__);
return -1;
} if (bDecodeName && nSize < 4)
{
/* at least name (length + at least 1 byte) and 1 byte of data */
RTMP_Log(RTMP_LOGDEBUG, "%s: Not enough data for decoding with name, less than 4 bytes!", __FUNCTION__);
return -1;
} if (bDecodeName)
{
// 解码对象属性的name;
unsigned short nNameSize = AMF_DecodeInt16(pBuffer);
if (nNameSize > nSize - 2)
{
RTMP_Log(RTMP_LOGDEBUG, "%s: Name size out of range: namesize (%d) > len (%d) - 2", __FUNCTION__, nNameSize, nSize);
return -1;
} AMF_DecodeString(pBuffer, &prop->p_name);
nSize -= 2 + nNameSize;
pBuffer += 2 + nNameSize;
} if (nSize == 0)
{
return -1;
} // 获取属性类型;
nSize--;
prop->p_type = *pBuffer++;
switch (prop->p_type)
{
case AMF_NUMBER:
{
if (nSize < 8)
{
return -1;
} prop->p_vu.p_number = AMF_DecodeNumber(pBuffer);
nSize -= 8;
}
break;
case AMF_BOOLEAN:
{
if (nSize < 1)
{
return -1;
} prop->p_vu.p_number = (double)AMF_DecodeBoolean(pBuffer);
nSize--;
}
break;
case AMF_STRING:
{
unsigned short nStringSize = AMF_DecodeInt16(pBuffer);
if (nSize < (long)nStringSize + 2)
{
return -1;
}
AMF_DecodeString(pBuffer, &prop->p_vu.p_aval);
nSize -= (2 + nStringSize);
}
break;
case AMF_OBJECT:
{
int nRes = AMF_Decode(&prop->p_vu.p_object, pBuffer, nSize, TRUE);
if (nRes == -1)
{
return -1;
}
nSize -= nRes;
}
break;
case AMF_MOVIECLIP:
{
RTMP_Log(RTMP_LOGERROR, "AMF_MOVIECLIP reserved!");
return -1;
}
break;
case AMF_NULL:
case AMF_UNDEFINED:
case AMF_UNSUPPORTED:
{
prop->p_type = AMF_NULL;
}
break;
case AMF_REFERENCE:
{
RTMP_Log(RTMP_LOGERROR, "AMF_REFERENCE not supported!");
return -1;
}
break;
case AMF_ECMA_ARRAY:
{
nSize -= 4;
/* next comes the rest, mixed array has a final 0x000009 mark and names, so its an object */
nRes = AMF_Decode(&prop->p_vu.p_object, pBuffer + 4, nSize, TRUE);
if (nRes == -1)
{
return -1;
}
nSize -= nRes;
}
break;
case AMF_OBJECT_END:
{
return -1;
}
break;
case AMF_STRICT_ARRAY:
{
unsigned int nArrayLen = AMF_DecodeInt32(pBuffer);
nSize -= 4;
nRes = AMF_DecodeArray(&prop->p_vu.p_object, pBuffer + 4, nSize, nArrayLen, FALSE);
if (nRes == -1)
{
return -1;
}
nSize -= nRes;
}
break;
case AMF_DATE:
{
RTMP_Log(RTMP_LOGDEBUG, "AMF_DATE");
if (nSize < 10)
{
return -1;
}
prop->p_vu.p_number = AMF_DecodeNumber(pBuffer);
prop->p_UTCoffset = AMF_DecodeInt16(pBuffer + 8); nSize -= 10;
}
break;
case AMF_LONG_STRING:
case AMF_XML_DOC:
{
unsigned int nStringSize = AMF_DecodeInt32(pBuffer);
if (nSize < (long)nStringSize + 4)
{
return -1;
}
AMF_DecodeLongString(pBuffer, &prop->p_vu.p_aval);
nSize -= (4 + nStringSize);
if (prop->p_type == AMF_LONG_STRING)
{
prop->p_type = AMF_STRING;
}
}
break;
case AMF_RECORDSET:
{
RTMP_Log(RTMP_LOGERROR, "AMF_RECORDSET reserved!");
return -1;
}
break;
case AMF_TYPED_OBJECT:
{
RTMP_Log(RTMP_LOGERROR, "AMF_TYPED_OBJECT not supported!");
return -1;
}
break;
case AMF_AVMPLUS:
{
int nRes = AMF3_Decode(&prop->p_vu.p_object, pBuffer, nSize, TRUE);
if (nRes == -1)
{
return -1;
}
nSize -= nRes;
prop->p_type = AMF_OBJECT;
}
break;
default:
{
RTMP_Log(RTMP_LOGDEBUG, "%s - unknown datatype 0x%02x, @%p", __FUNCTION__, prop->p_type, pBuffer - 1);
return -1;
}
break;
} return nOriginalSize - nSize;
} /************************************************************************************************************
* 对属性prop进行输出显示,用于调试;
*
************************************************************************************************************/
void AMFProp_Dump(AMFObjectProperty* prop)
{
char strRes[256];
char str[256];
AVal name; if (prop->p_type == AMF_INVALID)
{
RTMP_Log(RTMP_LOGDEBUG, "Property: INVALID");
return;
} if (prop->p_type == AMF_NULL)
{
RTMP_Log(RTMP_LOGDEBUG, "Property: NULL");
return;
} if (prop->p_name.av_len)
{
name = prop->p_name;
}
else
{
name.av_val = "no-name.";
name.av_len = sizeof("no-name.") - 1;
}
if (name.av_len > 18)
{
name.av_len = 18;
}
snprintf(strRes, 255, "Name: %18.*s, ", name.av_len, name.av_val); switch (prop->p_type)
{
case AMF_OBJECT:
{
RTMP_Log(RTMP_LOGDEBUG, "Property: <%sOBJECT>", strRes);
AMF_Dump(&prop->p_vu.p_object);
return;
}
break;
case AMF_ECMA_ARRAY:
{
RTMP_Log(RTMP_LOGDEBUG, "Property: <%sECMA_ARRAY>", strRes);
AMF_Dump(&prop->p_vu.p_object);
return;
}
break;
case AMF_STRICT_ARRAY:
{
RTMP_Log(RTMP_LOGDEBUG, "Property: <%sSTRICT_ARRAY>", strRes);
AMF_Dump(&prop->p_vu.p_object);
return;
}
break;
case AMF_NUMBER:
snprintf(str, 255, "NUMBER:\t%.2f", prop->p_vu.p_number);
break;
case AMF_BOOLEAN:
snprintf(str, 255, "BOOLEAN:\t%s", prop->p_vu.p_number != 0.0 ? "TRUE" : "FALSE");
break;
case AMF_STRING:
snprintf(str, 255, "STRING:\t%.*s", prop->p_vu.p_aval.av_len, prop->p_vu.p_aval.av_val);
break;
case AMF_DATE:
snprintf(str, 255, "DATE:\ttimestamp: %.2f, UTC offset: %d", prop->p_vu.p_number, prop->p_UTCoffset);
break;
default:
snprintf(str, 255, "INVALID TYPE 0x%02x", (unsigned char)prop->p_type);
break;
} RTMP_Log(RTMP_LOGDEBUG, "Property: <%s%s>", strRes, str);
} /************************************************************************************************************
* 属性prop的重置;
*
************************************************************************************************************/
void AMFProp_Reset(AMFObjectProperty* prop)
{
if (prop->p_type == AMF_OBJECT || prop->p_type == AMF_ECMA_ARRAY || prop->p_type == AMF_STRICT_ARRAY)
{
AMF_Reset(&prop->p_vu.p_object);
}
else
{
prop->p_vu.p_aval.av_len = 0;
prop->p_vu.p_aval.av_val = NULL;
}
prop->p_type = AMF_INVALID;
} /************************************************************************************************************
* 编码: obj->pBuffer;
*
************************************************************************************************************/
char* AMF_Encode(AMFObject* obj, char* pBuffer, char* pBufEnd)
{
int i;
if (pBuffer + 4 >= pBufEnd)
{
return NULL;
}
*pBuffer++ = AMF_OBJECT; for (i = 0; i < obj->o_num; i++)
{
// 各个属性依次编码;
char* res = AMFProp_Encode(&obj->o_props[i], pBuffer, pBufEnd);
if (res == NULL)
{
RTMP_Log(RTMP_LOGERROR, "AMF_Encode - failed to encode property in index %d", i);
break;
}
else
{
pBuffer = res;
}
} if (pBuffer + 3 >= pBufEnd)
{
return NULL; /* no room for the end marker */
} // oject的对象需要以009结尾标识;
pBuffer = AMF_EncodeInt24(pBuffer, pBufEnd, AMF_OBJECT_END); return pBuffer;
} /************************************************************************************************************
* 编码: obj->pBuffer;
*
************************************************************************************************************/
char* AMF_EncodeEcmaArray(AMFObject* obj, char* pBuffer, char* pBufEnd)
{
int i;
if (pBuffer + 4 >= pBufEnd)
{
return NULL;
}
*pBuffer++ = AMF_ECMA_ARRAY; // 数组需要把个数编码进去;
pBuffer = AMF_EncodeInt32(pBuffer, pBufEnd, obj->o_num);
for (i = 0; i < obj->o_num; i++)
{
char* res = AMFProp_Encode(&obj->o_props[i], pBuffer, pBufEnd);
if (res == NULL)
{
RTMP_Log(RTMP_LOGERROR, "AMF_Encode - failed to encode property in index %d", i);
break;
}
else
{
pBuffer = res;
}
} if (pBuffer + 3 >= pBufEnd)
{
return NULL; /* no room for the end marker */
} // oject的对象需要以009结尾标识;
pBuffer = AMF_EncodeInt24(pBuffer, pBufEnd, AMF_OBJECT_END); return pBuffer;
} /************************************************************************************************************
* 编码: obj->pBuffer;
*
************************************************************************************************************/
char* AMF_EncodeArray(AMFObject* obj, char* pBuffer, char* pBufEnd)
{
int i;
if (pBuffer + 4 >= pBufEnd)
{
return NULL;
}
*pBuffer++ = AMF_STRICT_ARRAY; // 数组需要把个数编码进去;
pBuffer = AMF_EncodeInt32(pBuffer, pBufEnd, obj->o_num);
for (i = 0; i < obj->o_num; i++)
{
char* res = AMFProp_Encode(&obj->o_props[i], pBuffer, pBufEnd);
if (res == NULL)
{
RTMP_Log(RTMP_LOGERROR, "AMF_Encode - failed to encode property in index %d",
i);
break;
}
else
{
pBuffer = res;
}
} // 此处oject的对象不需要以009结尾标识;
//if (pBuffer + 3 >= pBufEnd)
// return NULL; /* no room for the end marker */ //pBuffer = AMF_EncodeInt24(pBuffer, pBufEnd, AMF_OBJECT_END); return pBuffer;
} /************************************************************************************************************
* 解码: pBuffer->obj;
*
************************************************************************************************************/
int AMF_DecodeArray(AMFObject* obj, const char* pBuffer, int nSize,
int nArrayLen, int bDecodeName)
{
int nOriginalSize = nSize;
int bError = FALSE; obj->o_num = 0;
obj->o_props = NULL;
while (nArrayLen > 0)
{
AMFObjectProperty prop;
int nRes;
nArrayLen--; nRes = AMFProp_Decode(&prop, pBuffer, nSize, bDecodeName);
if (nRes == -1)
{
bError = TRUE;
}
else
{
// 解码出来的属性追加到obj上;
nSize -= nRes;
pBuffer += nRes;
AMF_AddProp(obj, &prop);
}
}
if (bError)
{
return -1;
} return nOriginalSize - nSize;
} int AMF3_Decode(AMFObject* obj, const char* pBuffer, int nSize, int bAMFData)
{
int nOriginalSize = nSize;
int32_t ref;
int len; obj->o_num = 0;
obj->o_props = NULL;
if (bAMFData)
{
if (*pBuffer != AMF3_OBJECT)
{
RTMP_Log(RTMP_LOGERROR, "AMF3 Object encapsulated in AMF stream does not start with AMF3_OBJECT!");
} pBuffer++;
nSize--;
} ref = 0;
len = AMF3ReadInteger(pBuffer, &ref);
pBuffer += len;
nSize -= len; if ((ref & 1) == 0)
{
/* object reference, 0xxx */
uint32_t objectIndex = (ref >> 1); RTMP_Log(RTMP_LOGDEBUG, "Object reference, index: %d", objectIndex);
}
else /* object instance */
{
int32_t classRef = (ref >> 1); AMF3ClassDef cd = { {0, 0} };
AMFObjectProperty prop; if ((classRef & 0x1) == 0)
{
/* class reference */
uint32_t classIndex = (classRef >> 1);
RTMP_Log(RTMP_LOGDEBUG, "Class reference: %d", classIndex);
}
else
{
int32_t classExtRef = (classRef >> 1);
int i; cd.cd_externalizable = (classExtRef & 0x1) == 1;
cd.cd_dynamic = ((classExtRef >> 1) & 0x1) == 1; cd.cd_num = classExtRef >> 2; /* class name */ len = AMF3ReadString(pBuffer, &cd.cd_name);
nSize -= len;
pBuffer += len; /*std::string str = className; */ RTMP_Log(RTMP_LOGDEBUG,
"Class name: %s, externalizable: %d, dynamic: %d, classMembers: %d",
cd.cd_name.av_val, cd.cd_externalizable, cd.cd_dynamic,
cd.cd_num); for (i = 0; i < cd.cd_num; i++)
{
AVal memberName = AV_empty;
len = AMF3ReadString(pBuffer, &memberName);
RTMP_Log(RTMP_LOGDEBUG, "Member: %s", memberName.av_val);
AMF3CD_AddProp(&cd, &memberName);
nSize -= len;
pBuffer += len;
}
} /* add as referencable object */ if (cd.cd_externalizable)
{
int nRes;
AVal name = AVC("DEFAULT_ATTRIBUTE"); RTMP_Log(RTMP_LOGDEBUG, "Externalizable, TODO check"); nRes = AMF3Prop_Decode(&prop, pBuffer, nSize, FALSE);
if (nRes == -1)
RTMP_Log(RTMP_LOGDEBUG, "%s, failed to decode AMF3 property!",
__FUNCTION__);
else
{
nSize -= nRes;
pBuffer += nRes;
} AMFProp_SetName(&prop, &name);
AMF_AddProp(obj, &prop);
}
else
{
int nRes, i;
for (i = 0; i < cd.cd_num; i++) /* non-dynamic */
{
nRes = AMF3Prop_Decode(&prop, pBuffer, nSize, FALSE);
if (nRes == -1)
RTMP_Log(RTMP_LOGDEBUG, "%s, failed to decode AMF3 property!",
__FUNCTION__); AMFProp_SetName(&prop, AMF3CD_GetProp(&cd, i));
AMF_AddProp(obj, &prop); pBuffer += nRes;
nSize -= nRes;
}
if (cd.cd_dynamic)
{
int len = 0; do
{
nRes = AMF3Prop_Decode(&prop, pBuffer, nSize, TRUE);
AMF_AddProp(obj, &prop); pBuffer += nRes;
nSize -= nRes; len = prop.p_name.av_len;
}
while (len > 0);
}
}
RTMP_Log(RTMP_LOGDEBUG, "class object!");
}
return nOriginalSize - nSize;
} /************************************************************************************************************
* 解码: pBuffer->obj;
*
************************************************************************************************************/
int AMF_Decode(AMFObject* obj, const char* pBuffer, int nSize, int bDecodeName)
{
int nOriginalSize = nSize; int bError = FALSE;
/* if there is an error while decoding - try to at least find the end mark AMF_OBJECT_END */
// 如果解码出错,会尝试查找009结束标识符; obj->o_num = 0;
obj->o_props = NULL;
while (nSize > 0)
{
AMFObjectProperty prop;
int nRes; if (nSize >=3 && AMF_DecodeInt24(pBuffer) == AMF_OBJECT_END)
{
nSize -= 3;
bError = FALSE;
break;
} if (bError)
{
RTMP_Log(RTMP_LOGERROR, "DECODING ERROR, IGNORING BYTES UNTIL NEXT KNOWN PATTERN!");
nSize--;
pBuffer++;
continue;
} nRes = AMFProp_Decode(&prop, pBuffer, nSize, bDecodeName);
if (nRes == -1)
{
bError = TRUE;
}
else
{
// 解码出来的属性追加到obj上;
nSize -= nRes;
pBuffer += nRes;
AMF_AddProp(obj, &prop);
}
} if (bError)
{
return -1;
} return nOriginalSize - nSize;
} /************************************************************************************************************
* 将属性prop追加到obj上(深拷贝实现);
*
************************************************************************************************************/
void AMF_AddProp(AMFObject* obj, const AMFObjectProperty* prop)
{
if (!(obj->o_num & 0x0f))
{
// 此处的意思每次一次性申请16块内存, 若第17个属性追加时还会触发再申请16块内存;
obj->o_props = realloc(obj->o_props, (obj->o_num + 16) * sizeof(AMFObjectProperty));
} memcpy(&obj->o_props[obj->o_num++], prop, sizeof(AMFObjectProperty));
} /************************************************************************************************************
* 获取obj内的属性数量;
*
************************************************************************************************************/
int AMF_CountProp(AMFObject* obj)
{
return obj->o_num;
} /************************************************************************************************************
* 获取obj内的某个属性;
*
* 优先以nIndex进行返回, 若nIndex<0 会根据name进行筛选;
************************************************************************************************************/
AMFObjectProperty* AMF_GetProp(AMFObject* obj, const AVal* name, int nIndex)
{
if (nIndex >= 0)
{
if (nIndex < obj->o_num)
{
return &obj->o_props[nIndex];
}
}
else
{
int n;
for (n = 0; n < obj->o_num; n++)
{
if (AVMATCH(&obj->o_props[n].p_name, name))
{
return &obj->o_props[n];
}
}
} return (AMFObjectProperty* )&AMFProp_Invalid;
} /************************************************************************************************************
* 对obj内的所有属性进行输出显示,用于调试;
*
************************************************************************************************************/
void AMF_Dump(AMFObject* obj)
{
int n;
RTMP_Log(RTMP_LOGDEBUG, "(object begin)");
for (n = 0; n < obj->o_num; n++)
{
AMFProp_Dump(&obj->o_props[n]);
}
RTMP_Log(RTMP_LOGDEBUG, "(object end)");
} /************************************************************************************************************
* 对obj内的所有属性进行重置,最后并释放属性数组;
*
************************************************************************************************************/
void AMF_Reset(AMFObject* obj)
{
int n;
for (n = 0; n < obj->o_num; n++)
{
AMFProp_Reset(&obj->o_props[n]);
}
free(obj->o_props);
obj->o_props = NULL;
obj->o_num = 0;
} /* AMF3ClassDefinition */
/************************************************************************************************************
* 将字符串prop追加到cd内的字符串数组中(深拷贝);
*
************************************************************************************************************/
void AMF3CD_AddProp(AMF3ClassDef* cd, AVal* prop)
{
if (!(cd->cd_num & 0x0f))
{
cd->cd_props = realloc(cd->cd_props, (cd->cd_num + 16) * sizeof(AVal));
}
cd->cd_props[cd->cd_num++] = *prop;
} /************************************************************************************************************
* 获取cd对象内的字符串数组内的第nIndex个字符串;
*
************************************************************************************************************/
AVal* AMF3CD_GetProp(AMF3ClassDef* cd, int nIndex)
{
if (nIndex >= cd->cd_num)
{
return (AVal* )&AV_empty;
}
return &cd->cd_props[nIndex];
}

【原】AMFObject数据格式详解的更多相关文章

  1. (转)JPEG图片数据结构分析- 附Png数据格式详解.doc

       一.简述 JPEG是一个压缩标准,又可分为标准JPEG.渐进式JPEG及JPEG2000三种: ①标准JPEG:以24位颜色存储单个光栅图像,是与平台无关的格式,支持最高级别的压缩,不过,这种压 ...

  2. BMP图像数据格式详解

    一.简介 BMP(Bitmap-File)图形文件是Windows采用的图形文件格式,在Windows环境下运行的所有图象处理软件都支持BMP图象文件格式.Windows系统内部各图像绘制操作都是以B ...

  3. [原][osg]Geometry详解

    //geometry成员变量 PrimitiveSetList _primitives; osg::ref_ptr<Array> _vertexArray; //顶点 osg::ref_p ...

  4. android之解析json数据格式详解

    1.JSON解析     (1).解析Object之一: view sourceprint? 1 {"url":"http://www.cnblogs.com/qianx ...

  5. ArcGIS数据格式详解

  6. LVDS 数据通道详解 单8 单6

    1.1.1           LVDS接口分类 1.1.1.1              单路6bit LVDS 这种接口电路中,采用单路方式传输,每个基色信号采用6位数据,共18位RGB数据,因此 ...

  7. 详解YUV与RGB数据格式-2016.01.20

    参考文献 什么是I帧,P帧,B帧 图文详解YUV420数据格式 RGB565 与 RGB888的相互转换 最简单的基于FFmpeg的libswscale的示例(YUV转RGB)

  8. 算法进阶面试题01——KMP算法详解、输出含两次原子串的最短串、判断T1是否包含T2子树、Manacher算法详解、使字符串成为最短回文串

    1.KMP算法详解与应用 子序列:可以连续可以不连续. 子数组/串:要连续 暴力方法:逐个位置比对. KMP:让前面的,指导后面. 概念建设: d的最长前缀与最长后缀的匹配长度为3.(前缀不能到最后一 ...

  9. Unity3D NGUI UIPlayTween(原UIButtonTween)动画事件详解

    http://blog.csdn.net/asd237241291/article/details/8507817 原创文章如需转载请注明:转载自 脱莫柔Unity3D学习之旅 Unity3D引擎技术 ...

随机推荐

  1. Fastbin attack

    Fastbin Attack 暂时接触到了两种针对堆分配机制中fastbin的攻击方式,double free和house of spirit Double free 基本原理 与uaf是对free之 ...

  2. Kubernetes Pod故障归类与排查方法

    Pod概念 Pod是kubernetes集群中最小的部署和管理的基本单元,协同寻址,协同调度. Pod是一个或多个容器的集合,是一个或一组服务(进程)的抽象集合. Pod中可以共享网络和存储(可以简单 ...

  3. Spark学习之路 (二)Spark2.3 HA集群的分布式安装[转]

    下载Spark安装包 从官网下载 http://spark.apache.org/downloads.html 从微软的镜像站下载 http://mirrors.hust.edu.cn/apache/ ...

  4. Educational Codeforces Round 76 (Rated for Div. 2)F - Make Them Similar

    题意: 给你n个数字(<230),求出一个数字使得所有数字^这个数字之后,二进制状态下的1的个数相同. 解析: 因为最大数字二进制数有30位,所以分为前15位和后15位,分别枚举0-1<& ...

  5. vue制作滚动条幅-跑马灯效果实例代码

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  6. 天兔修改登录页的title

    1.将 /opt/lampp/htdocs/lepus/application/views/login.php 文件中 第6行 <title><?php echo $this-> ...

  7. a标签绑定事件

    <a href="javascript:void(0);" onclick="js_method()"></a> 这种方法是很多网站最常 ...

  8. (转) 统计在从1到n的正整数中1出现的次数

    1. 题目描述 输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数.例如输入12,从1到12这些整数中包含1的数字有1,10,11和12,1一共出现了5次. 2. 题目来源 第一次看到是在 ...

  9. MySQL 8.0.18 在 Windows Server 2019 上的安装(ZIP)公开

    AskScuti MySQL : Windows Server 2019 安装 MySQL 8.0 温馨提示:为了展现我最“魅力”的一面,请用谷歌浏览器撩我. 一切就绪,点我开撩

  10. Oracle监听出现的问题总结,以及解决办法

    包括的错误类型: 1.ORA-12541: TNS: 无监听程序 2. ORA-12514: TNS: 监听程序当前无法识别连接描述符中请求的服务 3.ORA-12560: TNS: 协议适配器错误 ...