一个简单的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)

你可能感兴趣的:(一个简单的flv操作库)