Python implementation FLV video splicing

Thesis

This article briefly describes the format of FLV files, as a starting point, use Python to achieve FLV video of stitching .

A .FLV file format

Online analytical about FLV file format has many articles, where you need to know about the brief section for readers to better understand the function of each section of the code.

FLV file is a file header (Header) and a file body (Body) sequentially splicing. Reviewing FLV content to read the binary content.

Header: shows the encapsulation header format for FLV, object store audio, video or both.
The following is the Header FLV file, a total of nine bytes:

b'FLV\x01\x05\x00\x00\x00\t'
前 3 个字节(FLV)说明这是一个FLV文件
第 4 个字节(\x01)为版本号,固定为 1 
第 5 个字节(\x05)表明存储对象,需将其转化成二进制(00000101)查看,左、右边的 1 分别表示文件含有音频和视频
后 4 个字节(\x00\x00\x00\t)表示文件头的长度,其值固定为 9

Body: Tag file is composed of several compositions, in addition to the first, each of the Tag is (variable length) by a head (11 bytes), and a tail body (4 bytes). The first Tag only the tail.
Tag is divided into three categories, scripts (scripts), audio (audio) and video (video). Usually the first two Tag script type, and only one, the follow-up of all types of audio and video.
The following is the script Tag part, as an example tell us about:

头部:b'\x12\x00\tb\x00\x00\x00\x00\x00\x00\x00'
第 1 个字节(\x12)表示 Tag 类型,脚本类型的对应值为 18 ,音频为 8 ,视频为 9 
第 2-4 个字节(\x00\tb)表示 Tag 主体的长度,此处为 2402
第 5-7 个字节(\x00\x00\x00)为时间戳,脚本类型的时间戳通常为 0 
第 8 个字节(\x00)是时间戳的扩展,当前 3 个字节不够用时会用这个字节当作大端
后 3 个字节(\x00\x00\x00)是 Stream id,固定为 0

主体:脚本 Tag 的主体包含FLV视频的基本信息,如时长、大小、分辨率等,比较复杂,在此不作介绍

尾部:b'\x00\x00\tm'
固定 4 字节,表示 Tag 头部加主体的长度,即 11 + 2402 = 2413

Two .FLV video splicing

Multiple FLV videos into one video plays correctly, it is enough to meet most needs. Therefore, in the next splicing process, not adjusted for FLV nuanced, can meet the basic requirements.

Reader settings

Reader allows us to easily read the contents of the file.

class Reader():
    def __init__(self, content): # content (bytes):FLV文件的二进制内容
        self.content = content
        self.start = 0
        self.eof = False # 判断是否已读完全部内容
        self.length = len(self.content)
        
    def read(self, n=1):
        # 设置 if 语句防止过度读取内容
        if self.length > (self.start + n):
            out = self.content[self.start:self.start + n]
            self.start += n
        else:
            out = self.content[self.start:]
            self.eof = True
        return out

Header Tag to write and create a new FLV file

It is assumed here to be spliced ​​video information substantially similar, i.e. contain audio and video, resolution, bit rate and so the same or similar.

To generate a FLV video playback can be normal, Header and Tag is essential. We can choose a file at the head of a new FLV FLV written in, followed by the modified time stamp Tag written to, you can achieve the purpose of splicing.

def add_flv(flv, target, videoTimeStamp, audioTimeStamp): # 修改并添加 Tag 的函数
    with open(flv, 'rb') as f:
        content = f.read()
    reader = Reader(content)
    
    header = reader.read(13)

    with open(target, 'ab') as f:
        while not reader.eof: # 一直读取直到读完,此时 reader.eof = True
            dataType = reader.read(1)
            dataSize = reader.read(3)
            timeStamp = int.from_bytes(reader.read(3), 'big') # 将 3 字节转换成整数
            headerRemained = reader.read(4)

            if dataType == b'\t': # 视频
                timeStamp += videoTimeStamp
                videoTS = timeStamp
            if dataType == b'\x08': # 音频
                timeStamp += audioTimeStamp
                audioTS = timeStamp
            timeStamp = timeStamp.to_bytes(3, 'big') # 将整数转换成 3 字节

            tagHeader = dataType + dataSize + timeStamp + headerRemained
            tagData_andSize = reader.read(int.from_bytes(dataSize, 'big') + 4)

            f.write(tagHeader)
            f.write(tagData_andSize)
    
    return videoTS, audioTS
        
    
def merge_flv(flvs, target): # 主函数
    videoTS = 0
    audioTS = 0
    for i, flv in enumerate(flvs):
        with open(flv, 'rb') as f:
            content = f.read()
        reader = Reader(content)
        
        header = reader.read(13) # flvHeader + tagSize0
        if i == 0: # 写入第 1 个FLV视频的文件头
            with open(target, 'wb') as f:
                f.write(header)
                
        videoTS, audioTS = add_flv(flv, target, videoTS, audioTS)

splice

import time

since = time.time()

flvs = ['m1.flv', 'm2.flv', 'm3.flv', 'm4.flv'] # 视频大小:45MB,20MB,59MB,54MB
target = 't.flv'
merge_flv(flvs, target)

end = time.time()
print('Merging flvs takes {:.2f} s'.format(end - since))

# Merging flvs takes 0.88 s

Can be seen, a total of 178MB video splicing 4 when 0.88 seconds.

to sum up

FLV file format is quite simple, the requirements of the data is relatively relaxed, even without adjustment of parameters Scripts in the video after the stitching is still able to play correctly.
However, spliced video is a lot of hidden problems, such as the end of the video may appear Pictures of sync (about 0.5 seconds) phenomenon, and can not be easily separated from the complete video and audio.

Published an original article · won praise 0 · Views 23

Guess you like

Origin blog.csdn.net/Okery/article/details/104054228