AMF就是一种数据转换的规则(或者协议),它把本地字节顺序的数据转换成网络字节顺序(大端字节顺序)。
因为在进行网络通信的时候,我们需要对数据进行格式转换,这里的数据是指除了Byte(char字节)以外的所有数据类型,这样才方便通信双方对数据的理解。
AMF分成两种: 1、AMF0,基本的数据转换规则 2、AMF3,是AMF0的扩展
AMF0支持的数据类型
// amf(AMF0)的数据类型 typedef enum { AMF_NUMBER = 0, // 数字(double) AMF_BOOLEAN, // 布尔 AMF_STRING, // 字符串 AMF_OBJECT, // 对象 AMF_MOVIECLip, /* reserved, not used */ // 保留 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, /* reserved, not used */ // 保留 AMF_xml_DOC, // xml文档 AMF_TYPED_OBJECT, // 有类型的对象 AMF_AVMPLUS, /* switch to AMF3 */ // 需要扩展到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, // string AMF3_XML_DOC, // xml AMF3_DATE, // 日期 AMF3_ARRAY, // 数组 AMF3_OBJECT, // 对象 AMF3_XML, // xml AMF3_BYTE_ARRAY // 字节数组 } AMF3DataType;与AMF相关的数据结构
值
“值”是指普通的非复合结构的值,例如:整形、布尔、浮点、字符串等等。
/* ** AVal表示一个值 */ typedef struct AVal { char *av_val; // value的存放的地址 int av_len; // value的长度 } AVal;对象
对象表示了一个复合的数据结构。
// AMF对象 typedef struct AMFObject { // 属性的数量,因为对象实际就是由一系列的属性构成的 int o_num; // 属性数组 struct AMFObjectPRoperty *o_props; } AMFObject;对象属性
对象实际由多个对象属性构成。
属性包含:属性名字、属性类型、属性值等
// 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;数据转换规则
下面的数据转换规则以解码为例子,解码就是把网络字节顺序的数据转换为本地字节顺序。
整形转换
// 解码int16unsigned shortAMF_DecodeInt16(const char *data){ unsigned char *c = (unsigned char *)data; unsigned short val; // int16的两个字节互换 val = (c[0] << 8) | c[1]; return val;}// 解码int24(这个整数占用三个字节)unsigned intAMF_DecodeInt24(const char *data){ unsigned char *c = (unsigned char *)data; unsigned int val; // 调整内部字节的顺序 val = (c[0] << 16) | (c[1] << 8) | c[2]; return val;}// 解码int32unsigned intAMF_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;}字符串转换
解析的流程:
1、先解析字符串的长度
2、再获取字符串的数据
// 解码字符串voidAMF_DecodeString(const char *data, AVal *bv){ // 字符串的长度是int16 bv->av_len = AMF_DecodeInt16(data); bv->av_val = (bv->av_len > 0) ? (char *)data + 2 : NULL;}// 解码长字符串voidAMF_DecodeLongString(const char *data, AVal *bv){ // 字符串的长度是int32 bv->av_len = AMF_DecodeInt32(data); bv->av_val = (bv->av_len > 0) ? (char *)data + 4 : NULL;}数值(double)转换
// 解码数值(double)doubleAMF_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;}布尔转换
// 解码booleanintAMF_DecodeBoolean(const char *data){ return *data != 0;}对象转换
因为对象是由一个个的属性构成的,因此,它的内部实际是对对象属性进行转换。
// 解码一个AMF对象intAMF_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 */ obj->o_num = 0; obj->o_props = NULL; // 解码对象中所有的属性 while (nSize > 0) { AMFObjectProperty prop; int nRes; // 得到object 结束的标签,表示对象解码完成 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 { // 把属性添加到对象中 nSize -= nRes; pBuffer += nRes; AMF_AddProp(obj, &prop); } } if (bError) return -1; return nOriginalSize - nSize;}对象属性转换
解析的过程如下:
1、先解析属性名称(字符串)的长度
2、解析属性名称
3、解析属性的数据类型
4、根据数据类型的不同调用不同的解析函数
// 对象属性解码intAMFProp_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 (*pBuffer == AMF_NULL) bDecodeName = 0; 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) { // 解析属性名字的长度 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; prop->p_type = AMF_OBJECT; 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; prop->p_type = AMF_OBJECT; 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: // xml { 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; } return nOriginalSize - nSize;}
新闻热点
疑难解答