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) {如果不是 Date 类型,也返回当前时间:
reader.next(1); return Timestamp(0);
}
if (type != AMF::Date) {如果是 AMF3:
ERROR("Type %.2x is not a AMF Date type",type);
return Timestamp(0);
}
reader.next(1); double result = 0;
if(_amf3) {先读取 flag,最低一位必须是 1,其他位丢到垃圾桶。
UInt32 flags = reader.read7BitValue();当前相对位置。
UInt32 reference = reader.position();是 1 就 push back 到 _references 里。
bool isInline = flags & 0x01;读取一个 double,到 result 里(result 也是 double 类型哦~)。
if (isInline) { if(_referencing)
_references.push_back(reference);
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) {跳过 type:
reader.next(1); return false;
}
if (type != AMF::Dictionary) {
ERROR("Type %.2x is not a AMF Dictionary type",type);
return false;
}
// AMF3 reader.next(1); // marker当前相对位置值作为 reference,再读个 size,还是最低位必须为 1,不是就返回 false。
UInt32 reference = reader.position(); UInt32 size = reader.read7BitValue();下面要调用到 ObjectRef 构造函数,这里再把其实现拿出来看看,其实主要是初始化了哪些成员。
bool isInline = size & 0x01;size >>= 1; if(!isInline && size>_references.size()) {
ERROR("AMF3 reference not found")
return false;
}
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)如果标志位是 0,就把 count 设置为下一个变长整数值。
_references.push_back(reference);
pObjectDef->count = size;
}
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-
相关文章推荐
- OpenRTMFP/Cumulus Primer(16)AMF解析之AMFReader
- OpenRTMFP/Cumulus Primer(9)AMF解析之BinaryReader/Writer
- OpenRTMFP/Cumulus Primer(17)AMF解析之AMFReader(续1)
- OpenRTMFP/Cumulus Primer(9)AMF解析之BinaryReader/Writer
- OpenRTMFP/Cumulus Primer(14)AMF解析之PacketReader/Writer
- OpenRTMFP/Cumulus Primer(15)AMF解析之数据类型定义
- OpenRTMFP/Cumulus Primer(10)IO 管理之流缓冲区
- OpenRTMFP/Cumulus Primer(1)入门介绍与部署CumulusServer
- OpenRTMFP/Cumulus Primer(8)CumulusServer主进程主循环分析
- OpenRTMFP/Cumulus Primer(11)IO 管理之IO流
- OpenRTMFP/Cumulus Primer(2)用Lua编写HelloWorld应用扩展CumulusServer
- OpenRTMFP/Cumulus Primer(6)CumulusServer启动流程分析(续2)
- OpenRTMFP/Cumulus Primer(12)IO管理之IO流(续)
- OpenRTMFP/Cumulus Primer(3)图解CumulusEdge原理
- OpenRTMFP/Cumulus Primer(1)入门介绍与部署CumulusServer
- OpenRTMFP/Cumulus Primer(2)用Lua编写HelloWorld应用扩展CumulusServer
- OpenRTMFP/Cumulus Primer(13)IO管理之局部内存片
- OpenRTMFP/Cumulus Primer 入门(3)图解CumulusEdge原理
- OpenRTMFP/Cumulus Primer(4)CumulusServer启动流程分析
- OpenRTMFP/Cumulus Primer(4)CumulusServer启动流程分析