zoukankan      html  css  js  c++  java
  • 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:	%.2f", prop->p_vu.p_number);
            break;
        case AMF_BOOLEAN:
            snprintf(str, 255, "BOOLEAN:	%s",
                prop->p_vu.p_number != 0.0 ? "TRUE" : "FALSE");
            break;
        case AMF_STRING:
            snprintf(str, 255, "STRING:	%.*s", prop->p_vu.p_aval.av_len,
                prop->p_vu.p_aval.av_val);
            break;
        case AMF_DATE:
            snprintf(str, 255, "DATE:	timestamp: %.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);
    }
  • 相关阅读:
    ADO.NET基础学习 二(Command对象)
    如何使ElementUI中的el-dropdown传入多参数
    Vue router Element 重复点击导航路由报错解决方法
    vue-svgicon基本使用
    js 两个相等的数组,修改其中一个怎么做到不改变另外一个
    LocalStorage存储JSON对象
    js取整数、取余数的方法
    JS正则截取两个字符串之间及字符串前后内容的方法
    Vuetify 表单规则验证
    JS正则表达式
  • 原文地址:https://www.cnblogs.com/wainiwann/p/4256252.html
Copyright © 2011-2022 走看看