0

我正在用 Python 测试屏幕投射。客户端和服务器的代码都比较简单。

总之,我之前做的是:

  • 在服务器上:
    • 抓取屏幕与mss
    • 序列化pickle
    • 发送数据
    • 重复每一帧
  • 在客户端:
    • 接收数据并反序列化pickle
    • 通过 CV2 运行接收到的 numpy 数组以显示它

我在本地对其进行了测试,结果证明效果很好。然而,当我开始在我的网络中(台式机和笔记本电脑之间)进行测试时,问题迅速激增。质量很好,但非常滞后,FPS 非常低。

我意识到帧可能太大了,所以我决定把注意力转向压缩,我已经搜索和尝试了几个小时,但无济于事。经过一段时间的搜索,我遇到了一些使用 SO 的用户zlib,所以我决定做同样的事情,尽管通过zlib.compress(frame)在序列化和发送(在服务器上)之前压缩()以及反序列化和解压缩(zlib.decompress(frame))(在客户端)我不能'不要将数据转回 numpy 数组,因此 CV2 会崩溃,说出类似TypeError: Expected Ptr<cv::UMat> for argument 'src'.

除了知道如何有效地压缩帧之外,我还真正想知道是什么降低了我的代码速度,因为我不完全确定问题出在帧大小上。我将不胜感激有关该主题的任何帮助以及任何提示,提示或批评,因为我在该主题上毫无经验。

服务器代码:

import sys, socket as s
import pickle
import struct        
import cv2
import numpy as np
from mss import mss
from PIL import Image
import time

HOST = ''  

if len(sys.argv) > 1:  
    PORT = int(sys.argv[1]) 
else:  
    PORT = 9999  
    
sock = s.socket(s.AF_INET, s.SOCK_STREAM) 
sock.setsockopt(s.SOL_SOCKET, s.SO_REUSEADDR, 1)  

sock.bind((HOST, PORT)) 
sock.listen(1)  

(conn_sock, addr) = sock.accept()


bounding_box = {'top': 0, 'left': 0, 'width': 1920, 'height':1080}

sct = mss()
sct.compression_level = 9

while True:
    try:

        frame = np.array(sct.grab(bounding_box))
        
        msg_bytes = pickle.dumps(frame,-1)
        size_bytes = struct.pack('i',len(msg_bytes))

        # Sending size bytes before actual data
        conn_sock.sendall(size_bytes)
        conn_sock.sendall(msg_bytes)


    except Exception as e:   
        print(e)
        conn_sock.close()

        break

cv2.destroyAllWindows()

客户端代码:

import sys, socket as s
import pickle
import struct
import cv2
import numpy as np
from sock_utils import receive_all


if len(sys.argv) > 1:
    HOST = sys.argv[1]   
    PORT = int(sys.argv[2]) 

else:   
    HOST = '127.0.0.1'   
    PORT = 9999  


conn_sock = s.socket(s.AF_INET, s.SOCK_STREAM)   
conn_sock.connect((HOST, PORT))   
    
while True:   
    
    # Getting size of bytes to receive
    size_bytes = conn_sock.recv(4)
    size = struct.unpack('i',size_bytes)[0]

    # Getting frame bytes
    msg_bytes = receive_all(conn_sock, size)

    # Deserializing frame
    frame = pickle.loads(msg_bytes)


    # Showing output
    cv2.namedWindow("Screencasting", cv2.WINDOW_NORMAL)

    cv2.imshow("Screencasting", frame)

    # Checking for 'q' key if pressed
    key = cv2.waitKey(1) & 0xFF
    if key == ord("q"):
        break



conn_sock.close()
4

0 回答 0