gpt4 book ai didi

python - 如何通过 CUDA 支持将 BGR NumPy 数组直接传递给 FFMPEG

转载 作者:行者123 更新时间:2023-12-04 22:47:39 25 4
gpt4 key购买 nike

我正在使用 cv2 编辑图像并使用 FFMPEG 从帧创建视频。有关更多详细信息,请参阅此帖子。
这些图像是 3D RGB NumPy array s(形状类似于 [h, w, 3]),它们存储在 Python list 中。
是的,我知道 cv2 有一个 VideoWriter 并且我以前使用过它,但这不足以满足我的需求。
简而言之,它只能使用它附带的FFMPEG版本,该版本不支持CUDA,并且在生成视频时会占用所有CPU时间,而根本不使用任何GPU时间,输出太大了我不能' t 将许多 FFMPEG 参数传递给 VideoWrite 启动。
我下载了 FFMPEG for Windows 的预编译二进制文件,支持 CUDA here,我使用的是 Windows 10 21H1 x64,我的 GPU 是 NVIDIA Geforce GTX 1050 Ti。
无论如何,我需要弄乱所有找到的参数 herethere 以找到质量和压缩之间的最佳折衷,如下所示:

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 的输入,这很慢,但我需要那个二进制文件和所有这些参数。
经过数小时的 Google 搜索后,我发现 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 应该去哪里? hwaccelhwaccel_output_formatmultipass ...?)。
如何正确地将一堆 NumPy 数组传输到由支持 CUDA 的二进制文件生成的 FFMPEG 进程,并将各种参数传递给该进程的初始化?

最佳答案

如果您已经知道 FFmpeg CLI 的语法,您可以使用我的 following answer 中的 subprocess 模块。 (语法适用于 FFmpeg CLI)。
使用 ffmpeg-python 时包裹:

  • 所有输入参数(在 -i 之前)都在 input(...) 中部分。
  • 过滤器( -vf-filter_complex )链接为 filter(...).filter(...).filter(...)
  • 输出参数(在输入文件名之后)在 output(...) 中。部分。
  • 当存在带有冒号的参数时,如 'b:v' ,我们必须使用像 **{'b:v': '0'} 这样的字典符号.
  • .overwrite_output()相当于-y .

  • 笔记:
  • hevc_nvenc应用 H.265 (HEVC) 编解码器。
    如果您更喜欢 H.264 (AVC) 编解码器,请使用 h264_nvenc (可能需要不同的参数)。
  • 输入像素格式应为 'bgr24' (不是 'rgb24' )因为 OpenCV 使用 BGR 排序。

  • 使用 CUDA 加速缩放(调整大小):
    标准 scale过滤器,使用 CPU 软件缩放。
    对于 GPU CUDA 加速扩展,我们可以使用 scale_cuda筛选。
    使用前 scale_cuda ,我们必须使用 hwupload_cuda 将帧从 CPU 内存上传到 GPU 内存筛选。
    我们还应该使用以下参数(在开头): vsync=0, hwaccel='cuda', hwaccel_output_format='cuda' .
    见: Using FFmpeg with NVIDIA GPU Hardware Acceleration .

    这是一个演示 h264_nvenc 的 Python 代码示例编码和 scale_cuda过滤器(编写编号的帧进行测试):
    import cv2
    import numpy as np
    import ffmpeg

    width, height, n_frames, fps = 640, 480, 50, 25 # 50 frames, resolution 640x480, and 25 fps
    out_width, out_height = 320, 240 # Downscale to 320x240 (for example).

    output_filename = 'output.mp4'

    # Set pix_fmt to bgr24, because OpenCV uses BGR ordering (not RGB).
    # vcodec='hevc_nvenc' - Select hevc_nvenc codec for NVIDIA GPU accelerated H.265 (HEVC) video encoding.
    # hwupload_cuda - upload the frame from CPU memory to GPU memory before using CUDA accelerated scaling filter.
    # scale_cuda - Use CUDA (GPU accelerated) scaling filter
    # Use dictionary notation due to arguments with colon.

    # Execute FFmpeg sub-process using stdin pipe as input.
    process = (
    ffmpeg
    .input('pipe:', vsync=0, hwaccel='cuda', hwaccel_output_format='cuda', format='rawvideo', pix_fmt='bgr24', s=f'{width}x{height}', r=f'{fps}')
    .filter('hwupload_cuda') # https://docs.nvidia.com/video-technologies/video-codec-sdk/ffmpeg-with-nvidia-gpu/
    .filter('scale_cuda', w=out_width, h=out_height) # CUDA accelerated scaling filter
    .filter('setsar', sar=1) # Keep the aspect ratio
    .output(output_filename, vcodec='hevc_nvenc', **{'preset:v': '18', 'tune:v': '1', 'rc:v': 'vbr', 'cq:v': '19', 'b:v': '0'}, multipass=2)
    .overwrite_output()
    .run_async(pipe_stdin=True, overwrite_output=True)
    )


    # Build synthetic video frames and write them to ffmpeg input stream (for testing):
    for i in range(n_frames):
    # Build synthetic image for testing ("render" a video frame).
    img = np.full((height, width, 3), 60, np.uint8)
    cv2.putText(img, str(i+1), (width//2-100*len(str(i+1)), height//2+100), cv2.FONT_HERSHEY_DUPLEX, 10, (255, 30, 30), 20) # Blue number

    # Write raw video frame to input stream of ffmpeg sub-process.
    process.stdin.write(img.tobytes())

    # Close and flush stdin
    process.stdin.close()

    # Wait for sub-process to finish
    process.wait()

    笔记:
    上面的代码是用 NVIDIA GeForce GTX 1650 测试的,不能保证它可以和 GTX 1050 Ti 一起工作(由于硬件限制)。

    关于python - 如何通过 CUDA 支持将 BGR NumPy 数组直接传递给 FFMPEG,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72782178/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com