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()的源码:

void
AMFProp_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);
}

 

转载于:https://www.cnblogs.com/wainiwann/p/4256252.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值