使用OpenCV和Web Socket进行Python视频流传输

5
我正在尝试编写一个Python脚本,使用Web Socket流式传输视频到浏览器。我正在使用OpenCV作为客户端通过Socket发送帧,浏览器脚本接收并在浏览器上显示。单个图像可以在浏览器中显示,但是在流式传输视频时遇到问题,无法在浏览器上显示。 Python Flask可正常工作,但存在一些问题,因此我计划使用WebSocket进行浏览器显示。
客户端代码使用OpenCV和Socket将帧发送到服务器。
import cv2
import numpy as np
import socket
import sys
import pickle
import struct ### new code
cap=cv2.VideoCapture("test.avi")
clientsocket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
clientsocket.connect(('0.0.0.0',8082))
while True:
    ret,frame=cap.read()
    data = pickle.dumps(frame) ### new code
    clientsocket.sendall(struct.pack("L", len(data))+data)

浏览器代码
import socket   #for sockets handling
import time     #for time functions
import sys
import cv2
import pickle
import numpy as np
import struct ##

hostIP = '127.0.0.1'
SourcePort = 8082 #client socket
PlayerPort = 8081 #Internet Browser


def gen_headers():
     # determine response code
     h = ''
     h = 'HTTP/1.1 200 OK\n'
     # write further headers
     current_date = time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime())
     h += 'Date: ' + current_date +'\n'
     h += 'Content-Type: image/jpeg\n\n'
     return h

def start_server():
    socketFFMPEG = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # this is for easy starting/killing the app
    socketFFMPEG.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    print('Socket created')
    ### new
    data = b""
    payload_size = struct.calcsize("L")
    try:
        socketFFMPEG.bind((hostIP, SourcePort))
        print('Socket bind complete')
    except socket.error as msg:
        print('Bind failed. Error : ' + str(sys.exc_info()))
        sys.exit()

    #Start listening on socketFFMPEG
    socketFFMPEG.listen(10)
    print('Socket now listening. Waiting for video source from client socket on port', SourcePort)

    conn, addr = socketFFMPEG.accept()
    ip, port = str(addr[0]), str(addr[1])
    print('Accepting connection from ' + ip + ':' + port)

    socketPlayer = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    socketPlayer.bind((hostIP, PlayerPort))
    socketPlayer.listen(1) #listen just 1 petition
    print('Waiting for Internet Browser')
    conn2, addr2 = socketPlayer.accept()
    #conn2.sendall(gen_headers().encode())

    while True:
        try :
            while len(data) < payload_size:
                data += conn.recv(4096)
            packed_msg_size = data[:payload_size]
            data = data[payload_size:]
            msg_size = struct.unpack("L", packed_msg_size)[0]
            while len(data) < msg_size:
                data += conn.recv(4096)
            frame_data = data[:msg_size]
            data = data[msg_size:]
            ###

            frame=pickle.loads(frame_data) 
            #send data to internet browser
            print(frame)
            ret, frame = cv2.imencode('.jpg', frame)
            frames = frame.tobytes()
            conn2.sendall( gen_headers().encode()+frames)
        except socket.error:
            print('Error data :' + str(frame))
            print('send Error : ' + str(sys.exc_info()))
            conn2.close()
            sys.exit()

    socketFFMPEG.close()

start_server()  

什么问题? - Ardiya
@ardiya 我想在浏览器上显示OpenCV帧。 - vishalk
只需跟随一些教程,例如 https://blog.miguelgrinberg.com/post/video-streaming-with-flask/page/4。 - Ardiya
@ardiya,请仔细阅读我的问题:“Python Flask工作正常,但存在一些问题,因此我计划使用WebSockets来进行浏览器显示”。 - vishalk
1
我检查为什么用户对这个问题进行了负面评价,检查push_server以进行图像流传输(而非视频)。 - dsgdfg
1
在循环中获取图像('pyhton/flask/jpeg')并不是真正的视频流。RTP/RSTP 才是。 - Pawel
1个回答

0

Server.py

# This is server code to send video frames over UDP
import cv2, imutils, socket
import numpy as np
import time
import base64

BUFF_SIZE = 65536
server_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_RCVBUF,BUFF_SIZE)
host_name = socket.gethostname()
host_ip = '192.168.1.102'#  socket.gethostbyname(host_name)
print(host_ip)
port = 9999
socket_address = (host_ip,port)
server_socket.bind(socket_address)
print('Listening at:',socket_address)

vid = cv2.VideoCapture(0) #  replace 'rocket.mp4' with 0 for webcam
fps,st,frames_to_count,cnt = (0,0,20,0)

while True:
    msg,client_addr = server_socket.recvfrom(BUFF_SIZE)
    print('GOT connection from ',client_addr)
    WIDTH=400
    while(vid.isOpened()):
        _,frame = vid.read()
        frame = imutils.resize(frame,width=WIDTH)
        encoded,buffer = cv2.imencode('.jpg',frame,[cv2.IMWRITE_JPEG_QUALITY,80])
        message = base64.b64encode(buffer)
        server_socket.sendto(message,client_addr)
        frame = cv2.putText(frame,'FPS: '+str(fps),(10,40),cv2.FONT_HERSHEY_SIMPLEX,0.7,(0,0,255),2)
        cv2.imshow('TRANSMITTING VIDEO',frame)
        key = cv2.waitKey(1) & 0xFF
        if key == ord('q'):
            server_socket.close()
            break
        if cnt == frames_to_count:
            try:
                fps = round(frames_to_count/(time.time()-st))
                st=time.time()
                cnt=0
            except:
                pass
        cnt+=1

Client.py

# This is client code to receive video frames over UDP
import cv2, imutils, socket
import numpy as np
import time
import base64

BUFF_SIZE = 65536
client_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
client_socket.setsockopt(socket.SOL_SOCKET,socket.SO_RCVBUF,BUFF_SIZE)
host_name = socket.gethostname()
host_ip = '192.168.1.102'#  socket.gethostbyname(host_name)
print(host_ip)
port = 9999
message = b'Hello'

client_socket.sendto(message,(host_ip,port))
fps,st,frames_to_count,cnt = (0,0,20,0)
while True:
    packet,_ = client_socket.recvfrom(BUFF_SIZE)
    data = base64.b64decode(packet,' /')
    npdata = np.fromstring(data,dtype=np.uint8)
    frame = cv2.imdecode(npdata,1)
    frame = cv2.putText(frame,'FPS: '+str(fps),(10,40),cv2.FONT_HERSHEY_SIMPLEX,0.7,(0,0,255),2)
    cv2.imshow("RECEIVING VIDEO",frame)
    key = cv2.waitKey(1) & 0xFF
    if key == ord('q'):
        client_socket.close()
        break
    if cnt == frames_to_count:
        try:
            fps = round(frames_to_count/(time.time()-st))
            st=time.time()
            cnt=0
        except:
            pass
    cnt+=1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接