python中的屏幕共享 [英] Screen sharing in python
问题描述
我被卡住了,我在互联网上找不到任何有用的东西.我正在尝试用 python 制作一个屏幕共享程序.问题是我无法以至少 24 fps 的速度发送屏幕,因为当我使用 PIL (ImageGrab) 截取屏幕截图时,会出现延迟.我的客户端将从服务器获取图片(屏幕截图)并将其blit"到使用 pygame 的屏幕.
Hi I'm stuck and I did not find anything helpful on the internet. I'm trying to make a screen-sharing program in python. The problem is that I can't send the screen in at least 24 fps, because when I take a screenshot with PIL (ImageGrab), something delays there. my client will get the picture (screenshot) from the server and "blit" it to the screen using pygame.
服务器:
# -*- coding: utf-8 -*-
import socket
import os
import threading
from PIL import ImageGrab
def RetrFile(name, sock):
while 1:
img = ImageGrab.grab()
img.save("PATH_TO_PIC")
filename = "PATH_TO_PIC"
sock.send(str(os.path.getsize(filename)))
with open('PATH_TO_PIC', 'rb') as f:
bytesToSend = f.read(1024)
sock.send(bytesToSend)
while bytesToSend != "":
bytesToSend = f.read(1024)
sock.send(bytesToSend)
def Main():
host = '0.0.0.0'
port = 5000
s = socket.socket()
s.bind((host,port))
s.listen(5)
print "Server Started."
while True:
c, addr = s.accept()
print "Client connected ip: <"+ str(addr) + ">"
t = threading.Thread(target = RetrFile, args = ("retrThread", c))
t.start()
s.close()
if __name__ == '__main__':
Main()
客户:
import socket
import pygame as pg
def Main():
host = '127.0.0.1'
port = 5000
pg.init()
display_screen = pg.display.set_mode((1900, 1000))
clock = pg.time.Clock()
s = socket.socket()
s.connect((host,port))
filename = "PATH_TO_PIC"
isExit = False
while not isExit:
for event in pg.event.get():
if event.type == pg.QUIT:
isExit = True
data = s.recv(1024)
print data
filesize = long(data)
f = open(filename, 'wb')
data = s.recv(1024)
totalRecv = len(data)
f.write(data)
while totalRecv < filesize:
data = s.recv(1024)
totalRecv += len(data)
f.write(data)
showImg = pg.image.load('PATH_TO_PIC')
display_screen.blit(showImg, (0,0))
pg.display.flip()
clock.tick(60)
s.close()
if __name__ == '__main__':
Main()
基本上我的问题是:如何在2台电脑之间共享一个屏幕,我不知道使用PIL发送大量图片的方式是否高效正确.有没有更有效的方法?投出1号电脑的屏幕并显示在2号电脑上?
Basically my question is: how to share a screen between 2 computers, I don't know if the way of sending a lot of pictures using PIL is efficient and right. is there a more efficient way? that casts the screen of computer no.1 and shows it at computer no.2 ?
推荐答案
我刚刚尝试过,它似乎工作得很好(Python 3).如果您认为这可以接受,请告诉我,我正在使用 MSS 模块来防止 I/O.
I just tried and it seems to work pretty well (Python 3). Let me know if you find this acceptable, I am using the MSS module to prevent I/O.
server.py
from socket import socket
from threading import Thread
from zlib import compress
from mss import mss
WIDTH = 1900
HEIGHT = 1000
def retreive_screenshot(conn):
with mss() as sct:
# The region to capture
rect = {'top': 0, 'left': 0, 'width': WIDTH, 'height': HEIGHT}
while 'recording':
# Capture the screen
img = sct.grab(rect)
# Tweak the compression level here (0-9)
pixels = compress(img.rgb, 6)
# Send the size of the pixels length
size = len(pixels)
size_len = (size.bit_length() + 7) // 8
conn.send(bytes([size_len]))
# Send the actual pixels length
size_bytes = size.to_bytes(size_len, 'big')
conn.send(size_bytes)
# Send pixels
conn.sendall(pixels)
def main(host='0.0.0.0', port=5000):
sock = socket()
sock.connect((host, port))
try:
sock.listen(5)
print('Server started.')
while 'connected':
conn, addr = sock.accept()
print('Client connected IP:', addr)
thread = Thread(target=retreive_screenshot, args=(conn,))
thread.start()
finally:
sock.close()
if __name__ == '__main__':
main()
client.py
from socket import socket
from zlib import decompress
import pygame
WIDTH = 1900
HEIGHT = 1000
def recvall(conn, length):
""" Retreive all pixels. """
buf = b''
while len(buf) < length:
data = conn.recv(length - len(buf))
if not data:
return data
buf += data
return buf
def main(host='127.0.0.1', port=5000):
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
watching = True
sock = socket()
sock.connect((host, port))
try:
while watching:
for event in pygame.event.get():
if event.type == pygame.QUIT:
watching = False
break
# Retreive the size of the pixels length, the pixels length and pixels
size_len = int.from_bytes(sock.recv(1), byteorder='big')
size = int.from_bytes(sock.recv(size_len), byteorder='big')
pixels = decompress(recvall(sock, size))
# Create the Surface from raw pixels
img = pygame.image.fromstring(pixels, (WIDTH, HEIGHT), 'RGB')
# Display the picture
screen.blit(img, (0, 0))
pygame.display.flip()
clock.tick(60)
finally:
sock.close()
if __name__ == '__main__':
main()
您可以使用另一种压缩算法(如 LZ4)进行改进,该算法具有 Python 实现.你需要尝试一下:)
You could improve by using another compression algorithm like LZ4, which have a Python implementation. You will need to try out :)
这篇关于python中的屏幕共享的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!