欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

OpenRTMFP/Cumulus Primer(18)AMF解析之AMFReader(续2)  

程序员文章站 2022-05-13 17:42:57
...

OpenRTMFP/Cumulus Primer(18)AMF解析之AMFReader(续2)

  • Author: 柳大·Poechant(钟超)
  • Email: zhongchao.ustc#gmail.com (#->@)
  • Blog:Blog.CSDN.net/Poechant
  • Date: April 24th, 2012

1 开始引用与结束引用

如下这两个函数会在 FlowConnection 中调用。

inline void AMFReader::startReferencing() {
    _referencing = true;
}

inline void AMFReader::stopReferencing() {
    _referencing = false;
}

2 解析 AS3 ByteArray

先回顾一下 AMF3 中的ByteArray 的数据格式:

OpenRTMFP/Cumulus Primer(18)AMF解析之AMFReader(续2)
            
    
    
         

注意到,首先要读取一个变长无符号 32 位整数,但是最低位是 1,只有 28 位用于表示数据长度。解释完这里,下面的解析过程才好理解。

BinaryReader& AMFReader::readByteArray(UInt32& size) {

惯例:

    reset();
    AMF::Type type = followingType();

Null 就返回 BinaryReaderNull。

    if (type == AMF::Null) {
        reader.next(1);
        return BinaryReader::BinaryReaderNull;
    }

如果不是 ByteArray,也返回 BinaryReaderNull:

    if (type != AMF::ByteArray) {
        ERROR("Type %.2x is not a AMF ByteArray type",type);
        return BinaryReader::BinaryReaderNull;
    }

跳过这个字节:

    reader.next(1);

注意 position 返回的是相对位置,与 AS3 中一样。reference 表示这个地址(简单说,引用就是地址嘛)。

    UInt32 reference = reader.position();

读取一个变长 32 位无符号整数:

    size = reader.read7BitValue();

最低位是 1 的话,isInline 是 true,否则为 false。

    bool isInline = size & 0x01;

右移一位,因为那一位是标志位,上面解释过了。

    size >>= 1;

如果 isInline 是 true,表示是 ByteArray:

    if (isInline) {

如果 _referencing 为 true 的话(这是一个 vector),push back this reference:

        if (_referencing)
            _references.push_back(reference);
    }

不符合 ByteArray 的格式定义的话:

    else {
        if (size > _references.size()) {
            ERROR("AMF3 reference not found")
            return BinaryReader::BinaryReaderNull;
        }
        _reset = reader.position();

移动到这个 reference 的位置,_references[size] 就是这个位置(相对)。

        reader.reset(_references[size]); // TODO size 作为索引,还没有完全理解

读取这个 reference 的 size 值给 size对象(注意 size 是这个函数传入的引用参数,其值可以被修改)。

        size = reader.read7BitValue() >> 1;
    }

把读取完 ByteArraty 的 PacketReader 返回:

    return reader;
}

最后强调一点,ByteArray 的数据段最大长度为 228-1 字节,约为 256 MB。

2 解析 AS3 Date

先看下 Date 的数据格式:

OpenRTMFP/Cumulus Primer(18)AMF解析之AMFReader(续2)
            
    
    
         

下面开始分析:

Timestamp AMFReader::readDate() {

惯例:

    reset();
    AMF::Type type = followingType();

Null 的话,就返回当前时间:

    if (type == AMF::Null) {
        reader.next(1);
        return Timestamp(0);
    }

如果不是 Date 类型,也返回当前时间:

    if (type != AMF::Date) {
        ERROR("Type %.2x is not a AMF Date type",type);
        return Timestamp(0);
    }

    reader.next(1);
    double result = 0;

如果是 AMF3:

    if(_amf3) {

先读取 flag,最低一位必须是 1,其他位丢到垃圾桶。

        UInt32 flags = reader.read7BitValue();

当前相对位置。

        UInt32 reference = reader.position();

是 1 就 push back 到 _references 里。

        bool isInline = flags & 0x01;
        if (isInline) {
            if(_referencing)
                _references.push_back(reference);

读取一个 double,到 result 里(result 也是 double 类型哦~)。

            reader >> result;
        }

如果标志位不是 1,麻烦不少哒。。。

        else {
            flags >>= 1;

如果 flag 超了,就返回当前时间作为时间戳作为 Date。

            if (flags > _references.size()) {
                ERROR("AMF3 reference not found")
                return Timestamp(0);
            }

这段与 ByteArray 那段一样:

            _reset = reader.position();
            reader.reset(_references[flags]);
            reader >> result;
            reset();
        }

返回喽~

        return Timestamp((Timestamp::TimeVal) result * 1000);
    }
    reader >> result;

读俩,因为是 double(64 位):

    reader.next(2); // Timezone, useless

返回喽~

    return Timestamp((Timestamp::TimeVal) result * 1000);
}

3 解析 AS3 Dictionary

bool AMFReader::readDictionary(bool& weakKeys) {

下面这段咱就略了。。

    reset();
    AMF::Type type = followingType();
    if (type == AMF::Null) {
        reader.next(1);
        return false;
    }
    if (type != AMF::Dictionary) {
        ERROR("Type %.2x is not a AMF Dictionary type",type);
        return false;
    }

跳过 type:

    // AMF3
    reader.next(1); // marker

当前相对位置值作为 reference,再读个 size,还是最低位必须为 1,不是就返回 false。

    UInt32 reference = reader.position();
    UInt32 size = reader.read7BitValue();
    bool isInline = size & 0x01;
    size >>= 1;
    if(!isInline && size>_references.size()) {
        ERROR("AMF3 reference not found")
        return false;
    }

下面要调用到 ObjectRef 构造函数,这里再把其实现拿出来看看,其实主要是初始化了哪些成员。

ObjectDef(UInt32 amf3,UInt8 arrayType=0)
    : amf3(amf3),
      reset(0),
      dynamic(false),
      externalizable(false),
      count(0),
      arrayType(arrayType) {
}

可以看到要有一个 amf3,还有 reset 置为 0,dynamic 置为 false,externalizable 也是 false,count 是 0,arrayType 成员要赋值。

上面是插播哦,下面还要继续哒。创建这么一个对象,注意是 new 出来的,所以我们在《OpenRTMFP/Cumulus Primer(16)AMF解析之AMFReader》一文中提到了 AMFReader 的析构函数中要对 _objectRef 的每个元素逐一析构的。arrayType 就设置为 AMF3_DICTIONARY。

    ObjectDef* pObjectDef = new ObjectDef(_amf3, AMF3_DICTIONARY);
    pObjectDef->dynamic=true;
    _objectDefs.push_back(pObjectDef);

如果标志位是 1,就直接 push back,跟之前一样。不过这里多了一个 pObjectDef,所以还要设置一下它的计数为 size,就是 dictionary 数据大小。

    if (isInline) {
        if (_referencing)
            _references.push_back(reference);
        pObjectDef->count = size;
    }

如果标志位是 0,就把 count 设置为下一个变长整数值。

    else {
        pObjectDef->reset = reader.position();
        reader.reset(_references[size]);
        pObjectDef->count = reader.read7BitValue() >> 1;
    }
    pObjectDef->count *= 2;

读一个字节,如果最小位是 1,weakKeys 就是 true,否则为 false。

    weakKeys = reader.read8() & 0x01;

    return true;
}

-

转载请注明来自柳大的CSDN博客:Blog.CSDN.net/Poechant

-

上一篇: common

下一篇: connection