RTMP学习(十五)rtmpdump源码阅读(9)AMF格式

来源:互联网 发布:如何出售域名 编辑:程序博客网 时间:2024/04/28 18:15

AMF格式



    AMF就是一种数据转换的规则(或者协议),它把本地字节顺序的数据转换成网络字节顺序(大端字节顺序)。

    因为在进行网络通信的时候,我们需要对数据进行格式转换,这里的数据是指除了Byte(char字节)以外的所有数据类型,这样才方便通信双方对数据的理解。

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


AMF支持的数据类型


    AMF0支持的数据类型

// amf(AMF0)的数据类型typedef enum{AMF_NUMBER = 0, // 数字(double)AMF_BOOLEAN, // 布尔AMF_STRING,  // 字符串AMF_OBJECT, // 对象AMF_MOVIECLIP,/* reserved, not used */ // 保留AMF_NULL, // nullAMF_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 */ // 需要扩展到AMF3AMF_INVALID = 0xff} AMFDataType;

    AMF3支持的数据类型

typedef enum{AMF3_UNDEFINED = 0, // 未定义AMF3_NULL,  // nullAMF3_FALSE, // falseAMF3_TRUE, // trueAMF3_INTEGER, // intAMF3_DOUBLE, // doubleAMF3_STRING,  // stringAMF3_XML_DOC, // xmlAMF3_DATE, // 日期AMF3_ARRAY, // 数组AMF3_OBJECT,  // 对象AMF3_XML,  // xmlAMF3_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){// 字符串的长度是int16bv->av_len = AMF_DecodeInt16(data);bv->av_val = (bv->av_len > 0) ? (char *)data + 2 : NULL;}

// 解码长字符串voidAMF_DecodeLongString(const char *data, AVal *bv){// 字符串的长度是int32bv->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#endifreturn 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;}



0 0
原创粉丝点击