首页 > 学院 > 开发设计 > 正文

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

2019-11-06 08:28:00
字体:
来源:转载
供稿:网友

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, // 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;}


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表