通过Udp套接字

时间:2017-10-24 13:57:55

标签: sockets video stream udp

我试图在同一网络中的两台计算机上制作网络摄像头流, 所以我在互联网上做了一些研究,我发现这个客户端和服务器代码是客户端

import socket
import numpy as np
import cv2
UDP_IP = '127.0.0.1'                  
UDP_PORT = 999        
cap = cv2.VideoCapture(0)
while(True):
   ret, frame = cap.read()
   cv2.imshow('frame',frame)
   sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
   d = frame.flatten ()
   s = d.tostring ()
   for i in xrange(20):
       sock.sendto (s[i*46080:(i+1)*46080],(UDP_IP, UDP_PORT))


        if cv2.waitKey(1) & 0xFF == ord('q'):
          break

cap.release()
cv2.destroyAllWindows()

这是服务器:

#Server prog

import socket
import numpy
import time
import cv2

UDP_IP="127.0.0.1"
UDP_PORT = 999
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((UDP_IP, UDP_PORT))

s=""

while True:
      data, addr = sock.recvfrom(46080)
      s+= data
      if len(s) == (46080*20):
          frame = numpy.fromstring (s, dtype=numpy.uint8)
          frame = frame.reshape(480,640,3)
          cv2.imshow("frame",frame)

          s=""
      if cv2.waitKey(1) & 0xFF == ord('q'):
          break

有一些我无法理解的行

for i in xrange(20):
   sock.sendto (s[i*46080:(i+1)*46080],(UDP_IP, UDP_PORT))

他为什么要用它? (我知道在UDP中你不能发送一个巨大的文件而你需要发送部分内容,但为什么会这样?为什么要46080?) 并在服务器本身if len(s) == (46080*20):

+当您运行服务器和客户端时,服务器收到的视频流滞后且帧重复出现..

1 个答案:

答案 0 :(得分:0)

46080因为每帧由640x480 RGB像素组成,每个通道一个字节,因此每个像素三个字节,并发送20个:

>>> 640 * 480 * 3 / 20
46080

如果您的摄像头捕获不同分辨率的帧,则该值应与46080不同。大小为46k的帧可能对您的网络来说有点大,所以您可能想要尝试发送超过20个。

s[i*46080:(i+1)*46080]表示大小为46080"的第i个片段。这是所谓的切片符号的一个例子:

>>> a = [0, 1, 2, 3, 4, 5]
>>> a[0:2]  # take element #0 and #1
[0, 1]
>>> a[2:4]  # take element #2 and #3
[2, 3]

这是一个简单但功能强大的工具,因此我建议learn more了解它。您还使用numpy - numpy支持a lot of additional ways来切割n维数组。有点复杂,但更强大。

关于滞后流。

首先,UPD帧可能会丢失,重新排序和重复。为了避免重复和重新排序的数据报,您可以为您发送的每个数据报附加一个序列号,并在接收器上有一个优先级队列。

其次,我怀疑cv2.imshow是显示流畅视频的不错选择。你可能想尝试ffmpeg。

第三,确保发件人足够快,以至少20-30 fps的速度捕获和发送帧。如果没有,尝试将图像采集+处理和传输拆分为单独的线程。我的盲目猜测是你在sock.sendto花了很多时间。不要犹豫是否要对您的代码进行分析。

第四,即使对于相当小的期望分辨率和fps,逐图像地发送视频也可能是非常低效的。您需要在流媒体代码中添加压缩/解压缩阶段。发送未压缩的768x1024x3 @ 30 fps需要70 MBytes / s的带宽。再次ffmpeg可能会帮助你。