使用 Python结合ffmpeg 实现单线程和多线程推流

一、引言

在本文中,我们将详细介绍如何使用 Python 进行视频的推流操作。我们将通过两个不同的实现方式,即单线程推流和多线程推流,来展示如何利用 cv2(OpenCV)和 subprocess 等库将视频帧推送到指定的 RTMP 地址。这两种方式都涉及到从摄像头读取视频帧,以及使用 ffmpeg 命令行工具将视频帧进行编码和推流的过程。

二、单线程推流

以下是单线程推流的代码:

import cv2 as cv
import subprocess as sp


def push_stream():
    # 视频读取对象
    cap = cv.VideoCapture(0) 
    fps = int(cap.get(cv.CAP_PROP_FPS))
    w = int(cap.get(cv.CAP_PROP_FRAME_WIDTH))
    h = int(cap.get(cv.CAP_PROP_FRAME_HEIGHT))
    ret, frame = cap.read()
    # 推流地址
    rtmpUrl = "rtmp://192.168.3.33:1935/live/"
    # 推流参数
    command = ['ffmpeg',
              '-y',
              '-f', 'rawvideo',
              '-vcodec','rawvideo',
              '-pix_fmt', 'bgr24',
              '-s', "{}x{}".format(w, h),
              '-r', str(fps),
              '-i', '-',
              '-c:v', 'libx264',
              '-pix_fmt', 'yuv420p',
              '-preset', 'ultrafast',
              '-f', 'flv', 
              rtmpUrl]
    # 创建、管理子进程
    pipe = sp.Popen(command, stdin=sp.PIPE, bufsize=10 ** 8)
    # 循环读取
    while cap.isOpened():
        # 读取一帧
        ret, frame = cap.read()
        if frame is None:
            print('read frame err!')
            continue
        # 显示一帧
        cv.imshow("frame", frame)
        # 按键退出
        if cv.waitKey(1) & 0xFF == ord('q'):
            break
        # 读取尺寸、推流
        # img=cv.resize(frame,size)
        pipe.stdin.write(frame) 
    # 关闭窗口
    cv.destroyAllWindows()
    # 停止读取
    cap.release()

在这个单线程的实现中,我们执行以下步骤:

  1. 初始化视频读取对象
    • 使用 cv2.VideoCapture(0) 来打开默认的摄像头设备。
    • 获取摄像头的帧率 fps、宽度 w 和高度 h 等参数。
  2. 设置推流地址和参数
    • 定义 rtmpUrl 作为推流的目标地址。
    • 构造 ffmpeg 的命令列表 command,该列表包含了一系列的参数,如 -y 表示覆盖输出文件、-f rawvideo 表示输入格式为原始视频等。
    • 使用 sp.Popen 创建一个子进程,将 ffmpeg 命令作为子进程运行,并且将其输入管道 stdin 连接到我们的程序。
  3. 循环读取和推流
    • 在一个 while 循环中,不断读取摄像头的帧。
    • 若读取失败,打印错误信息并继续。
    • 使用 cv2.imshow 显示当前帧,同时监听 q 键,按下 q 键时退出程序。
    • 将读取到的帧通过管道发送给 ffmpeg 进行推流。

三、多线程推流

以下是多线程推流的代码:

import queue
import threading
import cv2 as cv
import subprocess as sp


class Live(object):
    def __init__(self):
        self.frame_queue = queue.Queue()
        self.command = ""
        # 自行设置
        self.rtmpUrl = ""
        self.camera_path = ""

    def read_frame(self):
        print("开启推流")
        cap = cv.VideoCapture(self.camera_path)

        # Get video information
        fps = int(cap.get(cv.CAP_PROP_FPS))
        width = int(cap.get(cv.CAP_PROP_FRAME_WIDTH))
        height = int(cap.get(cv.CAP_PROP_FRAME_HEIGHT))

        # ffmpeg command
        self.command = ['ffmpeg',
                       '-y',
                       '-f', 'rawvideo',
                       '-vcodec','rawvideo',
                       '-pix_fmt', 'bgr24',
                       '-s', "{}x{}".format(width, height),
                       '-r', str(fps),
                       '-i', '-',
                       '-c:v', 'libx264',
                       '-pix_fmt', 'yuv420p',
                       '-preset', 'ultrafast',
                       '-f', 'flv', 
                       self.rtmpUrl]

        # read webcamera
        while(cap.isOpened()):
            ret, frame = cap.read()
            if not ret:
                print("Opening camera is failed")
                break

            # put frame into queue
            self.frame_queue.put(frame)

    def push_frame(self):
        # 防止多线程时 command 未被设置
        while True:
            if len(self.command) > 0:
                # 管道配置
                p = sp.Popen(self.command, stdin=sp.PIPE)
                break

        while True:
            if self.frame_queue.empty()!= True:
                frame = self.frame_queue.get()
                # process frame
                # 你处理图片的代码
                # write to pipe
                p.stdin.write(frame.tostring())

    def run(self):
        threads = [
            threading.Thread(target=Live.read_frame, args=(self,)),
            threading.Thread(target=Live.push_frame, args=(self,))
        ]
        [thread.setDaemon(True) for thread in threads]
        [thread.start() for thread in threads]

在这个多线程的实现中,我们使用了 threadingqueue 库:

  1. 类的初始化
    • 创建一个 Live 类,在 __init__ 方法中初始化帧队列 frame_queuecommandrtmpUrlcamera_path 等变量。
  2. 读取帧的线程方法
    • read_frame 方法中,使用 cv2.VideoCapture(self.camera_path) 打开摄像头。
    • 获取摄像头的参数,并构造 ffmpeg 命令。
    • 不断从摄像头读取帧,并将帧放入队列 frame_queue 中。
  3. 推流的线程方法
    • push_frame 方法中,等待 command 被设置,然后使用 sp.Popen 启动 ffmpeg 子进程。
    • 从帧队列中取出帧,并将其写入 ffmpeg 的输入管道进行推流。
  4. 启动线程
    • run 方法创建并启动两个线程,一个用于读取帧,一个用于推流,并且将它们设置为守护线程。

四、代码解释和注意事项

单线程推流

  • 这种方式相对简单,适合初学者理解。但由于是单线程操作,在处理复杂任务时可能会导致性能瓶颈,特别是在同时进行视频显示、读取和推流的情况下,可能会出现卡顿现象。

多线程推流

  • 利用多线程可以将不同的任务分配给不同的线程,提高性能。
  • frame_queue 是一个线程安全的队列,用于在两个线程之间传递帧数据,避免了数据竞争问题。
  • setDaemon(True) 使得线程在主线程结束时自动终止,防止程序无法正常退出。

五、总结

通过上述代码和解释,我们可以看到如何使用 Python 进行单线程和多线程的视频推流操作。单线程代码简单明了,但性能可能受限;多线程代码可以更好地处理高负载,但也需要注意线程安全和资源管理等问题。在实际应用中,我们可以根据具体的需求和硬件性能来选择合适的推流方式。同时,我们可以进一步优化代码,例如添加异常处理、优化帧处理逻辑等,以提高程序的稳定性和性能。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Zero to JupyterHub with Kubernetes 下篇 - Jupyterhub on k8s

前言:纯个人记录使用。 搭建 Zero to JupyterHub with Kubernetes 上篇 - Kubernetes 离线二进制部署。搭建 Zero to JupyterHub with Kubernetes 中篇 - Kubernetes 常规使用记录。搭建 Zero to JupyterHub with Kubernetes 下篇 - Jupyterhub on k8s。 官方文档…

倾斜摄影相机在不动产确权登记和权籍调查中的应用

一、项目背景 1.1 项目背景 为贯彻落实中央、国务院关于实施乡村振兴战略、关于“扎实推进房地一体的农村集体建设用地和宅基地使用权确权登记颁证,完善农民闲置宅基地和闲置农房政策,探索宅基地所有权、资格权、使用权‘三权分置’”的要求&#xff0…

计算机网络 (22)网际协议IP

一、IP协议的基本定义 IP协议是Internet Protocol的缩写,即因特网协议。它是TCP/IP协议簇中最核心的协议,负责在网络中传送数据包,并提供寻址和路由功能。IP协议为每个连接在因特网上的主机(或路由器)分配一个唯一的IP…

网络安全测评技术与标准

18.1 概况 1)概念 :指参照一定的标准规范要求,通过一系列的技术和管理方法,获取评估对象的网络安全状况信息,对其给出相应的网络安全情况综合判定。 网络安全测评对象通常包括信息系统的组成要素或信息系统自身。 2…

5个不同类型的mysql数据库安装

各种社区版本下载官方地址:MySQL :: MySQL Community Downloads 一、在线YUM仓库(Linux) 选择 MySQL Yum Repository 选择对应版本下载仓库安装包(No thanks, just start my download.) 下载方法1:下载到本…

Lua开发环境如何安装?保姆级教程

大家好,我是袁庭新。Lua开发环境如何安装搭建?这套篇文章帮你搞定~ CentOS 7系统默认已经安装了Lua语言环境,因此可直接运行Lua代码。可以使用以下命令查看当前系统中默认自带的Lua版本。 # 查看系统默认自带的Lua版本 [rootloc…

Linux 系统搭建网络传输环境汇总

Ubuntu 系统搭建 TFTP 服务器 1. 创建 /home/username/workspace/tftp 目录并赋予最大权限,username 是自己用户名 sudo mkdir -p /home/username/workspace/tftp sudo chmod 777 /home/username/workspace/tftp 2. 安装 tftp-hpa( 客户端软件包&#x…

深度学习中CUDA环境安装教程

首先说明,本人是小白,一次安装,可能有不对的地方,望包含。 安装CUDA 因为我们是深度学习,很多时候要用到gpu进行训练,所以我们需要一种方式加快训练速度。 通俗地说,CUDA是一种协助“CPU任务分…

基于word2vec的推荐系统

基于word2vec的推荐系统 可用于推荐商品,图书,电影,课程,旅游景点,音乐… 效果 网址点我跳转 一、word2vec简介 Word2Vec是一种词向量表示方法,是在自然语言处理领域(NLP)的神经…

多目标优化算法——基于聚类的不规则Pareto前沿多目标优化自适应进化算法(CA-MOEA)

基于聚类的不规则Pareto前沿多目标优化自适应进化算法(CA-MOEA) 一、算法简介 简介: 现有的多目标进化算法(moea)在具有规则Pareto前沿且Pareto最优解在目标空间上连续分布的多目标优化问题(MOPs&#xff…

Kubernetes开发环境minikube | 开发部署apache tomcat web单节点应用

minikube是一个主要用于开发与测试Kubernetes应用的运行环境 本文主要描述在minikube运行环境中部署J2EE tomcat web应用 minikube start --force minikube status 如上所示,在Linux中启动minikube运行环境 service docker start docker version service docker …

【QT-QTableView实现鼠标悬浮(hover)行高亮显示+并设置表格样式】

1、自定义委托类 HoverDelegate hoverdelegate.h #ifndef HOVERDELEGATE_H #define HOVERDELEGATE_H#include <QObject> #include <QStyledItemDelegate>class hoverdelegate : public QStyledItemDelegate {Q_OBJECT // 添加 Q_OBJECT 宏public:explicit hoverde…

企业网络性能监控

什么是网络性能监控 网络性能监控&#xff08;NPM&#xff09;是指对计算机网络的性能进行持续测量、分析和管理的过程&#xff0c;通过监控流量、延迟、数据包丢失、带宽利用率和正常运行时间等关键指标&#xff0c;确保网络高效、安全地运行&#xff0c;并将停机时间降至最低…

引领AI发展潮流:打造大模型时代的安全与可信——CCF-CV企业交流会走进合合信息会议回顾

一、前言 随着数字化浪潮的推动&#xff0c;人工智能技术正在以前所未有的速度深刻改变着我们的生活、工作方式以及社会结构。AI技术的飞速发展不仅为各行业带来了前所未有的机遇&#xff0c;也同时引发了关于其风险与挑战的广泛关注。如何平衡技术进步与安全保障&#xff0c;…

List ---- 模拟实现LIST功能的发现

目录 listlist概念 list 中的迭代器list迭代器知识const迭代器写法list访问自定义类型 附录代码 list list概念 list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。list的底层是双向链表结构&#xff0c;双向链表中每个元素…

Matlab回归预测大合集(不定期更新)-188

截至2025-1-2更新 1.BP神经网络多元回归预测&#xff08;多输入单输出&#xff09; 2.RBF神经网络多元回归预测&#xff08;多输入单输出&#xff09; 3.RF随机森林多元回归预测&#xff08;多输入单输出&#xff09; 4.CNN卷积神经网络多元回归预测&#xff08;多输入单输…

go语言zero框架中教务crm系统的在职继承和离职交接的设计与实践

在GoZero中实现一个在职继承和离职交接的通用模块&#xff0c;涉及到顾问离职交接客户、领导离职交接审批单据等功能。为了使这个模块通用且易于扩展&#xff0c;我们可以分成几个部分&#xff1a; 1. **数据模型设计**&#xff1a;我们首先需要设计离职交接相关的数据模型。 …

Mac软件介绍之录屏软件Filmage Screen

软件介绍 Filmage Screen 是一款专业的视频录制和编辑软件&#xff0c;适用于 Mac 系统 可以选择4k 60fps&#xff0c;可以选择录制电脑屏幕&#xff0c;摄像头录制&#xff0c;可以选择区域录制。同时也支持&#xff0c;简单的视频剪辑。 可以同时录制电脑麦克风声音 标准…

毕业项目推荐:基于yolov8/yolov5的行人检测识别系统(python+卷积神经网络)

文章目录 概要一、整体资源介绍技术要点功能展示&#xff1a;功能1 支持单张图片识别功能2 支持遍历文件夹识别功能3 支持识别视频文件功能4 支持摄像头识别功能5 支持结果文件导出&#xff08;xls格式&#xff09;功能6 支持切换检测到的目标查看 二、数据集三、算法介绍1. YO…

对话|企业如何构建更完善的容器供应链安全防护体系

对话&#xff5c;企业如何构建更完善的容器供应链安全防护体系 云布道师 随着云计算和 DevOps 的兴起&#xff0c;容器技术和自动化成为软件开发中的必要手段&#xff0c;软件供应链也进入了自动化及 CI/CD 阶段。然而&#xff0c;容器技术和自动化虽然提升了软件的更新速度&…