我正在用 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()