Python读取视频-硬解和软解
1、软解码(Software Decoding)
软解(软件解码)指通过CPU的计算能力解码视频流,不依赖特定硬件加速模块。Python中常用OpenCV、FFmpeg等库实现,兼容性强但CPU占用较高。
2、硬解码(Hardware Decoding)
硬解(硬件解码)利用GPU或专用芯片(如NVIDIA NVENC、Intel Quick Sync)进行解码,显著降低CPU负载。需硬件支持,通常通过NVDEC、VAAPI等接口实现。
3、Python里怎么选?
OpenCV 的 cv2.VideoCapture
默认就是软解,最简单,但吃 CPU。
opencv-python
不管用 FFMPEG 还是 GStreamer,默认都是“软解”——除非你在打开 VideoCapture
时显式地给后端传递硬解参数,否则 CPU 还是会吭哧吭哧算每一帧。
4、为什么看起来有 FFMPEG / GStreamer 还是软解?
VideoCapture
只是一个“壳”。
真正干活的是后端:
- FFMPEG:默认用
libavcodec
的纯软件解码器(h264
,hevc
等)。 - GStreamer:如果不加
vaapi
,nvdec
,qsv
之类 element,也只是 CPU 软解。
OpenCV 的 FFMPEG / GStreamer 后端只是“通道”,默认走软解;想硬解就在打开 VideoCapture
时把对应参数或 pipeline 写进去,不然 CPU 还是逃不掉。但是惨痛的事实是,OpenCV预装版都是不支持这些后端的硬解码,什么连GStreamer都不支持 OpenCV的cv2.VideoCapture如何加GStreamer后端-CSDN博客),想要支持,需要自己重新编译OpenCV。
5、我有英伟达显卡,有其他的硬解方案吗?
是的,常用的硬解方案包括三种:FFmpeg+NVDEC(cuvid)、GStreamer+NVDEC(nvdec/nvdec_h264)、NVIDIA Video Processing Framework(PyNvCodec/VPF)
只大概介绍前两种,FFmpeg和GStreamer都是比较优秀的工具,需要下载他们的exe程序,然后用对应的python包,去调用他们的工具。
下面的程序仅供测试,实际还会有问题,因为这些工具往往也没有支持英伟达解码器,需要自己编译。。。。这是我踏过最长的坑,搞了很多天,但即便CPU解码,效率也比OpenCV 的 cv2.VideoCapture要快,常规推荐这些方案。
- 示例 1 FFmpeg-Python(PyAV)+ CUDA 硬解
- 示例 2 GStreamer-Python + CUDA 硬解
# pip install av==11.0.0 (PyAV 是 FFmpeg 的 Python 绑定)import av
import numpy as npdef rtsp_cuda_pyav(rtsp_url: str):# 关键:把 FFmpeg 的硬件加速参数通过 options 传进去container = av.open(rtsp_url,options={"rtsp_transport": "tcp", # 避免 UDP 丢包"hwaccel": "cuda","hwaccel_device": "0", # 第 0 张卡"c:v": "h264_cuvid", # NVDEC 解码器"fflags": "nobuffer", # 低延迟"analyzeduration": "100000",})stream = container.streams.video[0]stream.thread_type = "AUTO" # 多线程解码for frame in container.decode(stream):# 把 GPU 解码后的 CUDA frame 转成 numpy BGRimg = frame.to_ndarray(format='bgr24')yield img # 生成器,逐帧给主程序if __name__ == "__main__":url = "rtsp://user:password@ip:port/Streaming/Channels/101"for bgr in rtsp_cuda_pyav(url):# 这里随便你用 cv2.imshow / AI 推理cv2.imshow("PyAV-CUDA", bgr)if cv2.waitKey(1) == 27:break
# apt install python3-gi python3-gi-cairo gir1.2-gstreamer-1.0
# 或者 pip install PyGObjectimport cv2
import gi
gi.require_version("Gst", "1.0")
from gi.repository import Gst, GLibGst.init(None)def rtsp_cuda_gst(rtsp_url: str):# pipeline:RTSP → NVDEC → BGR → appsinkpipe = (f"rtspsrc location={rtsp_url} latency=0 ! ""rtph264depay ! h264parse ! ""nvh264dec ! " # ← CUDA 硬解"videoconvert ! ""video/x-raw,format=BGR ! ""appsink max-buffers=1 drop=true")cap = cv2.VideoCapture(pipe, cv2.CAP_GSTREAMER)if not cap.isOpened():raise RuntimeError("无法打开 GStreamer 管道")while True:ok, frame = cap.read()if not ok:breakyield framecap.release()if __name__ == "__main__":url = "rtsp://user:password@ip:port/Streaming/Channels/101"for bgr in rtsp_cuda_gst(url):cv2.imshow("GST-CUDA", bgr)if cv2.waitKey(1) == 27:break