一个简单的flv操作库

忘记从哪里找到的了.

  1. 'Utilities for working with flv files'
  2. from __future__ import with_statement
  3. import array, struct
  4. def duration(header):
  5.     'Duration of flv file'
  6.     i = header.index('duration') + len('duration')
  7.     a = array.array('d')
  8.     a.fromstring(header[i + 1:i + 9])
  9.     a.byteswap()
  10.     return a[0]
  11. def tag_value(text, tag, offset, length):
  12.     'Value of tag in text'
  13.     i = text.index(tag) + len(tag) + offset
  14.     return text[i:i + length]
  15. def decode_double(s):
  16.     'Double value from binary encoded string'
  17.     a = array.array('d')
  18.     a.fromstring(s)
  19.     a.byteswap()
  20.     return a[0]
  21.     
  22. def replace(text, tag, offset, length, new):
  23.     'Replace value of tag in text with new (which must string)'
  24.     i = text.index(tag) + len(tag)
  25.     return text[:i + offset] + new + text[i + offset + length:]
  26. def header_body(flv_path):
  27.     'Tuple (header, body) of flv file without onMetaData tag'
  28.     with open(flv_path, 'rb'as f:
  29.         header = f.read(9)
  30.         f.read(4)
  31.         f.read(1)
  32.         data_size = struct.unpack('>I''/x00' + f.read(3))[0]
  33.         f.read(7)
  34.         f.read(data_size)
  35.         body = f.read()
  36.     return header, body
  37. def flv_header(f):
  38.     'First 9 bytes from file'
  39.     return f.read(9)
  40. def skip_metadata(f):
  41.     'File position must be on previous tag size'
  42.     result = ''
  43.     f.read(4)
  44.     result += f.read(1)
  45.     size = f.read(3)
  46.     result += size
  47.     data_size = struct.unpack('>I''/x00' + size)[0]
  48.     result += f.read(7)
  49.     return result + f.read(data_size)
  50. def flv_metadata(f):
  51.     'File position must be on previous tag size'
  52.     return skip_metadata(f)
  53. def add_prev_size(tag, size):
  54.     'Replace previous tag size with size'
  55.     return struct.pack('>I', size) + tag
  56. def previous_tag_size(f):
  57.     return struct.unpack('>I', f.read(4))
  58. def tag_timestamp(tag):
  59.     'Timestamp value of in milliseconds'
  60.     return struct.unpack('>I''/x00' + tag[4:7])[0]
  61. def replace_timestamp(tag, timestamp):
  62.     'Replace timestamp in tag with new value'
  63.     packed = struct.pack('>I', timestamp)[1:]
  64.     return tag[:4] + packed + tag[7:]
  65. def simple_merge(out_path, *paths):
  66.     'Merge paths (which must be flv files) and write output to out_path'
  67.     parsed = []
  68.     files = [open(p, 'rb'for p in paths]
  69.     header = flv_header(files[0])
  70.     for f in files[1:]: flv_header(f)
  71.     metadata = [flv_metadata(f) for f in files]
  72.     total = 0
  73.     for meta in metadata:
  74.         total += duration(meta)
  75.     metadata[0] = replace(metadata[0], 'duration', 1, 8, struct.pack('>d', total))
  76.     with open(out_path, 'wb'as out:
  77.         out.write(header)
  78.         prev_size = 0
  79.         offset = 0
  80.         # uncomment next line if you want save metadata
  81.         # out.write(add_prev_size(metadata[0], prev_size))
  82.         for f in files:
  83.             prev = previous_tag_size(f)
  84.             for tag, size in tags(f):
  85.                 new_offset = tag_timestamp(tag)
  86.                 tag = replace_timestamp(tag, offset + new_offset)
  87.                 out.write(add_prev_size(tag, prev_size))
  88.                 prev_size = size
  89.                 prev = previous_tag_size(f)
  90.             offset += new_offset
  91. def tags(flv, max_tags = -1):
  92.     '''Generator yielding (tag, size) from flv stream. File position must be on
  93. tag type'''
  94.     tag_type = flv.read(1)
  95.     while tag_type and max_tags:
  96.         basic_size = flv.read(3)
  97.         data_size = struct.unpack('>I''/x00' + basic_size)[0]
  98.         buf = tag_type + basic_size
  99.         buf += flv.read(7)
  100.         buf += flv.read(data_size)
  101.         #print(flv.tell())
  102.         yield buf, data_size + 11
  103.         tag_type = flv.read(1)
  104.         max_tags -= 1
  105. import glob, os.path, re, tkFileDialog, tkMessageBox, webbrowser, sys
  106. def flv_files(directory):
  107.     ''''List of flv files in directory sorted in right order
  108. (i.e part2 is before part10)'''
  109.     lst = glob.glob(os.path.join(directory, '*.flv'))
  110.     def right_cmp(x, y):
  111.         xs = int(re.findall(r'/d+', x)[-1])
  112.         ys = int(re.findall(r'/d+', y)[-1])
  113.         return cmp(xs, ys)
  114.     lst.sort(right_cmp)
  115.     return lst
  116. if __name__ == '__main__':
  117.     directory = tkFileDialog.askdirectory()
  118.     if directory:
  119.         out_file = os.path.join(os.path.dirname(directory),
  120.                                 os.path.basename(directory) + '.flv')
  121.         lst = flv_files(directory)
  122.         if len(lst) == 0:
  123.             tkMessageBox.showerror('Error''No flv files in %s' % directory)
  124.         else:
  125.             simple_merge(out_file, *lst)
  126.             webbrowser.open(out_file)

【该资源在win7——64位系统下验证通过。win10系统试试用win7兼容方式打开】 解析flv二进制数据的小工具,tag header tag data等都分析出来了的 这个工具的主要功能是查看FLV的文件结构,帮助我们理解FLV格式。另外,如果涉及到处理flv文件的开发,这个工具对于查看处理结果非常有帮助。因此我觉得有必要写一个使用说明,希望这个工具能够给大家提供帮助。 打开后的界面如下图所示。 先说一下界面布局:左上方是FLV文件的结构树,右边是FLV文件的字节流数据;左侧结构树下面依次是结构树的信息等级选择、高速模式选择、文件分析用时及进度条等;下方是分析文件的地址显示以及文件选择按钮。下面详细介绍一下相关部分。 结构树及信息等级 FLV结构树是这个工具最重要的显示信息,用户可以直观的查看当前FLV文件的结构。FLVParse默认FLV文件结构树的形式为:File Header + Metadata Tag(1个) + Video or Audio Tags(按顺序)。 结构树的信息详细程度是按等级划分的,之所以要分等级,是为了区分显示信息的详细程度,因为不同程度的分析对于分析所用的时间影响是比较大的(主要在UI界面上),越详细的信息等级占用分析时间越长。一共有6个等级,按从简单到详细介绍如下。 only section position info —— 只有每个section的位置信息,如下图所示。其中每个section后的方括号里是位置信息(十六进制表示),每个“Pre Tag Size”后面的数字表示size的大小(十进制表示),Video&Audio Tag按照在文件中的顺序依次排序标号; file header info, metadata info —— 只有File Header + Metadata Tag的详细信息,如下图所示。其中File Header的详细结构信息会在子树中列出,并在每项后面标示该项的值;Metadata Tag类似,包含Tag Header和Tag Data两个子树,并且对应子项的详细信息也都列出; file header info, metadata info, tag position info —— 包含File Header + Metadata Tag的详细信息,Video&Audio Tags的位置信息,以及Pre Tag Size信息,如下图所示; file header info, metadata info, tag section position info —— 比上个等级多出Video&Audio Tags的Tag Header和Tag Data的位置信息,如下图所示; file header info, metadata info, tag header info —— 比上个等级多出Tag Header的详细子项信息,如下图所示; file header info, metadata info, tag info —— 比上个等级多出Tag Data的详细子项信息,如下图所示。 FLV字节流数据显示 右侧显示了FLV文件的数据,可以让用户方便地查询对应位置上的字节。每一行都以一个十六进制的位置开始,该位置为相对于文件开头的位置。每一行有十六个字节,每个字节按高4位和第4位显示2个十六进制的字符,用户可以滑动滚动条查看任意位置的字节。 当用户选中左边结构树中的某项时,右边数据会自动选中对应的数据区域(绿色),根据不同项的类型,选中的区域大小也会自动对应。 高速模式 这个选项是为了解决分析比较大的FLV文件时,用户等待时间过长的问题。 普通模式时,分析过程为阻塞模式,即主线程分析完毕后刷新界面,用户才可以继续操作。 高速模式时,为非阻塞模式,主线程分析一小部分后立即返回刷新界面,响应用户操作;另外一个线程会继续分析剩余大部分文件,直到分析完毕自动结束线程。因此高速模式时,用户会看到结构树的滚动条一直在滑动,这是因为后台分析线程在不断向结构树里添加子项。需要注意的是,当后台分析线程还没有结束,如果用户打开新的文件进行分析,有可能出现错误的分析结果。这个目前没有进行测试,我想应该是这样的。 这里需要提一下,其实真正分析文件的时间并不会特别长,即使几百兆的文件,几十秒内应该没有问题,时间主要消耗在MFC的树型控件CTreeCtrl上。为了开发效率,FLVParse使用了MFC控件,但是CTreeCtrl在结构比较复杂,子项比较多的时候,效率会出现比较大的下降。当子项超过10000的时候,再进行添加的时间大大变长,几乎到了无法忍受的程度,好在还算稳定,没有出现崩溃等现象。粗略估计,每次分析文件,花在更新UI界面上的时间要占总耗时的90%以上,而且对于越大的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值