Python OpenCV支持多个UDP流。巨大的延迟和丢弃率
我使用ffmpeg从一个设备传输多个UDP流,每个流也有一个并发进程,为每个帧计算分数,并在另一个端口发送分数。在接收端,客户端正在读取每个流的帧和分数,并显示来自具有最佳分数的流的帧 问题是,如果有多个流,接收器开始变得非常滞后,并丢弃如此多的帧,更奇怪的是,在较低的比特率下情况更糟(在200kpbs和4个视频流下,大约40%的帧被丢弃,延迟约10秒) 为了排除网络问题,我尝试在不同的进程中显示客户端上的所有流(每个进程读取并显示一个流)。这样,延迟和丢包就最小化了。似乎在同一个过程中有多个视频捕获在某种程度上减慢了速度 以下是客户端代码的相关部分Python OpenCV支持多个UDP流。巨大的延迟和丢弃率,python,opencv,udp,video-streaming,Python,Opencv,Udp,Video Streaming,我使用ffmpeg从一个设备传输多个UDP流,每个流也有一个并发进程,为每个帧计算分数,并在另一个端口发送分数。在接收端,客户端正在读取每个流的帧和分数,并显示来自具有最佳分数的流的帧 问题是,如果有多个流,接收器开始变得非常滞后,并丢弃如此多的帧,更奇怪的是,在较低的比特率下情况更糟(在200kpbs和4个视频流下,大约40%的帧被丢弃,延迟约10秒) 为了排除网络问题,我尝试在不同的进程中显示客户端上的所有流(每个进程读取并显示一个流)。这样,延迟和丢包就最小化了。似乎在同一个过程中有多个视
# thread per stream, reads frames and queues them up
def rx_thread(ip, vport, tport, q):
global die
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((ip, tport))
reader = s.makefile('r')
cap = cv2.VideoCapture('udp://'+ip+':'+str(vport))
while not die:
score = float(reader.readline())
ret, frame = cap.read()
if not ret:
die = True
break
q.put((frame, score))
cap.release()
reader.close()
s.close()
output = open(argv[1], 'w', buffering=1)
# arg[3] .. are pairs of video port and score port
queues = []
for i in range(3, len(argv), 2):
q = queue.Queue(30)
t = threading.Thread(target=rx_thread,
args=(argv[2], int(argv[i]),int(argv[i+1]), q))
t.start()
queues.append(q)
frames_count = 0
start = None
while True:
try:
frames, info = zip(*map(lambda q: q.get(True, 5), queues))
except queue.Empty:
die = True
break
if start is None:
start = time()
output.write('start: %.3f\n' % start)
frames_count += 1
# get stream with max score and show
index = info.index(max(info))
cv2.imshow('Video', frames[index])
if cv2.waitKey(1) & 0xFF == ord('q'):
die = True
break
output.write('frames_count: %d\n' % frames_count)
编辑:
一些人认为这可能与分数的发送方式有关。我试图完全忽略分数(我没有打开分数套接字,并且在排队时为每一帧设置1.0的虚拟分数)。因此,基本上,客户端只是在读取一组视频流。这个问题仍然存在。一开始,总是会有一大堆错误,比如:
[mpeg4 @ 0x7ff838016fc0] Error, header damaged or not MPEG-4 header (f_code=0)
[mpeg4 @ 0x7ff838016fc0] header damaged
[mpeg4 @ 0x7ff838046c40] warning: first frame is no keyframe
[mpeg4 @ 0x7ff840016f80] Error, header damaged or not MPEG-4 header (qscale=0)
第一帧没有关键帧
错误似乎在流数为n时正好发生n-1次。猜测这与您发送分数的方式有关。UDP不是一个可靠的流协议,并告诉Python通过s假装是。makefile()
是一个非常的协议。我可以通过让客户端和服务器执行以下操作来复制类似的内容:
def receiver():
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
sock.bind(('', 8888))
with sock.makefile('r') as reader:
print('receiver running')
while True:
print('received', repr(reader.readline()))
def sender():
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
sock.connect(('127.0.0.1', 8888))
with sock.makefile('w') as writer:
for i in range(1000):
print('sending', i)
print('value =', i, 'stuff to fill the buffers up', file=writer)
time.sleep(0.02)
同时运行它们。您将看到发送方定期“发送”值,但接收方将在数据块中接收它们,因为它们恰好被刷新
我猜测,当事情进展缓慢时,行为变得更糟糕的原因是,由于缓冲区填充得更慢,分数被推送得不那么频繁
一般来说,您最好直接在套接字上使用
send
和recv
,这样可以更好地控制缓冲和数据包边界。还要注意,UDP是不可靠的,因此可以随意丢弃和重新排序数据包。因此,您需要其中的某些内容来跟踪所有内容,可能会要求评分服务在未及时收到分数时重试发送分数如何保持视频帧与分数同步?如果你这样对待套接字,为什么不使用TCP呢?目前,什么都没有。我想,我以后会处理的。这可能是问题的原因吗?分数在单独的帧中发送。我将尝试验证这是否是原因。你看了吗?@nathancy我已经在不同的线程中轮询每个流的帧