首页 > 代码库 > AMFObject 数据格式浅析

AMFObject 数据格式浅析

amf.h中关于 AMFObject 是这样的定义的:

 typedef struct AMFObject  {    int o_num;    struct AMFObjectProperty *o_props;  } AMFObject;

有里面变量可知 o_num 代表 o_props的个数;

在rtmp.c里有这样一段使用在

static int HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize){    AMFObject obj;    AVal method;    AVal method11;    int txn;    int ret = 0, nRes;    if (body[0] != 0x02)        /* make sure it is a string method name we start with */    {        //RTMP_Log(RTMP_LOGWARNING, "%s, Sanity failed. no string method in invoke packet", __FUNCTION__);        return 0;    }    nRes = AMF_Decode(&obj, body, nBodySize, FALSE);    if (nRes < 0)    {        //RTMP_Log(RTMP_LOGERROR, "%s, error decoding invoke packet", __FUNCTION__);        return 0;    }

   AMF_Dump(&obj);
   AMFProp_GetString(AMF_GetProp(&obj, NULL, 0), &method);  
  .....  .....}

在此函数内 AMFObject obj;通过 nRes = AMF_Decode(&obj, body, nBodySize, FALSE); 会对body进行AMF解码相当于给obj进行赋值,然后通过AMF_Dump(&obj) 应该是进行一个解析?(最下面会贴出该函数的源码)

经过AMF_Dump()之后,会获通过 AMFProp_GetString(AMF_GetProp(&obj, NULL, 0), &method); 获取信令的操作。当然也可以自定义他们的操作,类似于:

static const AVal av_NetStream_Pause_Notify = AVC("NetStream.Pause.Notify");static const AVal av_NetStream_Play_UnpublishNotify = AVC("NetStream.Play.UnpublishNotify");//................

下面代码会根据method的内容进行相应的操作。
-----------------------------------------------

扯的有点偏了,这里还是 讲AMFObject 上面的操作经过抓包可以看一下大致的内容:

技术分享

===================================================

由包里的内容此次信令操作为自定义的“NoticeNotify”,而obj相当于一个容器,里面就有上面标识的3项内容,也就是根据AMFObject 的数据结构可知:

o_num 个数为3 项 o_props 内容。而 o_props 的数据结构为:

 

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;  } AMFObjectProperty;


其中 o_props 里有个“联合”数据结构成员,从上面抓包的内容来看其中的三项,也很好的解释了其中三项的内容。

第一项:type 为string 对应 AVal 类似于 key-value

第二项:type 为Number 对应 double。

第三项:type 也为string 对应 AVal。

这样来看如果想取obj里的内容就比较好取了。

其中obj的成员 o_props 就是一个类似数组,在操作的时候可以 obj->o_props[index];

或者再细一点就是 obj->o_props[index].p_type;

=====================================

总结的比较乱,因为现在对amf还不是很了解,不过对于amf真的可以花些时间去分析一下它的博大精深。

 

 

 

 

 

 

 

 

 

 

再此贴一下AMF_Dump()的源码:

voidAMFProp_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);    if (prop->p_type == AMF_OBJECT)    {        //RTMP_Log(RTMP_LOGDEBUG, "Property: <%sOBJECT>", strRes);        AMF_Dump(&prop->p_vu.p_object);        return;    }    switch (prop->p_type)    {    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);    }    //RTMP_Log(RTMP_LOGDEBUG, "Property: <%s%s>", strRes, str);}

 

AMFObject 数据格式浅析