A replacement for cv2.videoWriter with CUDA support in Linux, which is currently not supported Instead, we use ffmpeg built with CUDA support to encode and save frames.
- NVIDIA GPU
- CUDA 11.3.r11.3
- Ubuntu 20.04.4 LTS
- Python 3.8.10
cv2cuda --device gpu --width 2000 --height 2000 --fps 45 --output output.mp4
Following the guides from NVIDIA, ffmpeg and StackOverflow:
- https://docs.nvidia.com/video-technologies/video-codec-sdk/ffmpeg-with-nvidia-gpu/#commonly-faced-issues-and-tips-to-resolve-them
- https://trac.ffmpeg.org/wiki/CompilationGuide/Ubuntu
- https://stackoverflow.com/a/55747785/3541756
an ffmpeg subprocess is used to receive Python's standard output and encode it into a video using GPU hardware acceleration. The ffmpeg command has the following structure
ffmpeg -y -r FRAMERATE -f rawvideo -pix_fmt gray -vsync 0 -extra_hw_frames 2 -s WIDTHxHEIGHT -i - -an -c:v h264_nvenc OUTPUT.mp4
-
-y -r FRAMERATE
tells ffmpeg to ignore and overwrite any existing data in the output and sets the framerate -
-f rawvideo -pix_fmt gray
tells ffmpeg that the input will be raw video (which matches what Python outputs), and the pixel format is gray (only gray is supported for now by cv2cuda) -
-vsync 0 -extra_hw_frames 2
are flags that I have read can improve the performance. But I am not sure why and maybe they dont. They could potentially be removed -
-s WIDTHxHEIGHT
tells ffmpeg what width and height to expect in the incoming frames -
-i -
tells ffmpeg to read input from the standard input (i.e. to listen to Python) -
-an
tells ffmpeg there is no audio input -
c:v h264_nvenc
tells ffmpeg to use hardware acceleration by using the NVIDIA h264_nvenc codec for encoding -
OUTPUT.mp4
(or whatever path) is the output file
This command is built and run for you when you use cv2cuda
The cv2cuda package provides a drop-in replacement for the popular cv2.VideoWriter
class called cv2cuda.VideoWriter
.
It has functionality very similar to the original cv2.VideoWriter
but uses ffmpeg behind the scenes to make use of the GPU. Thus it is a solution to the issue posed here opencv/opencv_contrib#3044
You can initialize like so:
video_writer = cv2cuda.VideoWriter(
filename = output_mp4,
apiPreference="FFMPEG",
fourcc="h264_nvenc",
fps=fps,
frameSize=frameSize,
isColor=False,
)
i.e. just like the cv2.VideoWriter
You can add frames to the video, and stop it, in a way identical to the cv2.VideoWriter
video_writer.write(frame)
video_writer.release()
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2021 NVIDIA Corporation
Built on Sun_Mar_21_19:15:46_PDT_2021
Cuda compilation tools, release 11.3, V11.3.58
Build cuda_11.3.r11.3/compiler.29745058_0
ffmpeg version n4.2.2 Copyright (c) 2000-2019 the FFmpeg developers
built with gcc 9 (Ubuntu 9.3.0-17ubuntu1~20.04)
configuration: --prefix=/usr/local/ffmpeg --pkg-config-flags=--static --enable-nonfree --enable-gpl --enable-version3 --enable-libmp3lame --enable-libvpx --enable-libopus --enable-opencl --enable-libxcb --enable-opengl --enable-nvenc --enable-vaapi --enable-vdpau --enable-ffplay --enable-ffprobe --enable-libxvid --enable-libx264 --enable-libx265 --enable-openal --enable-openssl --enable-cuda-nvcc --enable-cuvid --extra-cflags=-I/usr/local/cuda/include --extra-ldflags=-L/usr/local/cuda/lib64 --nvccflags='-gencode arch=compute_52,code=sm_52 -O2' --enable-pic
libavutil 56. 31.100 / 56. 31.100
libavcodec 58. 54.100 / 58. 54.100
libavformat 58. 29.100 / 58. 29.100
libavdevice 58. 8.100 / 58. 8.100
libavfilter 7. 57.100 / 7. 57.100
libswscale 5. 5.100 / 5. 5.100
libswresample 3. 5.100 / 3. 5.100
libpostproc 55. 5.100 / 55. 5.100