Python与FFmpeg

Python并没有关于视频、音频的原生库,因此读取也好、写入也好都要借助第三方库。业内最好的第三方库可能就是FFmpeg了。要在Python中使用ffmpeg,可以使用PyFFmpeg等绑定库。但是对于简单的读写需求来说,这样的绑定库显得太过臃肿,因此我们可以使用FFmpeg的command line来执行我们简单的读写需求,用Pipe控制FFmpeg的输入输出即可。本人写的一个拙作在此
Gitee 仓库—> https://gitee.com/huzheyang/pyffpipe

用FFmpeg切割音频文件,请移步另一篇文章
对应的Github 仓库—> https://github.com/jsjyhzy/cuecut

读取帧

ffmpeg.exe -i filepath -f image2pipe -pix_fmt rgb24 -vcodec rawvideo -

命令行:

其中-i指示了输入的视频文件,-f指示了输出格式(要用pipe的话,这一项不能改),-pix_fmt指示了输出的色彩制式(这里使用rgb24,方便Pillow模块),-vcodec指示了视频编码格式(为了得到可直接导入Pillow的数据,使用了rawvideo),“-”指示了pipe(不可忽略)
接下来只需要用过subprocess模块调用这个命令行,将输入流定义为pipe即可:

import subprocess as sp 
pipe = sp.Popen(command, stdout=sp.PIPE, stderr=sp.STDOUT, bufsize=bytes_per_frame) 
img_bytes = pipe.stdout.read(bytes_per_frame)

有必要的话可以将read过程包装成generator方便使用。

写入帧

命令行:

ffmpeg.exe -y -f rawvideo -vcodec rawvideo -s size -pix_fmt rgb24 \ -r frame_rate -i - -an -vcodec mpeg4 filepath

其中-y指示若存在文件则覆盖(可选),-f、-vcodec、-pix_fmt同上,-s指示每一帧的尺寸大小(格式为:宽x高),-r指示帧率,“-i -”指示从pipe输入,-an指示没有音轨。
Python代码:

pipe = sp.Popen(command, stdin=sp.PIPE, stderr=sp.STDOUT, bufsize=bytes_per_frame) 
pipe.stdin.write(img_bytes)

注意点

观察到ffmpeg在写入帧时默认会输出信息条,例如帧率,速度等信息。输出的信息是以\r结尾,达到覆盖输出的效果,但如果要把stderr也用pipe连接,则会导致read读不到\n或EOF,发生阻塞。虽然可以通过设置subprocess中universal_newlines=True,但这会导致该线程所有pipe都是以文本方式打开。因此要么不要用pipe连接stderr,要么设置ffmpeg不回显信息。

加入对话

1条评论

留下评论