我正在尝试根据此
帖子
中找到的代码来构建我的用例。但是,我在使用 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