我用cv2
编辑图像,并用FFMPEG从帧中创建视频.有关更多详细信息,请参阅本文.
图像是3D RGB NumPy array
(形状类似[h,w,3]),它们存储在Python list
中.
是的,我知道cv2
有一个VideoWriter
,我以前也用过,但它不足以满足我的需要.
简单地说,它只能使用随附的FFMPEG
版本,该版本不支持CUDA,在生成视频时会占用所有CPU时间,而根本不使用任何GPU时间,输出太大,我无法将许多FFMPEG参数传递给VideoWrite
初始化.
我下载了FFMPEG for Windows的预编译二进制文件,支持CUDA here,我使用的是Windows 10 21H1 x64,我的GPU是NVIDIA Geforce GTX 1050 Ti.
无论如何,我需要处理找到的所有参数here和there,以找到质量和压缩之间的最佳折衷,如下所示:
command = '{} -y -stream_loop {} -framerate {} -hwaccel cuda -hwaccel_output_format cuda -i {}/{}_%d.png -c:v hevc_nvenc -preset 18 -tune 1 -rc vbr -cq {} -multipass 2 -b:v {} -vf scale={}:{} {}'
os.system(command.format(FFMPEG, loops-1, fps, tmp_folder, file_name, quality, bitrate, frame_width, frame_height, outfile))
我需要准确地使用我下载的二进制文件,并指定尽可能多的参数,以实现最佳结果.
目前,我只能将数组作为图像保存到磁盘,并将图像用作FFMPEG的输入,这很慢,但我需要的正是二进制和所有这些参数.
经过数小时的谷歌搜索,我找到了ffmpeg-python
,这似乎很适合这项工作,我甚至找到了this :我可以将二进制路径作为参数传递给run
函数this
import ffmpeg
import io
def vidwrite(fn, images, framerate=60, vcodec='libx264'):
if not isinstance(images, np.ndarray):
images = np.asarray(images)
_,height,width,channels = images.shape
process = (
ffmpeg
.input('pipe:', format='rawvideo', pix_fmt='rgb24', s='{}x{}'.format(width, height), r=framerate)
.output(fn, pix_fmt='yuv420p', vcodec=vcodec, r=framerate)
.overwrite_output()
.run_async(pipe_stdin=True, overwrite_output=True, pipe_stderr=True)
)
for frame in images:
try:
process.stdin.write(
frame.astype(np.uint8).tobytes()
)
except Exception as e: # should probably be an exception related to process.stdin.write
for line in io.TextIOWrapper(process.stderr, encoding="utf-8"): # I didn't know how to get the stderr from the process, but this worked for me
print(line) # <-- print all the lines in the processes stderr after it has errored
process.stdin.close()
process.wait()
return # cant run anymore so end the for loop and the function execution
但是,我需要将所有这些参数以及可能更多的参数传递给流程,我不确定这些参数应该传递到哪里(stream_loop
应该传递到哪里?hwaccel
、hwaccel_output_format
、multipass
……?).
我如何正确地将一堆NumPy数组传输到由支持CUDA的二进制文件生成的FFMPEG进程,并将各种参数传递给该进程的初始化?