您的位置:首页 > 运维架构

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

2012-04-24 18:24 696 查看

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 的数据格式:

注意到,首先要读取一个变长无符号 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 的数据格式:

下面开始分析:
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-
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: