python rtsp 硬件解码 二

news2024/12/24 8:54:34

上次使用了python的opencv模块
述说了使用PyNvCodec 模块,这个模块本身并没有rtsp的读写,那么读写rtsp是可以使用很多方法的,我们为了输出到pytorch直接使用AI程序,简化rtsp 输入,可以直接使用ffmpeg的子进程

方法一

使用pyav,这个下次再讲

方法二

使用pipe方式,也就是我们使用任何一种方式都可以,如果我们有ffmpeg,那么直接使用ffmpeg来读取流也是可行的,使用live555 去读取流也是可行的,只要把流取过来pipe给python程序就行,把ffmpeg的可执行放到py文件的同一文件夹,如下图所示

在这里插入图片描述

我们为了使用硬件解码,安装了nvidia本身的PyNvCodec模块
首先我们要判决本身系统是否安装有cuda,

if os.name == "nt":
    # Add CUDA_PATH env variable
    cuda_path = os.environ["CUDA_PATH"]
    if cuda_path:
        os.add_dll_directory(cuda_path)
    else:
        print("CUDA_PATH environment variable is not set.", file=sys.stderr)
        print("Can't set CUDA DLLs search path.", file=sys.stderr)
        exit(1)

    # Add PATH as well for minor CUDA releases
    sys_path = os.environ["PATH"]
    if sys_path:
        paths = sys_path.split(";")
        for path in paths:
            if os.path.isdir(path):
                os.add_dll_directory(path)
    else:
        print("PATH environment variable is not set.", file=sys.stderr)
        exit(1)

使用ffmpeg来探测

我们可以使用ffprobe来探测我们的rtsp流,用来知道流的格式,是h264,还是h265,ok,我们使用process来启动子进程来探测

def get_stream_params(url: str) -> Dict:
    cmd = [
        "ffprobe",
        "-v",
        "quiet",
        "-print_format",
        "json",
        "-show_format",
        "-show_streams",
        url,
    ]
    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
    stdout = proc.communicate()[0]

    bio = BytesIO(stdout)
    json_out = json.load(bio)

    params = {}
    if not "streams" in json_out:
        return {}

    for stream in json_out["streams"]:
        if stream["codec_type"] == "video":
            params["width"] = stream["width"]
            params["height"] = stream["height"]
            params["framerate"] = float(eval(stream["avg_frame_rate"]))

            codec_name = stream["codec_name"]
            is_h264 = True if codec_name == "h264" else False
            is_hevc = True if codec_name == "hevc" else False
            if not is_h264 and not is_hevc:
                raise ValueError(
                    "Unsupported codec: "
                    + codec_name
                    + ". Only H.264 and HEVC are supported in this sample."
                )
            else:
                params["codec"] = (
                    nvc.CudaVideoCodec.H264 if is_h264 else nvc.CudaVideoCodec.HEVC
                )

                pix_fmt = stream["pix_fmt"]
                is_yuv420 = pix_fmt == "yuv420p"
                is_yuv444 = pix_fmt == "yuv444p"

                # YUVJ420P and YUVJ444P are deprecated but still wide spread, so handle
                # them as well. They also indicate JPEG color range.
                is_yuvj420 = pix_fmt == "yuvj420p"
                is_yuvj444 = pix_fmt == "yuvj444p"

                if is_yuvj420:
                    is_yuv420 = True
                    params["color_range"] = nvc.ColorRange.JPEG
                if is_yuvj444:
                    is_yuv444 = True
                    params["color_range"] = nvc.ColorRange.JPEG

                if not is_yuv420 and not is_yuv444:
                    raise ValueError(
                        "Unsupported pixel format: "
                        + pix_fmt
                        + ". Only YUV420 and YUV444 are supported in this sample."
                    )
                else:
                    params["format"] = (
                        nvc.PixelFormat.NV12 if is_yuv420 else nvc.PixelFormat.YUV444
                    )

                # Color range default option. We may have set when parsing
                # pixel format, so check first.
                if "color_range" not in params:
                    params["color_range"] = nvc.ColorRange.MPEG
                # Check actual value.
                if "color_range" in stream:
                    color_range = stream["color_range"]
                    if color_range == "pc" or color_range == "jpeg":
                        params["color_range"] = nvc.ColorRange.JPEG

                # Color space default option:
                params["color_space"] = nvc.ColorSpace.BT_601
                # Check actual value.
                if "color_space" in stream:
                    color_space = stream["color_space"]
                    if color_space == "bt709":
                        params["color_space"] = nvc.ColorSpace.BT_709

                return params
    return {}

rtsp client

写一个rtsp client,实际上使用了ffmpeg的子进程,并且使用管道来获取数据,然后使用PyCodec来解码


def rtsp_client(url: str, name: str, gpu_id: int, length_seconds: int) -> None:
    # Get stream parameters
    params = get_stream_params(url)

    if not len(params):
        raise ValueError("Can not get " + url + " streams params")

    w = params["width"]
    h = params["height"]
    f = params["format"]
    c = params["codec"]
    g = gpu_id

    # Prepare ffmpeg arguments
    if nvc.CudaVideoCodec.H264 == c:
        codec_name = "h264"
    elif nvc.CudaVideoCodec.HEVC == c:
        codec_name = "hevc"
    bsf_name = codec_name + "_mp4toannexb,dump_extra=all"

    cmd = [
        "ffmpeg",
        "-hide_banner",
        "-i",
        url,
        "-c:v",
        "copy",
        "-bsf:v",
        bsf_name,
        "-f",
        codec_name,
        "pipe:1",
    ]
    # Run ffmpeg in subprocess and redirect it's output to pipe
    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)

    # Create HW decoder class
    nvdec = nvc.PyNvDecoder(w, h, f, c, g)

    # Amount of bytes we read from pipe first time.
    read_size = 4096
    # Total bytes read and total frames decded to get average data rate
    rt = 0
    fd = 0

    # Main decoding loop, will not flush intentionally because don't know the
    # amount of frames available via RTSP.
    t0 = time.time()
    print("running stream")
    while True:
        if (time.time() - t0) > length_seconds:
            print(f"Listend for {length_seconds}seconds")
            break
        # Pipe read underflow protection
        if not read_size:
            read_size = int(rt / fd)
            # Counter overflow protection
            rt = read_size
            fd = 1

        # Read data.
        # Amount doesn't really matter, will be updated later on during decode.
        bits = proc.stdout.read(read_size)
        if not len(bits):
            print("Can't read data from pipe")
            break
        else:
            rt += len(bits)

        # Decode
        enc_packet = np.frombuffer(buffer=bits, dtype=np.uint8)
        pkt_data = nvc.PacketData()
        try:
            surf = nvdec.DecodeSurfaceFromPacket(enc_packet, pkt_data)

            if not surf.Empty():
                fd += 1
                # Shifts towards underflow to avoid increasing vRAM consumption.
                if pkt_data.bsl < read_size:
                    read_size = pkt_data.bsl
                # Print process ID every second or so.
                fps = int(params["framerate"])
                if not fd % fps:
                    print(name)

        # Handle HW exceptions in simplest possible way by decoder respawn
        except nvc.HwResetException:
            nvdec = nvc.PyNvDecoder(w, h, f, c, g)
            continue

主流程

if __name__ == "__main__":
    gpuID = 0 
    urls = []
    urls.append('rtsp://172.28.176.1/a.264')
    pool = []
    for url in urls:
        client = Process(
            target=rtsp_client,
            args=(url, str(uuid.uuid4()), gpuID, 9),
        )
        client.start()
        pool.append(client)

    for client in pool:
        client.join()

我们的时间为9秒,到了9秒退出程序
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/904967.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

申请部署阿里云SSL免费证书

使用宝塔自动创建的证书有时候会报NET::ERR_CERT_COMMON_NAME_INVALID&#xff0c;并且每次只能三个月&#xff0c;需要点击续期非常麻烦&#xff0c;容易遗忘。 阿里云免费SSL证书 前往阿里云管理控制台【数字证书管理服务】【SSL证书】&#xff0c;每年20个额度&#xff0c;一…

FPGA原理与结构——时钟资源

一、时钟概述 1、时钟 时钟&#xff0c;即clock信号&#xff0c;是由晶体经过激发产生的振荡电路。模拟端通过各种技术&#xff08;PLL,DPLL&#xff09;产生规律、周期性变化的信号给数字端&#xff0c;数字端使用该信号的边沿进行过赋值&#xff08;procedural assignment&a…

在vue3中创建多重布局的方法

在vue3中创建多重布局的方法 在本文中&#xff0c;会通过demo演示来讲解几个用于创建多重布局的方式。 demo需求&#xff1a;创建一个带有主页、营销页面和应用程序页面的 Web 应用程序 1. 导入Layouts作为常规组件来创建布局系 这是创建布局最简单的方法&#xff0c;但灵活…

ROS-2.ros工具简单认识

ROS命令工具 ros提供了丰富的命令行工具 命令作用rostopic主题相关工具rosservicerosnode节点相关工具rosparam参数相关工具rosmsg消息相关工具rossrv$1 运行小海龟 开启一个终端&#xff0c;启动ros master roscore开启一个终端&#xff0c;启动小海龟仿真器 rosrun tur…

图床项目进度(一)——UI首页

1. 前言 前面我不是说了要做一个图床吗&#xff0c;现在在做ui。 我vue水平不够高&#xff0c;大部分参考b站项目照猫画虎。 vue实战后台 我使用ts&#xff0c;vite&#xff0c;vue3进行了重构。 当然&#xff0c;我对这些理解并不深刻&#xff0c;许多代码都是游离于表面&am…

k8s之Pod及Probe 探针机制(健康检查机制)

文章目录 1、Pod1.1、定义1.2、Pod的形式1.2、Pod的使用1.3、 Pod生命周期1.4、生命周期钩子1.5、临时容器1.5.1、定义1.5.2、使用临时容器的步骤 1.6、静态Pod 2、Probe 探针机制&#xff08;健康检查机制&#xff09;2.1、探针分类2.2、Probe配置项2.3、编写yaml测试探针机制…

初阶c语言:实战项目三子棋

前言 大家已经和博主学习有一段时间了&#xff0c;今天讲一个有趣的实战项目——三子棋 目录 前言 制作菜单 构建游戏选择框架 实现游戏功能 模块化编程 初始化棋盘 打印棋盘 玩家下棋 电脑下棋 时间戳&#xff1a;推荐一篇 C语言生成随机数的方法_c语言随机数_杯浅…

成为创作者的第512天——创作纪念日

​ &#x1f4da;文章目录 &#x1f4e8;官方致信 &#x1f3af;我的第一篇文章 &#x1f9e9;机缘 &#x1f9e9;收获 &#x1f9e9;成就 &#x1f9e9;憧憬与目标 &#x1f4e8;官方致信 ​ &#x1f3af;我的第一篇文章 2022 年 03 月 26 日&#xff0c;那一天我在C…

【网络安全】防火墙知识点全面图解(一)

防火墙知识点全面图解&#xff08;一&#xff09; 1、什么是防火墙&#xff1f; 防火墙&#xff08;Firewall&#xff09;是防止火灾发生时&#xff0c;火势烧到其它区域&#xff0c;使用由防火材料砌的墙。 后来这个词语引入到了网络中&#xff0c;把从外向内的网络入侵行为看…

nodejs使用PassThrough流进行数据传递合并

在Node.js中&#xff0c;流&#xff08;stream&#xff09;是处理数据的强大工具&#xff0c;它们允许我们以流式方式处理大量数据&#xff0c;而不必一次性将所有数据加载到内存中。PassThrough是Node.js中的一个流类型&#xff0c;它在数据流传递过程中起到 无操作 的中间层&…

LeetCode 周赛上分之旅 #41 结合离散化的线性 DP 问题

⭐️ 本文已收录到 AndroidFamily&#xff0c;技术和职场问题&#xff0c;请关注公众号 [彭旭锐] 和 BaguTree Pro 知识星球提问。 学习数据结构与算法的关键在于掌握问题背后的算法思维框架&#xff0c;你的思考越抽象&#xff0c;它能覆盖的问题域就越广&#xff0c;理解难度…

设计模式——里氏替换原则

文章目录 里氏替换原则OO 中的继承性的思考和说明基本介绍一个程序引出的问题和思考解决方法 里氏替换原则 OO 中的继承性的思考和说明 继承包含这样一层含义&#xff1a;父类中凡是已经实现好的方法&#xff0c;实际上是在设定规范和契约&#xff0c;虽然它不强制要求所有的…

Web会话技术

会话:用户打开浏览器&#xff0c;访问web服务器的资源&#xff0c;会话建立&#xff0c;直到有一方断开连接&#xff0c;会话结束。在一次会话中可以包含多次请求和响应 会话跟踪:一种维护浏览器状态的方法&#xff0c;服务器需要识别多次请求是否来自于同一浏览器&#xff0c;…

线性代数的学习和整理6:向量和矩阵详细,什么是矩阵?(草稿-----未完成)

43 矩阵 4.1 矩阵 4 整理网上总结一些 关于直击线性代数本质的 观点 矩阵的本质是旋转和缩放 矩阵里的数字0矩阵里的数字1&#xff0c;表示不进行缩放矩阵里的数字2等&#xff0c;表示缩放矩阵里的数字-3 表示缩放-3倍&#xff0c;并且反向矩阵里的数字的位置矩阵拆分为列向量…

学C的第三十四天【程序环境和预处理】

相关代码gitee自取&#xff1a; C语言学习日记: 加油努力 (gitee.com) 接上期&#xff1a; 学C的第三十三天【C语言文件操作】_高高的胖子的博客-CSDN博客 1 . 程序的翻译环境和执行环境 在ANSI C(C语言标准)的任何一种实现中&#xff0c;存在两个不同的环境。 &#xff0…

Baumer工业相机堡盟工业相机如何通过BGAPISDK设置相机的Bufferlist序列(C++)

Baumer工业相机堡盟工业相机如何通过BGAPISDK设置相机的Bufferlist序列&#xff08;C&#xff09; Baumer工业相机Baumer工业相机的Bufferlist序列功能的技术背景CameraExplorer如何查看相机Bufferlist功能在BGAPI SDK里通过函数设置相机Bufferlist参数 Baumer工业相机通过BGAP…

第9步---MySQL的索引和存储引擎

第9步---MySQL的索引和存储引擎 1.索引 1.1分类 索引可以快速的找出具有特定值的行。不用从头开始进行寻找了。 类别 hash和btree hash 根据字段值生生成一个hash的值 快速的进行定位到对应的行的值 可能会出现相同的值&#xff0c;找到对应的空间会出现对应的值 btree树…

深度学习|自监督学习、MAE学习策略、消融实验

前言&#xff1a;最近在阅读论文&#xff0c;发现太多机器学习的知识不懂&#xff0c;把最近看的一篇论文有关的知识点汇总了一下。 自监督学习、MAE学习策略、消融实验 自监督学习MAE学习策略消融实验 自监督学习 Pretrain-Finetune&#xff08;预训练精调&#xff09;模式&…

从LeakCanary看如何判断对象被回收

前面已经了解了Service&#xff0c;Fragment&#xff0c;ViewModel对象的销毁时机&#xff0c;那么在触发销毁时机后&#xff0c;我们怎么判断这些对象有没有回收呢&#xff1f; 大家都知道在Java中有强引用&#xff0c;弱引用&#xff0c;软引用&#xff0c;虚引用四种引用方…

2、手写模拟Spring底层原理

创建BeanDefinition bean定义 设置BeanDefinition 的类信息&#xff0c;作用域信息 创建beanDefinitionMap scope为原型&#xff1a; scope为单例&#xff1a; 总结&#xff1a; 扫描ComponentScan注解上的包扫描路径&#xff0c;将Component注解修饰的类&#xff0c;生成Bea…