AMF 格式是 Adobe 推出的一个二进制数据格式
AMF0 :http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/amf/pdf/amf0-file-format-specification.pdf
AMF3 :http://download.macromedia.com/pub/labs/amf/amf3_spec_121207.pdf
rtmp流里分析帧类型18为AMF0类型,15为AMF3类型。 rtmp流里常用的AMF0格式有: AMF_NUMBER 0x00 AMF_BOOLEAN 0x01 AMF_STRING 0x02 AMF_NULL 0x05 AMF_LONG_STRING 0x0C AMF_OBJECT 0x03 AMF_OBJECT_END 0x09
解析流程: 一个字节为类型 :后面字节为数据内容 例子: 01 00 01 表示后面的值为bool , 00 为值 false
各个常用类型的解析
AMF_NUMBER :一个类型字节 + 八个数据字节(大编码)
00 41 1e 9a e4 00 00 00 00 00 表示 AMF_NUMBER 41 1e 9a e4 00 00 00 00 换算为 501433
AMF_BOOLEAN : 一个类型字节 + 一个数字字节
01 01 01 表示 AMF_BOOLEAN 01 为 true
AMF_STRING :一个类型字节 + 二个字节保存长度N (大编码) + N个数据字节
02 00 04 6d 70 34 32 02 表示 AMF_STRING 00 04 表示字符串长度为4 6d 70 34 32 换算成 “mp42”
AMF_NULL : 一个类型字节
05 05 表示 AMF_NULL 后面没有数据内容
AMF_LONG_STRING :一个类型字节 + 四个字节保存长度N(大编码) + N个数据字节
类似 AMF_STRING ,只是长度由4个字节组装
AMF_OBJECT : 一个类型字节 + N个组合字节[AMF_STRING + 一个类型字节 + 类型字节内容] + 长度为0的AMF_STRING + AMF_OBJECT_END类型字节
Name: level 为一个AMF_STRING类型,不带一个字节类型标示 String `status` 为一个AMF_STRING类型,带一个字节类型标示,也可以是带一个字节类型标示的AMF_BOOLEAN或者AMF_NUMBER
代码: yuAMF.h
typedef enum{ AMF_NUMBER = 0, AMF_BOOLEAN, AMF_STRING, AMF_OBJECT, AMF_MOVIECLip, /* reserved, not used */ AMF_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, AMF_TYPED_OBJECT, AMF_AVMPLUS, /* switch to AMF3 */ AMF_INVALID = 0xff} AMFDataType;typedef struct AVal{ char *av_val; int av_len;} AVal;class uyAMF {public: uyAMF(char* data , int len); ~uyAMF(); bool checkout(); AMFDataType AMF_GetType(); unsigned short AMF_DecodeInt16(); unsigned int AMF_DecodeInt24(); unsigned int AMF_DecodeInt32(); void AMF_DecodeString( AVal& bv); void AMF_DecodeLongString( AVal& bv); int AMF_DecodeBoolean(); double AMF_DecodeNumber(); void AMF_DecodeObject(std::map<std::string,std::string>& paramMap);public: char* amf_data; int amf_len; int decode_amf_len;};uyAMF.cpp
uyAMF::uyAMF(char *data, int len):amf_data(data),amf_len(len),decode_amf_len(0){}uyAMF::~uyAMF(){}AMFDataType uyAMF::AMF_GetType(){ decode_amf_len ++ ; return (AMFDataType)*amf_data++;}unsigned short uyAMF::AMF_DecodeInt16(){ if (decode_amf_len + 2 > amf_len) { return 0; } unsigned char *c = (unsigned char *) amf_data; unsigned short val; val = (c[0] << 8) | c[1]; amf_data += 2; decode_amf_len += 2; return val;}unsigned int uyAMF::AMF_DecodeInt24(){ if (decode_amf_len + 3 > amf_len) { return 0; } unsigned char *c = (unsigned char *) amf_data; unsigned int val; val = (c[0] << 16) | (c[1] << 8) | c[2]; amf_data += 3; decode_amf_len += 3; return val;}unsigned int uyAMF::AMF_DecodeInt32(){ if (decode_amf_len + 4 > amf_len) { return 0; } unsigned char *c = (unsigned char *)amf_data; unsigned int val; val = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3]; amf_data += 4; decode_amf_len += 4; return val;}void uyAMF::AMF_DecodeString(AVal& bv){ if (decode_amf_len + 1 > amf_len) { bv.av_len = 0; bv.av_val = NULL; return; } bv.av_len = AMF_DecodeInt16(); if (decode_amf_len + bv.av_len > amf_len) { bv.av_len = 0; bv.av_val = NULL; return; } bv.av_val = (bv.av_len > 0) ? (char *)amf_data : NULL; amf_data += bv.av_len ; decode_amf_len += bv.av_len;}void uyAMF::AMF_DecodeLongString(AVal &bv){ if (decode_amf_len + 1 > amf_len) { bv.av_len = 0; bv.av_val = NULL; return; } bv.av_len = AMF_DecodeInt32(); if (decode_amf_len + bv.av_len > amf_len) { bv.av_len = 0; bv.av_val = NULL; return; } bv.av_val = (bv.av_len > 0) ? (char *)amf_data : NULL; amf_data += bv.av_len ; decode_amf_len += bv.av_len;}int uyAMF::AMF_DecodeBoolean(){ bool succ = *amf_data != 0; amf_data += 1; decode_amf_len += 1; return succ;}double uyAMF::AMF_DecodeNumber(){ if (decode_amf_len + 8 > amf_len) { return 8; } double dVal;#if __FLOAT_Word_ORDER == __BYTE_ORDER#if __BYTE_ORDER == __BIG_ENDIAN memcpy(&dVal, amf_data, 8);#elif __BYTE_ORDER == __LITTLE_ENDIAN unsigned char *ci, *co; ci = (unsigned char *)amf_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 *)amf_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 *)amf_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 decode_amf_len += 8; amf_data += 8; return dVal;}bool uyAMF::checkout(){ return (decode_amf_len + 1 <= amf_len);}void uyAMF::AMF_DecodeObject(std::map<std::string, std::string>& paramMap){ AVal tmp; std::string val; std::string key; bool succ = true; while (succ) { key.clear(); val.clear(); AMF_DecodeString(tmp); PRintf_info("Name : %s",tmp.av_val); AMFDataType type = AMF_GetType(); key.append(tmp.av_val,tmp.av_len); switch (type) { case AMF_STRING: AMF_DecodeString(tmp); printf_info("string : %s",tmp.av_val); val.append(tmp.av_val,tmp.av_len); break; case AMF_NUMBER: { double db = AMF_DecodeNumber(); printf_info("double : %f",db); char data[1024] = {0}; sprintf(data,"%f",db); val = data; break; } case AMF_BOOLEAN: { bool succ = AMF_DecodeBoolean(); printf_info("bool : %d",succ); val = succ ? "true" : "false"; break; } case AMF_OBJECT_END: default: succ = false; break; } paramMap[key] = val; }}新闻热点
疑难解答