python:基于套接字socket传输视频的方法代码记录总结

tech2023-06-07  106

初始想法是想模拟IP摄像头传输视频然后实时监测的场景,后来发现和要实现的目标有所偏离,但还是把其中可参考、有所修改的可用代码记录下来。 功能都是客户端发送视频,服务器接收视频,没有服务器发送视频返回客户端的内容。

我在修改其中代码的时候没有考虑到多进程(multiprocessing)与多线程(threading)的区别,所以代码中有混用的情况,请注意这个情况,在此不做仔细区分。 下面多进程/多线程客户端的代码是相同的,可以多建几个文件只改变发送的视频文件,模拟多客户端。

先运行接收端(服务器),再运行发送端(客户端)。 ip地址要在同一网段下,及前三段数字相同,发送端被拒绝连接时要查看端口是否被占用。

1.使用opencv读取视频,按帧使用套接字发送并接收写为视频

import socket import cv2 import numpy as np import time import sys def SendVideo(): address = ('172.23.13.216', 8025) try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(address) except socket.error as msg: print(msg) sys.exit(1) capture = cv2.VideoCapture('../testvideo/video1_24.avi') # capture = cv2.VideoCapture(1) # capture.set(3, 1920)#参数:3:在视频流的帧的宽度 功能:把视频流的帧(图片)的宽度调成指定值 # capture.set(4, 1080) #参数:4:在视频流的帧的高度 功能:把视频流的帧(图片)的高度调成指定值 # capture.set(5, 24) #5:CV_CAP_PROP_FPS 帧速率 ret, frame = capture.read() encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 15] sumtime = 0 while ret: t1 = time.time() ## 首先对图片进行编码,因为socket不支持直接发送图片 result, imgencode = cv2.imencode('.jpg', frame, encode_param)# data = np.array(imgencode) stringData = data.tostring() ## 首先发送图片编码后的长度 sock.send(str.encode(str(len(stringData)).ljust(16))) ## 然后发送编码的内容 sock.send(stringData) eachtime = time.time() - t1 sumtime += eachtime ret, frame = capture.read()# cv2.imshow('show', frame) if cv2.waitKey( 2) & 0xff == 27: break print('process time = ', eachtime) # 处理时间 sock.close() print('++++++++++This path send over++++++++++') print(sumtime) if __name__ == '__main__': SendVideo() """ 传输时间慢 1.cv2.imencode('.jpg', frame, encode_param),修改为png,传输速度更慢 2.encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 15],压缩传输中的质量参数改变对传输速度影响小 原因 待寻找 """ import socket import time import cv2 import numpy import copy from multiprocessing import Process#多进程 def ReceiveVideo(conn, addr): # 接受图片及大小的信息 def recvall(sock, count):#读取count长度的数据 buf = b'' while count: newbuf = sock.recv(count) # s.sendall()发送, s.recv()接收. 因为client是通过 sk.recv()来进行接受数据,而count表示,最多每次接受count字节, if not newbuf: return None buf += newbuf count -= len(newbuf) return buf print('connect from:' + str(addr)) fourcc = cv2.VideoWriter_fourcc('X', 'V', 'I','D')#avi格式 videoWriter = cv2.VideoWriter('./receive_video/%s.avi' % time.strftime("%Y-%m-%d-%H_%M_%S",time.localtime(time.time())) , fourcc, 24, (1920, 1080))##%(str(time.strftime("%Y-%m-%d-%H:%M:%S",time.localtime()))) while True: start = time.time() length = recvall(conn, 1024) stringData = recvall(conn, int(length))#nt()只能转化由纯数字组成的字符串 # length =conn.recv(1024) # stringData = conn.recv(int(length))#nt()只能转化由纯数字组成的字符串 data = numpy.fromstring(stringData,numpy.uint8) # 将获取到的字符流数据转换成1维数组 data = numpy.fromstring() numpy.frombuffer decimg = cv2.imdecode(data, cv2.IMREAD_COLOR) # 将数组解码成图像 #cv2.imshow('SERVER', decimg) # 显示图像 # ================================================================================================================================= videoWriter.write(decimg) end = time.time() eachtime =end - start print('process time = ', eachtime) # ================================================================================================================================ if cv2.waitKey( 10) & 0xff == 27: break cv2.destroyAllWindows() # videoWriter.release()##释放写入视频流 if __name__ == '__main__': address = ('172.23.13.226', 8035)#'192.168.1.104', 8004 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(address) s.listen(5) while True: conn, addr = s.accept() p=Process(target=ReceiveVideo,args=(conn, addr)) #daemon默认值为False,如果设置为True,代表该进程为后台守护进程;当该进程的父进程终止时,该进程也随之终止;并且设置为True后,该进程不能创建子进程,设置该属性必须在start()之前 p.start() s.close()

2.读写文件形式,二进制文件,直接发送及接收为视频

参考:Python socket传输MP4,MP3

import socket import os from time import * import sys def SendVideo(): address = ('172.23.13.226', 8105) # 192.168.1.103ubuntu try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(address) except socket.error as msg: print(msg) sys.exit(1) videopath = "../testvideo/video0_24.flv" video_size = os.path.getsize(videopath)/1024/1024 #字节换算为MB with open(videopath,'rb') as f: stringData = f.read() #读出来就是字节 start_time = time() sock.send(stringData) end_time = time() All_time = end_time - start_time rate = round(video_size/All_time,2) #计算速率,四舍五入保留两位 print("[*]发送时间(sec):%s"%(All_time)) print(f"[*]Rate: {rate}MB/s") print('[*]This path send over') sock.close() if __name__ == '__main__': SendVideo() import socket import time import os from multiprocessing import Process def ReceiveVideo(conn,addr): print('[*]connect from:' + str(addr)) start = time.time() videoname="%s.flv" % (time.strftime("%Y-%m-%d-%H_%M_%S",time.localtime(time.time()))) while True:#一次接收1024字节 持续发送 s=time.time() stringData=conn.recv(1024) if not stringData: break videopath="./receive_video/"+ videoname #% time.strftime("%Y-%m-%d-%H_%M_%S",time.localtime(time.time())) with open(videopath,'ab') as f: f.write(stringData) #===================== # e = time.time() # eachtime=e-s # print(eachtime) # each_size=os.path.getsize(videopath) # print(each_size) # rate = round(each_size / eachtime, 4) # print(print(f"[*]Rate: {rate}MB/s")) #======================= end = time.time() print('[*]process time (sec): ', end - start) video_size = os.path.getsize(videopath)# #单位是B(字节) print(f"[*]This File is {round(video_size/1024/1024,2)} MB") print('[*]This path send over') if __name__ == '__main__': address = ('172.23.13.226', 8105)#'192.168.1.104', 8004 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(address) s.listen(5) print(f"[*]Listening: {address}") while True: conn, addr = s.accept() p=Process(target=ReceiveVideo,args=(conn, addr)) #daemon默认值为False,如果设置为True,代表该进程为后台守护进程;当该进程的父进程终止时,该进程也随之终止;并且设置为True后,该进程不能创建子进程,设置该属性必须在start()之前 p.start() s.close()

3.

参考: Python3远程监控程序实现 基于python和opencv的视频传输程序(一)

import socket import struct import time import cv2 import numpy class Config(object): def __init__(self): self.TargetIP = ('172.23.13.216', 6666) self.resolution = (720, 480) # 分辨率720, 480 self.img_fps = 15 # each second send pictures self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.server.connect(self.TargetIP) self.img = '' self.img_data = '' def RT_Image(self): camera = cv2.VideoCapture(0)#"../testvideo/video0_24.flv" img_param = [int(cv2.IMWRITE_JPEG_QUALITY), self.img_fps] while True: #time.sleep(0.1) # sleep for 0.1 seconds ret, self.img = camera.read() self.img = cv2.resize(self.img, self.resolution) _, img_encode = cv2.imencode('.jpg', self.img, img_param) img_code = numpy.array(img_encode) self.img_data = img_code.tostring() # bytes data try: packet = struct.pack(b'lhh', len(self.img_data), self.resolution[0], self.resolution[1]) self.server.send(packet) self.server.send(self.img_data) except Exception as e: print(e.args) camera.release() return if __name__ == '__main__': config = Config() config.RT_Image() import socket import cv2 import struct import numpy import threading import time class Camera_Connect_Object(object): def __init__(self, TargetIP=('', 6666)): self.TargetIP = TargetIP self.resolution = (720, 480) self.src = 888 + 15 self.interval = 0 self.img_fps = 15 self.Server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.Server.bind(self.TargetIP) self.Server.listen(5) def RT_Image(self): #=========================================================================================================== fourcc = cv2.VideoWriter_fourcc('X', 'V', 'I', 'D') # avi格式 videoWriter = cv2.VideoWriter('./%s.avi' % time.strftime("%Y-%m-%d-%H_%M_%S", time.localtime(time.time())), fourcc, 30, (720, 480)) # =========================================================================================================== self.client, self.addr = self.Server.accept() self.name = self.addr[0] + " Camera" print(self.name) while True: # time.sleep(0.3) # sleep for 0.3 seconds tempdata = self.client.recv(8) if len(tempdata) == 0: print("+1") continue info = struct.unpack('lhh', tempdata) buf_size = int(info[0]) if buf_size: try: self.buf = b"" self.temp_buf = self.buf while buf_size: self.temp_buf = self.client.recv(buf_size) buf_size -= len(self.temp_buf) self.buf += self.temp_buf data = numpy.fromstring(self.buf, dtype='uint8') self.image = cv2.imdecode(data, 1) # =========================================================================================================== videoWriter.write(self.image) # =========================================================================================================== cv2.imshow(self.name, self.image) except Exception as e: print(e.args) pass finally: if cv2.waitKey(10) == 27: self.client.close() cv2.destroyAllWindows() videoWriter.release() break def Get_data(self): showThread = threading.Thread(target=self.RT_Image) showThread.start() showThread.join() if __name__ == '__main__': camera = Camera_Connect_Object() camera.Get_data()

在个我在自己windows电脑本地发送接收成功,但在windoes向ubuntu发送接收失败,ubuntu出现有关于“info = struct.unpack(‘lhh’, tempdata)”的错误提示。

4.

参考 基于Python3 + OpenCV3.3.1的远程监控程序

#服务器端 import socket import threading import struct import time import cv2 import numpy class Carame_Accept_Object: def __init__(self,S_addr_port=("",8880)): self.resolution=(640,480) #分辨率 self.img_fps=15 #每秒传输多少帧数 self.addr_port=S_addr_port self.Set_Socket(self.addr_port) #设置套接字 def Set_Socket(self,S_addr_port): self.server=socket.socket(socket.AF_INET,socket.SOCK_STREAM) self.server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #端口可复用 self.server.bind(S_addr_port) self.server.listen(5) #print("the process work in the port:%d" % S_addr_port[1]) def check_option(object,client): #按格式解码,确定帧数和分辨率 info=struct.unpack('lhh',client.recv(8)) if info[0]>888: object.img_fps=int(info[0])-888 #获取帧数 object.resolution=list(object.resolution) # 获取分辨率 object.resolution[0]=info[1] object.resolution[1]=info[2] object.resolution = tuple(object.resolution) return 1 else: return 0 def RT_Image(object,client,D_addr): if(check_option(object,client)==0): return camera=cv2.VideoCapture(0) #从摄像头中获取视频 img_param=[int(cv2.IMWRITE_JPEG_QUALITY),object.img_fps] #设置传送图像格式、帧数 while(1): time.sleep(0.1) #推迟线程运行0.1s _,object.img=camera.read() #读取视频每一帧 object.img=cv2.resize(object.img,object.resolution) #按要求调整图像大小(resolution必须为元组) _,img_encode=cv2.imencode('.jpg',object.img,img_param) #按格式生成图片 img_code=numpy.array(img_encode) #转换成矩阵 object.img_data=img_code.tostring() #生成相应的字符串 try: #按照相应的格式进行打包发送图片 client.send(struct.pack("lhh",len(object.img_data),object.resolution[0],object.resolution[1])+object.img_data) except: camera.release() #释放资源 return if __name__ == '__main__': camera=Carame_Accept_Object() while(1): client,D_addr=camera.server.accept() clientThread=threading.Thread(None,target=RT_Image,args=(camera,client,D_addr,)) clientThread.start() #客户端 import socket import cv2 import threading import struct import numpy class Camera_Connect_Object: def __init__(self,D_addr_port=["",8880]): self.resolution=[640,480] self.addr_port=D_addr_port self.src=888+15 #双方确定传输帧数,(888)为校验值 self.interval=0 #图片播放时间间隔 self.img_fps=15 #每秒传输多少帧数 def Set_socket(self): self.client=socket.socket(socket.AF_INET,socket.SOCK_STREAM) self.client.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) def Socket_Connect(self): self.Set_socket() self.client.connect(self.addr_port) print("IP is %s:%d" % (self.addr_port[0],self.addr_port[1])) def RT_Image(self): #按照格式打包发送帧数和分辨率 self.name=self.addr_port[0]+" Camera" self.client.send(struct.pack("lhh", self.src, self.resolution[0], self.resolution[1])) while(1): info=struct.unpack("lhh",self.client.recv(8)) buf_size=info[0] #获取读的图片总长度 if buf_size: try: self.buf=b"" #代表bytes类型 temp_buf=self.buf while(buf_size): #读取每一张图片的长度 temp_buf=self.client.recv(buf_size) buf_size-=len(temp_buf) self.buf+=temp_buf #获取图片 data = numpy.fromstring(self.buf, dtype='uint8') #按uint8转换为图像矩阵 self.image = cv2.imdecode(data, 1) #图像解码 cv2.imshow(self.name, self.image) #展示图片 except: pass; finally: if(cv2.waitKey(10)==27): #每10ms刷新一次图片,按‘ESC’(27)退出 self.client.close() cv2.destroyAllWindows() break def Get_Data(self,interval): showThread=threading.Thread(target=self.RT_Image) showThread.start() if __name__ == '__main__': camera=Camera_Connect_Object() camera.addr_port[0]=input("Please input IP:") camera.addr_port=tuple(camera.addr_port) camera.Socket_Connect() camera.Get_Data(camera.interval)
最新回复(0)