获取CBS站点的高清视频的小结

引子:近几日,本人想获取CBS站点的高清视频文件。刚开始,采用常规的解析HTTP头域,找Content-Type = video/x-flv,以及Content-Length的方法。很遗憾,没有成功。几经探究发现,CBS站点是使用RTMP传送视频数据。由此,就有了后续的开发。

准备:在Linux下,用FireFox观看CBS高清视频(用作唤起CBS站点的视频服务),与此同时,让“IP数据包监视器”(在Linux下,自己写的程序)将此时网络上的数据全部存盘。记录在data.bin中。

环境:本人在Linux下未能找到便捷的Hex源码查看和编辑工具,所以换到Windows下,同时在其下开发,用来解析RTMP 。


正文:RTMP数据可通过专门端口:1935,或者借助HTTP之80端口(此时RTMP是将其伪装成普通的HTTP数据)传输。所以在data.bin需查找这两处端口的传送内容。假如是端口1935,那好办,铁定就是RTMP数据(虽然这么说,该做的有效性检查,还是需要的)。若是借助HTTP的80端口,那就要看到CBS站点高清视频的另一个特点————采用FLV格式,且是砍掉了FLV格式前9个头字节的FLV文件。以此原则在data.bin中提取RTMP时,还应考虑一个问题,假如data.bin中保留有超过一个以上的视频内容,如何区分?就是找被砍掉前9字节的FLV,那就是新的视频文件的开始。


如何来判断在data.bin中的哪些数据是某一视频文件中的内容呢?考虑TCP/IP的一个特点,TCP有两个字段,其一是“发送序号",其二是"接收序号"。对于一段完整的信息“接收序号”是相当于类型识别字,即只要是后续TCP包中还是该“接收序号”,那么说明它还是该视频文件。“发送序号”是说明TCP包中视频数据在欲还原的视频文件中的相对位置。以第1块(序数词从1开始)的“发送序号”作为基址,后续“发送序号”与此基址相减,就是后续TCP包中的视频数据在欲还原的视频文件中地址。例如:第1块“发送序号”是0x10000000,第2块“发送序号”是0x10000A00,那说明第2块应将TCP包中视频数据,接着第1块记录,且从0x0A00开始。若一切正确,那么第1块的已经记录的内容长度也应为0x0A00。

还有一个情况需要考虑,当视频文件较大时,TCP的“接收序号”会变化(都是增加),所以此时就不能简单以“接收序号”变化,作为新的视频文件开始的判断条件。还应该结合“发送序号”,若此时N+1的TCP数据包中的“发送序号”减去,N的TCP的数据包中的“发送序号”,正好等于N的TCP数据包的有效数据的长度,那么此时的N+1的TCP数据仍和N的TCP数据一样,同属于同一视频文件。

第3点要注意的是,"发送序号"、“接收序号”是一个以Big-Endian排列的4字节数值,当它们增加时,有可能卷回来,也就是从0xFFFFFFFF加到0x00000000,在计算的时候,需要注意此特点。

既然说到了TCP/IP数据,那再多说两句。其一,自研的IP数据包监视器,是原样记录通过本机网卡的IP数据包。众所周知,IP数据包是有可能“先出后到”的,那就是说,在做上述操作前,需将原样的IP数据包按预期的顺序重新排序(先将IP数据按照站点分类),方法为:以“接收序号”,由小到大对IP数据包进行排序,再以“发送序号”,由小到大对“接收序号”相同的IP数据包再排序。对于序号大小,也要注意上面提到的有可能卷回来的情况。其二,IP数据包,可能重传某些内容。TCP协议毕竟是可靠连接协议,那些重传的内容的TCP包,虽然N的“发送序号”和“接收序号”,与N+1的“发送序号”和“接收序号”不能彼此映射,但是以它们相对第1块的算出的偏址,并以此偏址索引应的数据内容却肯定是一样的。若不一样,请自行查找错误的原因!



到此时,终于将CBS的高清视频数据从data.bin中提取出来。可以对其,按照RTMP方式进行分析。首先要说的第一句是,RTMP不是仅仅为传FLV而制定的,而本文又是以获取FLV高清视频为目标的,所以会有对RTMP“以偏代全”的认识,请注意。

RTMP没有专门的开始识别字,所以对于任意数据都可用来作为头域进行分析。那如何来判断其头域是否有效呢?
方法一,头域中必须要有合法的“消息类型”。对于头域中没有“消息类型”字段的,那么判断该块数据所对应的Chunk ID是否与前一头域中的Chunk ID是否相同?若否,则该数据区不是合法头域。
方法二,chunk ID 和 message stream Id数值一般不会每个字节都是非零值,若出现,此两项ID的每个字段都是非零值,则重点怀疑该数据区为头域的正确性。
方法三,没有哪个视频的播放时间会超过1天,甚至超值5小时的都很少,所以,头域中timestamp不应该超过5小时(5小时都是有很大余量的),若出现超过5小时的值,则重点怀疑该数据区为头域的正确性。
前三个方法,除了方法1是铁定判断法则外(判断为非法头域的充分条件,判断为合法头域的必要条件),其余两个只能作为旁证。
方法四,先假定某片数据N的是合法头域,以此头域来的message length计算后续块N+1开始的位置,对N+1位置的数据进行头域判断,若其中为非法“消息类型”,则可断定为此前假定的N为合法头域,是错误的。假如能看到方法二、三的旁证,那就更能说明问题了。需要注意的是,若N+1开始的位置是无“消息类型”的消息时,可判断N是否为aggregate message,若是,再找N+2,若否,则可判出此前假设N为合法头域,是错误的。

在RTMP头域中,有个Extended Time Stamp的4字节字段,它要在头域中time stamp字段为0xFFFFFF时,才出现。同时我们也可看看当time stamp为全1时,表示的时间约为4.66小时,而在高清视频中,是很少出现的,所以Extended Time Stamp 也很少出现。


RTMP的"消息类型"为8、9、18、22时,是我所关心的,8对应Audio,9对应Video,18对应FLV的描述脚本,22对应aggregate message。22类型表示紧接的数据包含有若干的8、9类型的视频内容,这些内容有别于在chunk中类型的8、9的标志时,在类型22的8、9又带有子头域,格式为: Message Type 1Byte + Payload Length 3Bype + timestamp 4Byte + streateID 3Byte。

找到的FLV视频数据在data.bin的位置,剩下的事情似乎和普通的Content-Type: vedio/x-flv一样了。事实却不是这样的。原因有二:的确在普通的Content-Type: vedio/x-flv,只要将HTTP包中的内容顺次取出即可,但是RTMP有个机制叫做:有效数据内容长度Chunk Size,需要切包,每块最大也就Chunk Size,后续内容再加Chunk头域(一般是1字节长的头域),后面再跟未完的部分,直至最后结束。所以在从data.bin中提取视频数据时,需要将多加的头域字节剔除。

至此,CBS通过RTMP发布的视频,就被我拿到并还原了。






































猜你喜欢

转载自a-10jqka-2010.iteye.com/blog/694970
今日推荐