PyAV录制视频如何定期刷盘?解决文件0KB及崩溃后有效性问题
解决PyAV录制视频时文件实时写入磁盘的问题
你的问题出在两个核心点:一是PyAV默认会缓存编码数据包与文件元信息,直到容器关闭才写入磁盘;二是中途调用encode(None)会直接终止编码上下文,导致后续编码触发错误。以下是具体修复方案:
核心修复思路
- 用容器刷盘替代终止编码:不要在
recieved_frame里调用encode(None),改用容器的flush()方法——它会把已复用的数据包强制写入磁盘,同时保留编码上下文继续工作。 - 设置关键帧间隔:给VP9编码器添加关键帧参数,确保程序崩溃后,最近关键帧之前的视频片段依然可正常播放。
修改后的代码
class Recorder: def __init__(self) -> None: recorder_instances.append(self) self.frame_count = 0 # 每100帧触发一次刷盘(可根据帧率调整,比如60fps下约1.6秒刷一次) self.flush_interval = 100 def start(self, output_file, width, height, fps): self.output_container = av.open(output_file, mode="w") self.output_stream = self.output_container.add_stream("libvpx-vp9", rate=fps) self.output_stream.width = width self.output_stream.height = height self.output_stream.options = { # 设置关键帧间隔,每2秒生成一个关键帧(fps*2) 'g': str(fps * 2), # 可选:根据需求调整编码速度/质量 'cpu-used': '4', 'crf': '30' } def recieved_frame(self, frame): for packet in self.output_stream.encode(frame): self.output_container.mux(packet) self.frame_count += 1 # 达到间隔阈值时强制刷盘 if self.frame_count % self.flush_interval == 0: self.output_container.flush() def stop(self): # 停止编码时刷出剩余数据包 for packet in self.output_stream.encode(None): self.output_container.mux(packet) # 最后一次刷盘确保所有数据写入 self.output_container.flush() self.output_container.close()
关键说明
flush()方法的作用:它会强制将容器缓存的所有数据写入磁盘,包括首次刷盘时写入文件头,这样录制过程中文件大小会实时增长,程序崩溃后已写入的部分也能正常解析播放。- 关键帧参数
g的意义:VP9默认关键帧间隔较大,设置g为fps*2意味着每2秒生成一个关键帧,即使崩溃,最多丢失最近2秒的视频,之前的内容都能通过关键帧正常播放。 - 禁止中途调用
encode(None)的原因:这个调用是向编码器发送「输入结束」的信号,编码器会输出剩余数据包并关闭编码上下文,后续再传入帧就会触发"end of file"错误,仅能在停止录制时使用。
内容的提问来源于stack exchange,提问作者Jojo71
相关产品推荐
相关产品推荐

