昨天心血来潮写了一篇关于简易共享屏幕工具的文章,发现也有一些阅读量,并且我对于它的效果不是很满意 ,实际呈现的帧率还是太低了。所以我今天换了更高效的方式来实现。
50 行代码简易屏幕共享工具
改进
降低分辨率
昨天那个测试的帧率低,最大的原因是我的电脑的分辨率有点高了,它是2.5K屏幕,所以我今天换成了 1920*1080 的屏幕来测试,效果就好很多了,基本都在 50 帧左右。
更换截屏库
更换了一个速度更快的截屏库,这个截屏库的速度很快,比昨天那个快多了,但是反应到实际的帧率上就低了,所以还是后续其他的操作太过于耗时,但是暂时也没有想到啥优化的好方法。
降低图片的质量
JPEG 格式的图片是可以选择压缩质量的,适当的调低质量可以提高处理的速度。
缺点
这个程序占用资源还是挺大的,运行程序之后,我的笔记本电脑风扇就开始运行了,不过这个可能也是因为帧率提高的原因吧。
代码
from flask import Flask, Response
from io import BytesIO
from PIL import Image, ImageDraw, ImageFont
import time
import dxcam
app = Flask(__name__)
# 整个应用只创建一个即可
camera = dxcam.create(device_idx=0, output_idx=1) # output_idx 0 是第一块屏幕,1 是第二块屏幕
camera.start(target_fps=60, video_mode=True)
@app.route('/monitor', methods=['GET'])
def monitor():
"""获取屏幕数据并返回"""
def gen_img():
# 获取屏幕的全部区域
fps = 0 # 帧率
frame_count = 0 # 计算帧率,这是服务端生成的速率,到了客户端还会更低
start_time = time.perf_counter()
buffer = BytesIO()
while True:
reset_buffer(buffer) # 每次重置buffer,方便复用
t1 = time.perf_counter()
yield get_frame(buffer, fps)
print("get frame fps: ", 1.0 / (time.perf_counter() - t1))
frame_count += 1
elapsed_time = time.perf_counter() - start_time
if elapsed_time >= 1:
fps = frame_count // elapsed_time
frame_count = 0
start_time = time.perf_counter()
print("real frame fps: ", fps)
return Response(gen_img(), mimetype="multipart/x-mixed-replace; boundary=frame")
def get_frame(buffer, fps):
"""
获取一帧,然后处理成jpeg并返回二进制数据
"""
image_array = camera.get_latest_frame()
img = Image.fromarray(image_array)
if fps > 0:
img = add_fps(img, fps)
img.save(buffer, format="JPEG", quality=20)
return (b'--frame\r\n' +
b'Content-Type: image/jpeg\r\n\r\n' + buffer.getvalue() + b'\r\n')
def reset_buffer(buffer):
# 重置buffer,方便复用
buffer.truncate(0)
buffer.seek(0)
def add_fps(img, fps):
"""在图片上添加fps"""
draw = ImageDraw.Draw(img)
draw.text((100, 100), f"fps: {fps}", (255, 0, 0), ImageFont.truetype("arial.ttf", 100))
return img
if __name__ == '__main__':
print("monitoring...")
app.run("127.0.0.1", 9000)