Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/285.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python OpenCV支持多个UDP流。巨大的延迟和丢弃率_Python_Opencv_Udp_Video Streaming - Fatal编程技术网

Python OpenCV支持多个UDP流。巨大的延迟和丢弃率

Python OpenCV支持多个UDP流。巨大的延迟和丢弃率,python,opencv,udp,video-streaming,Python,Opencv,Udp,Video Streaming,我使用ffmpeg从一个设备传输多个UDP流,每个流也有一个并发进程,为每个帧计算分数,并在另一个端口发送分数。在接收端,客户端正在读取每个流的帧和分数,并显示来自具有最佳分数的流的帧 问题是,如果有多个流,接收器开始变得非常滞后,并丢弃如此多的帧,更奇怪的是,在较低的比特率下情况更糟(在200kpbs和4个视频流下,大约40%的帧被丢弃,延迟约10秒) 为了排除网络问题,我尝试在不同的进程中显示客户端上的所有流(每个进程读取并显示一个流)。这样,延迟和丢包就最小化了。似乎在同一个过程中有多个视

我使用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我已经在不同的线程中轮询每个流的帧