如何使用cv2.VideoWriter输出x265压缩视频 [英] How to output x265 compressed video with cv2.VideoWriter

查看:285
本文介绍了如何使用cv2.VideoWriter输出x265压缩视频的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在对45分钟的1.2GB视频进行一些渲染,每个视频80,0000帧,大小为1344x756,视频为mp4格式,我正在尝试输出x265压缩的视频,问题是当我我正在使用cv2.VideoWriter,视频10分钟的输出大小超过2GB,这不是我想要的最终结果,因此我在mac osx和ubuntu 18上尝试了以下操作:

I'm doing some rendering on a 45-min 1.2GB video 80,0000 frames of size 1344x756 each and the video is in the mp4 format, I'm trying to output a video with x265 compression the problem is when I'm using cv2.VideoWriter the output size for 10 minutes of the video exceeds 2GB which is not what I'm intending to end up with so I tried the following on mac osx and ubuntu 18:

codec = cv2.VideoWriter_fourcc(*'HEVC')
out = cv2.VideoWriter('output.mp4', 'HEVC', fps, (width, height))

我得到的只是运行时警告:

All I'm getting is runtime warnings:

OpenCV: FFMPEG: tag 0x43564548/'HEVC' is not found (format 'mp4 / MP4 (MPEG-4 Part 14)')'

我想要实现的不一定是最高质量的输出,而应该是高质量和最小的尺寸.

What I'm trying to achieve is not necessarily the highest quality output but should be a good quality and the lowest size possible.

推荐答案

据我所知,OpenCV VideoWriter 还不支持HEVC编码.

As far as I know, OpenCV VideoWriter has no support for HEVC encoding (yet).

我建议您使用 FFmpeg 作为子过程,然后将渲染的帧插入到 stdin中 ffmpeg 的输入流.

I recommend you using FFmpeg as sub-process, and PIPE the rendered frames to stdin input stream of ffmpeg.

您可以对 ffmpeg 使用Python绑定,例如 ffmpeg-python ,或使用Python 子进程执行 ffmpeg .

You may use Python binding for ffmpeg like ffmpeg-python, or execute ffmpeg using Python subprocess.

使用 ffmpeg ,与 cv2.VideoWriter ( cv2.VideoWriter 相比,您可以更轻松地控制视频编码参数广泛的灵活性).

Using ffmpeg, you have much more control over video encoding parameters compared to cv2.VideoWriter (cv2.VideoWriter is designed for simplicity on expanse of flexibility).

这是一个示例代码,可渲染50帧,将帧流转换为 ffmpeg ,该代码使用HEVC视频编解码器对MP4视频文件进行编码:

Here is a sample code that renders 50 frames, stream frames to ffmpeg that encodes MP4 video file with HEVC video codec:

import cv2
import numpy as np
import subprocess as sp
import shlex

width, height, n_frames, fps = 1344, 756, 50, 25  # 50 frames, resolution 1344x756, and 25 fps

output_filename = 'output.mp4'

# Open ffmpeg application as sub-process
# FFmpeg input PIPE: RAW images in BGR color format
# FFmpeg output MP4 file encoded with HEVC codec.
# Arguments list:
# -y                   Overwrite output file without asking
# -s {width}x{height}  Input resolution width x height (1344x756)
# -pixel_format bgr24  Input frame color format is BGR with 8 bits per color component
# -f rawvideo          Input format: raw video
# -r {fps}             Frame rate: fps (25fps)
# -i pipe:             ffmpeg input is a PIPE
# -vcodec libx265      Video codec: H.265 (HEVC)
# -pix_fmt yuv420p     Output video color space YUV420 (saving space compared to YUV444)
# -crf 24              Constant quality encoding (lower value for higher quality and larger output file).
# {output_filename}    Output file name: output_filename (output.mp4)
process = sp.Popen(shlex.split(f'ffmpeg -y -s {width}x{height} -pixel_format bgr24 -f rawvideo -r {fps} -i pipe: -vcodec libx265 -pix_fmt yuv420p -crf 24 {output_filename}'), stdin=sp.PIPE)

# Build synthetic video frames and write them to ffmpeg input stream.
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()

# Terminate the sub-process
process.terminate()

注意:

  • ffmpeg 可执行文件必须位于Python脚本的执行路径中.

  • ffmpeg executable must be in the execution path of the Python script.

对于Linux,如果 ffmpeg 不在执行路径中,则可以使用完整路径:

For Linux, in case ffmpeg is not in the execution path, you may use the full path:

 process = sp.Popen(shlex.split(f'/usr/bin/ffmpeg -y -s {width}x{height} -pixel_format bgr24 -f rawvideo -r {fps} -i pipe: -vcodec libx265 -pix_fmt yuv420p -crf 24 {output_filename}'), stdin=sp.PIPE)

(假设 ffmpeg 可执行文件位于/usr/bin/中).

(Assuming ffmpeg executable is in /usr/bin/).

Python 3的f-Strings 语法需要Python 3.6或更高版本.

Python 3's f-Strings syntax requires Python version 3.6 or above.

这篇关于如何使用cv2.VideoWriter输出x265压缩视频的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆