目标与问题
我想建立一个opencv系统来处理HLS流或RMTP流,但是,我遇到了一个关于帧速率降低和累积滞后的奇怪问题。就好像视频离它应该在流里的位置越来越远。
我正在寻找一种方法,以跟上一个活源,即使它意味着下降帧。
现行方法
import cv2
cap = cv2.VideoCapture()
cap.open('https://videos3.earthcam.com/fecnetwork/9974.flv/chunklist_w1421640637.m3u8')
while (True):
_, frame = cap.read()
cv2.imshow("camCapture", frame)
cv2.waitKey(1)我已经在VLC上验证了流的质量,它似乎在那里工作得很好。
cv2速度

。
实际/预期速度

问题:
发布于 2019-10-15 01:37:43

我的假设是,抖动最有可能是由于网络限制,并发生在帧数据包被丢弃时。当一个帧被删除时,这将导致程序显示最后一个“好”帧,这会导致显示冻结。这可能是一个硬件或带宽问题,但我们可以通过软件缓解其中的一些问题。以下是一些可能的更改:
1.设置最大缓冲区大小
我们将cv2.videoCapture()对象设置为具有cv2.CAP_PROP_BUFFERSIZE参数的有限缓冲区大小。我们的想法是,通过限制缓冲区,我们将始终拥有最新的帧。这也有助于缓解帧随机跳转的问题。
2.设置帧检索延迟
目前,我认为read()读起来太快了,尽管它是在它自己的专用线程中。这可能是为什么所有帧看起来都聚集在一起并突然在下一个帧中爆炸的原因之一。例如,在一秒钟时间间隔内,它可能产生15个新帧,但在下一个一秒间隔中,只返回3个帧。这可能是由于网络数据包帧丢失造成的,因此为了保证获得恒定的帧速率,我们只需在帧检索线程中添加一个延迟。延迟以获得粗略的~30 FPS可以很好地“正常化”帧速率,并在丢包的情况下平滑帧间的转换。
注意:,我们应该尝试匹配流的帧速率,但是我不确定摄像头的FPS是什么,所以我猜到了30 FPS。此外,通常有一个“直接”流链接,而不是通过一个中间的can服务器,这可以大大提高性能。
如果您尝试使用保存的.mp4视频文件,您将注意到没有抖动。这证实了我的怀疑,这个问题很可能是由于网络延迟造成的。
from threading import Thread
import cv2, time
class ThreadedCamera(object):
def __init__(self, src=0):
self.capture = cv2.VideoCapture(src)
self.capture.set(cv2.CAP_PROP_BUFFERSIZE, 2)
# FPS = 1/X
# X = desired FPS
self.FPS = 1/30
self.FPS_MS = int(self.FPS * 1000)
# Start frame retrieval thread
self.thread = Thread(target=self.update, args=())
self.thread.daemon = True
self.thread.start()
def update(self):
while True:
if self.capture.isOpened():
(self.status, self.frame) = self.capture.read()
time.sleep(self.FPS)
def show_frame(self):
cv2.imshow('frame', self.frame)
cv2.waitKey(self.FPS_MS)
if __name__ == '__main__':
src = 'https://videos3.earthcam.com/fecnetwork/9974.flv/chunklist_w1421640637.m3u8'
threaded_camera = ThreadedCamera(src)
while True:
try:
threaded_camera.show_frame()
except AttributeError:
pass相关摄像头/IP/RTSP/流、FPS、视频、线程和多处理帖子
发布于 2019-10-09 19:51:01
尝试线程化
我尝试过用this解决方案从nathancy那里获得一些小小的成功。
它涉及:
代码:
import cv2
from threading import Thread
class ThreadedCamera(object):
def __init__(self, source = 0):
self.capture = cv2.VideoCapture(source)
self.thread = Thread(target = self.update, args = ())
self.thread.daemon = True
self.thread.start()
self.status = False
self.frame = None
def update(self):
while True:
if self.capture.isOpened():
(self.status, self.frame) = self.capture.read()
def grab_frame(self):
if self.status:
return self.frame
return None if __name__ == '__main__':
stream_link = "https://videos3.earthcam.com/fecnetwork/9974.flv/chunklist_w1421640637.m3u8"
streamer = ThreadedCamera(stream_link)
while True:
frame = streamer.grab_frame()
if frame is not None:
cv2.imshow("Context", frame)
cv2.waitKey(1) 紧张,但实时结果

。
流能工作。它能保持实时。然而,就好像所有的帧都聚集在一起,突然爆发到视频中。我想找人解释一下。
有待改进的余地
实时流可以在这里找到。
https://www.earthcam.com/usa/newyork/timessquare/?cam=tsstreet
这个站点是使用python的m3u8流刮刀器为streamlink抓取的。
import streamlink
streams = streamlink.streams("https://www.earthcam.com/usa/newyork/timessquare/?cam=tsstreet")
print(streams)哪几个人:
OrderedDict([
('720p',<HLSStream('https://videos3.earthcam.com/fecnetwork/9974.flv/chunklist_w202109066.m3u8')>),
('live', <RTMPStream({'rtmp': 'rtmp://videos3.earthcam.com/fecnetwork/', 'playpath': '9974.flv', 'pageUrl': 'https://www.earthcam.com/usa/newyork/timessquare/?cam=tsstreet','swfUrl': 'http://static.earthcam.com/swf/streaming/stream_viewer_v3.swf', 'live': 'true'}, redirect=False>),
('worst', <HLSStream('https://videos3.earthcam.com/fecnetwork/9974.flv/chunklist_w202109066.m3u8')>),
('best', <RTMPStream({'rtmp': 'rtmp://videos3.earthcam.com/fecnetwork/', 'playpath': '9974.flv', 'pageUrl': 'https://www.earthcam.com/usa/newyork/timessquare/?cam=tsstreet', 'swfUrl': 'http://static.earthcam.com/swf/streaming/stream_viewer_v3.swf', 'live': 'true'}, redirect=False>)
])流被误读的可能性。
https://stackoverflow.com/questions/58293187
复制相似问题