首页 > 编程问答 >使用 FFpyplayer 帧和 QPixmap 以及 MPEG-TS 格式的 UDP 流时出现追赶延时缓冲和滞后问题

使用 FFpyplayer 帧和 QPixmap 以及 MPEG-TS 格式的 UDP 流时出现追赶延时缓冲和滞后问题

时间:2024-07-21 01:53:57浏览次数:16  
标签:python pyqt6 ffpyplayer

我正在尝试根据此 帖子 中找到的代码来构建我的用例。但是,我在使用 python FFpyPlayer 时遇到了麻烦;对于传统的 ffplay ,我没有这些问题。运行我的应用程序时,我注意到一种追赶延时缓冲效果,视频播放速度显着加快,然后恢复到正常速度。在某些视频中,我发现有些卡顿或滞后。我正在使用 ffpyplayer 在后台线程中处理来自 udp 流的视频播放和帧。不确定在哪里或如何,但我相信使用 PyQt 的 QPixmap 检索和显示帧时会出现问题。下面是使用此股票 ffmpeg 视频 发送udp流的命令: 这里是

ffmpeg -re -stream_loop -1 -i .\2099536-hd_1920_1080_30fps.mp4 -f mpegts udp://127.0.0.1:51234?localaddr=127.0.0.1

运行没有问题的命令: ffplay 这里是一个示例代码,使用

ffplay udp://127.0.0.1:51234

显示它与提到的问题: ffpyplay 这是改编自此

from PyQt6 import QtGui, QtWidgets, QtCore
from ffpyplayer.player import MediaPlayer
import time
from threading import Thread

class VideoDisplayWidget(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.player = None
        self.layout = QtWidgets.QVBoxLayout(self)
        self.video_frame_widget = QtWidgets.QLabel()
        self.layout.addWidget(self.video_frame_widget)
        self.frame_rate = 30

        self.latest_frame = QtGui.QPixmap()

        self.timer = QtCore.QTimer()
        self.timer.setTimerType(QtCore.Qt.TimerType.PreciseTimer)
        self.timer.timeout.connect(self.nextFrameSlot)
        self.timer.start(int(1000.0/self.frame_rate))

        self.play()
        self.setLayout(self.layout)

    def play(self):
        play_thread = Thread(target=self._play, daemon=True)
        play_thread.start()
    
    def _play(self):
        player = MediaPlayer("udp://127.0.0.1:51234")
        val = ''
        while val != 'eof':
            frame, val = player.get_frame()
            if val != 'eof' and frame is not None:
                img, t = frame
                # display img
                w = img.get_size()[0] 
                h = img.get_size()[1]
                data = img.to_bytearray()[0]

                qimage = QtGui.QImage(data, w, h, QtGui.QImage.Format.Format_RGB888)
                self.latest_frame = QtGui.QPixmap.fromImage(qimage)
                time.sleep(0.001)
    
    def nextFrameSlot(self):
        self.video_frame_widget.setPixmap(self.latest_frame)

if __name__ == "__main__":
    current_port = 51234
    app = QtWidgets.QApplication([])
    player = VideoDisplayWidget()
    player.show()

    exit(app.exec())

帖子 的代码块,使用 ffpyplay 没有问题 opencv 是否有特定设置或者参数 I 应该用

from ffpyplayer.player import MediaPlayer
import time
from pathlib import Path
import numpy as np
import cv2

player = MediaPlayer("udp://127.0.0.1:51234")
val = ''
while val != 'eof':
    frame, val = player.get_frame()
    if val != 'eof' and frame is not None:
        img, t = frame
        # display img
        w = img.get_size()[0] 
        h = img.get_size()[1]
        arr = np.uint8(np.array(img.to_bytearray()[0]).reshape(h,w,3)) # h - height of frame, w - width of frame, 3 - number of channels in frame
        arr = cv2.cvtColor(arr, cv2.COLOR_BGR2RGB)
        
        cv2.imshow('test', arr)
        if cv2.waitKey(25) & 0xFF == ord('q'):
            cv2.destroyAllWindows()
            break

和/或 ffpyplay 进行调整以防止这种追赶延时缓冲效应? pyqt to prevent this catch-up time-lapse buffering effect?


FFpyplayer 追赶延迟缓冲和滞后问题的解决方案

遇到的问题是由于视频帧的生成速率与显示速率不匹配造成的。FFmpeg 解码帧的速度可能比 PyQt 显示帧的速度快,这会导致缓冲区累积并出现追赶效果。以下是一些解决此问题的步骤:

1. 使用 time.sleep() 动态调整帧率:

  • 不要在循环中使用固定的 time.sleep(0.001) ,而是根据视频的实际帧率动态调整延迟。
  • 可以使用 player.get_metadata() 获取视频的帧率信息。

```python def _play(self): player = MediaPlayer("udp://127.0.0.1:51234") metadata = player.get_metadata() fps = metadata.get('framerate', 30) # 默认帧率为 30 frame_duration = 1.0 / fps if fps else 0.033 val = '' while val != 'eof': start_time = time.time() frame, val = player.get_frame() if val != 'eof' and frame is not None: img, t = frame # ... 处理帧 ...

           # 动态调整延迟
           elapsed_time = time.time() - start_time
           time.sleep(max(0, frame_duration - elapsed_time))

```

2. 使用 QTimer 控制帧显示:

  • 使用 QTimer 设置固定的帧率,并在每个计时器事件中显示下一帧。
  • 使用 Queue 或其他线程安全的数据结构在 _play() 线程和 GUI 线程之间传递帧。

```python from queue import Queue

class VideoDisplayWidget(QtWidgets.QWidget): def init (self): # ... self.frame_queue = Queue() # ...

   def _play(self):
       # ...
       while val != 'eof':
           # ... 处理帧 ...
           self.frame_queue.put(qimage) # 将帧放入队列

   def nextFrameSlot(self):
       if not self.frame_queue.empty():
           qimage = self.frame_queue.get()
           self.latest_frame = QtGui.QPixmap.fromImage(qimage)
           self.video_frame_widget.setPixmap(self.latest_frame)

```

3. 调整 ffpyplayer 的缓冲区大小:

  • 使用 player.set_option 函数调整 ffpyplayer 的缓冲区大小。
  • 减小缓冲区大小可以减少延迟,但可能会增加丢帧的风险。

python player = MediaPlayer("udp://127.0.0.1:51234") player.set_option('fflags', 'nobuffer') # 禁用缓冲 player.set_option('framedrop', '1') # 允许丢帧

4. 优化帧处理:

  • 确保帧处理代码(例如图像转换)尽可能高效。
  • 使用 timeit 模块分析代码性能并识别瓶颈。

总结:

通过结合以上方法,应该能够解决 FFpyplayer 中的追赶延迟缓冲和滞后问题,并实现流畅的视频播放。请记住,最佳解决方案取决于的特定需求和系统配置,因此可能需要进行一些实验才能找到最佳设置。

标签:python,pyqt6,ffpyplayer
From: 78752567

相关文章

  • 有人可以解决我的代码中的问题吗?而且我无法在我的电脑上安装 nsetools。如何在 python
    从nsetools导入Nseimportpandasaspdnse=Nse()all_stock_codes=nse.get_stock_codes()companies_with_low_pe=[]对于all_stock_codes中的代码:如果代码=='符号':继续尝试:stock_quote=nse.get_quote(代码)pe_ratio=stock_quote.get('priceT......
  • 将 python 脚本的 stdin 重定向到 fifo 会导致 RuntimeError: input():lost sys.stdin
    我有这个python脚本,它的作用是充当服务器,它从重定向到fifo的stdin读取命令:test.py:whileTrue:try:line=input()exceptEOFError:breakprint(f'Received:{line}')在bash中运行命令:mkfifotestfifotest.py<testfifo......
  • Python/Flask mysql 游标:为什么它不起作用?
    fromflaskimportFlaskfromflask_mysqldbimportMySQLapp=Flask(__name__)app.config['MYSQL_HOST']='localhost'app.config['MYSQL_USER']='root'app.config['MYSQL_PASSWORD']='password'a......
  • Python pandas to_csv 导致 OSError: [Errno 22] 参数无效
    我的代码如下:importpandasaspdimportnumpyasnpdf=pd.read_csv("path/to/my/infile.csv")df=df.sort_values(['distance','time'])df.to_csv("path/to/my/outfile.csv")此代码成功从infile.csv(一个3GBcsv文件)读取数据,对其进行排......
  • 从 python 中的字符串列表中提取 def 定义函数的标签
    我想使用Python中的正常def过程创建函数,并将标签分配给从字符串列表中提取的命名空间。如何实现这一点?这个问题的动机:我正在创建一个与sympy兼容的python函数库,供数学家用于符号计算实验。许多函数需要初始化具有相关标签的多个对象的系统,这些标签分别由用户提供的字......
  • 在 Raspberry Pi 4 上使用 Python 从具有 SPI 连接的 MT6816 磁性编码器读取
    我对这个领域完全陌生,并不真正知道自己在做什么并且需要帮助。我正在尝试使用MT681614位磁性编码器通过RaspberryPi的SPI连接读取绝对角度。我有以下问题:在硬件方面,是否只是简单地连接必要的连接(3.3V、MOSI、MISO、SCK、GND、CE01)?对于编码......
  • PythonW 不运行脚本。严重地
    因此,使用Windows10和Python3.6。我创建了一个.py脚本,它可以使用命令pythonmyscript.py在命令提示符下正常运行,但是当我制作该脚本的精确副本并为其赋予扩展名.pyw,并尝试使用pythonw运行它时命令pythonwmyscript.pyw,什么也没有发生......
  • 如何使用Python和Selenium模拟产品购买以获取库存信息
    我正在开发一项网络抓取服务,主要针对时尚行业。我的目标是提供有关产品的全面数据,包括库存水平。为了实现这一目标,我需要模拟购买以确定每种尺寸的产品的最大可用数量。我一直在使用Python和Selenium进行网络抓取部分,但在准确模拟购买方面面临着挑战检索股票信息的过程。......
  • 连接Python套接字的问题
    当我写“关闭”时,我试图让我的电报机器人关闭计算机。我不想将机器人连接到网站上的托管。我选择我的手机(AndroidRedmiNote10)作为托管。我在上面安装了Termux和Pydroid。我写了两个文件:main到我的电脑,client到我的手机。通过在计算机上运行这两个文件,一切正常。但是,当我在......
  • 如何修复导入 Numexpr Python 时的错误
    在Windows10Python3.7.9(IDLE)上,我成功安装了“pipinstallnumexpr”,但在“importnumexprasne”时出现错误:Traceback(最近一次调用):文件“<pyshell#21>”,第267行,位于将numexpr导入为ne文件“C:\Python379\lib\site-packages\numexpr_init_.py”......