Python读取视频-硬解和软解

发布于:2025-09-13 ⋅ 阅读:(13) ⋅ 点赞:(0)

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 只是一个“壳”。

真正干活的是后端:

  1. FFMPEG:默认用 libavcodec 的纯软件解码器(h264, hevc 等)。
  2. 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. 示例 1 FFmpeg-Python(PyAV)+ CUDA 硬解
  2. 示例 2 GStreamer-Python + CUDA 硬解
# pip install av==11.0.0  (PyAV 是 FFmpeg 的 Python 绑定)

import av
import numpy as np

def 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 BGR
        img = 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 PyGObject

import cv2
import gi
gi.require_version("Gst", "1.0")
from gi.repository import Gst, GLib

Gst.init(None)

def rtsp_cuda_gst(rtsp_url: str):
    # pipeline:RTSP → NVDEC → BGR → appsink
    pipe = (
        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:
            break
        yield frame
    cap.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