如何用OpenCV逐帧处理视频并保留音频,或降低内存占用?
大视频逐帧处理并保留音频的解决方案
问题背景
用OpenCV逐帧读取大视频、处理后写入新文件的方式,能避免将整个视频加载到内存,但无法保留音频。事后用MoviePy添加音频时,因需要重新编码完整视频,速度极慢,相关代码如下:
# OpenCV逐帧处理逻辑 success, img = vidObj.read() img = processImg(img) vidWriter.write(img) # MoviePy事后添加音频的代码 def addAudio(audioSource, videoSource, savePath): source_audio = AudioFileClip(audioSource) target_video = VideoFileClip(videoSource) target_video = target_video.set_audio(source_audio) target_video.write_videofile(savePath, audio_codec='aac')
可行解决方案
1. 用PyAV实现逐帧处理视频+直接复制音频流
PyAV基于FFmpeg,支持对流式音视频进行处理,能在逐帧处理视频的同时,直接复制原视频的音频流,无需重新编码音频,既节省内存又保证速度。
示例代码:
import av def process_video_with_audio(input_path, output_path, process_func): # 打开输入视频容器 input_container = av.open(input_path) # 创建输出视频容器 output_container = av.open(output_path, 'w') # 初始化音频输出流(直接复用原音频参数) audio_out_stream = None for stream in input_container.streams: if stream.type == 'audio': audio_out_stream = output_container.add_stream(template=stream) audio_out_stream.codec_context.codec = None # 标记为直接复制 # 逐帧处理视频并写入 for stream in input_container.streams: if stream.type == 'video': video_out_stream = output_container.add_stream(template=stream) for frame in input_container.decode(stream): # 转换为OpenCV兼容的numpy数组 img = frame.to_ndarray(format='bgr24') # 执行自定义帧处理 processed_img = process_func(img) # 转回AVFrame并保留时间戳(保证音视频同步) processed_frame = av.VideoFrame.from_ndarray(processed_img, format='bgr24') processed_frame.pts = frame.pts # 编码写入输出容器 for packet in video_out_stream.encode(processed_frame): output_container.mux(packet) # 结束视频流编码 for packet in video_out_stream.encode(): output_container.mux(packet) # 复制原音频流数据包到输出容器 if audio_out_stream: for stream in input_container.streams: if stream.type == 'audio': for packet in input_container.demux(stream): packet.stream = audio_out_stream output_container.mux(packet) # 关闭容器 input_container.close() output_container.close() # 调用示例:传入自定义的processImg处理函数 process_video_with_audio('input.mp4', 'output.mp4', processImg)
2. 用FFmpeg命令行快速合并音频与处理后的视频
如果已经用OpenCV处理完无音频的视频文件,可以直接用FFmpeg命令行不重新编码视频,仅将原视频的音频复制到处理后的视频中,速度极快:
ffmpeg -i processed_video.mp4 -i original_video.mp4 -c:v copy -c:a aac -map 0:v:0 -map 1:a:0 final_output.mp4
参数说明:
-c:v copy:直接复制处理后的视频流,跳过重新编码-c:a aac:指定音频编码为AAC(若原音频编码兼容,可替换为copy进一步提速)-map 0:v:0:取第一个输入文件的视频流-map 1:a:0:取第二个输入文件的音频流
核心优势
- 两种方案都无需将整个视频加载到内存,适配大文件处理场景
- 音频流直接复制或复用原编码,彻底避免了MoviePy重新编码全视频的耗时问题
内容的提问来源于stack exchange,提问作者Frobot
相关产品推荐
相关产品推荐

