[color=]import
[color=]tkinter
[color=]as
[color=]tk
[color=]from
[color=]tkinter
[color=]import
[color=]ttk
,
[color=]messagebox
[color=]import
[color=]socket
[color=]import
[color=]threading
[color=]from
[color=]flask
[color=]import
[color=]Flask
,
[color=]Response
,
[color=]request
[color=]import
[color=]mss
[color=]import
[color=]mss
.
[color=]tools
[color=]import
[color=]os
[color=]import
[color=]sys
[color=]import
[color=]time
[color=]import
[color=]subprocess
[color=]from
[color=]PIL
[color=]import
[color=]Image
[color=]import
[color=]io
[color=]import
[color=]queue
[color=]import
[color=]json
[color=]import
[color=]ctypes
[color=]import
[color=]numpy
[color=]as
[color=]np
[color=]import
[color=]cv2
[color=]# 添加OpenCV用于高效图像处理
[color=]class
[color=]ScreenMirrorApp
:
[color=]def
[color=]__init__
(
[color=]self
,
[color=]root
):
[color=]self
.
[color=]root
[color=]=
[color=]root
[color=]self
.
[color=]root
.title(
[color=]"低延迟屏幕投屏工具"
)
[color=]self
.
[color=]root
.geometry(
[color=]"550x550"
)
[color=]self
.
[color=]root
.resizable(
[color=]False
,
[color=]False
)
[color=]# 设置应用图标
[color=]self
.
[color=]set_icon
()
[color=]# 获取本机IP地址
[color=]self
.
[color=]ip_address
[color=]=
[color=]self
.
[color=]get_ip_address
()
[color=]# 创建UI
[color=]self
.
[color=]create_widgets
()
[color=]# 获取显示器信息
[color=]self
.
[color=]monitors
[color=]=
[color=]self
.
[color=]get_monitors
()
[color=]# 初始化投屏状态
[color=]self
.
[color=]mirroring
[color=]=
[color=]False
[color=]self
.
[color=]server_thread
[color=]=
[color=]None
[color=]self
.
[color=]flask_app
[color=]=
[color=]None
[color=]self
.
[color=]last_frame
[color=]=
[color=]None
[color=]self
.
[color=]frame_queue
[color=]=
[color=]queue
.
[color=]Queue
(
[color=]maxsize
[color=]=
[color=]1
)
[color=]self
.
[color=]capture_thread
[color=]=
[color=]None
[color=]self
.
[color=]stop_capture
[color=]=
[color=]threading
.
[color=]Event
()
[color=]# 自动添加防火墙规则
[color=]self
.
[color=]add_firewall_rule
()
[color=]# 性能参数默认值
[color=]self
.
[color=]quality
[color=]=
[color=]70
[color=]self
.
[color=]frame_rate
[color=]=
[color=]30
[color=]self
.
[color=]resolution
[color=]=
[color=]0.7
[color=]# 性能计数器
[color=]self
.
[color=]frame_count
[color=]=
[color=]0
[color=]self
.
[color=]start_time
[color=]=
[color=]time
.
[color=]time
()
[color=]# 客户端连接状态
[color=]self
.
[color=]active_clients
[color=]=
[color=]set
()
[color=]# 黑屏图像
[color=]self
.
[color=]black_image
[color=]=
[color=]self
.
[color=]create_black_image
()
[color=]# 加载上次选择的设置
[color=]self
.
[color=]load_config
()
[color=]def
[color=]create_black_image
(
[color=]self
):
[color=]"""创建黑屏图像"""
[color=]img
[color=]=
[color=]Image
.
[color=]new
(
[color=]'RGB'
, (
[color=]100
,
[color=]100
), (
[color=]0
,
[color=]0
,
[color=]0
))
[color=]img_byte_arr
[color=]=
[color=]io
.
[color=]BytesIO
()
[color=]img
.
[color=]save
(
[color=]img_byte_arr
,
[color=]format
[color=]=
[color=]'JPEG'
,
[color=]quality
[color=]=
[color=]1
)
[color=]return
[color=]img_byte_arr
.
[color=]getvalue
()
[color=]def
[color=]set_icon
(
[color=]self
):
[color=]"""设置应用图标"""
[color=]try
:
[color=]if
[color=]getattr
(
[color=]sys
,
[color=]'frozen'
,
[color=]False
):
[color=]icon_path
[color=]=
[color=]os
.
[color=]path
.
[color=]join
(
[color=]sys
._MEIPASS,
[color=]'icon.ico'
)
[color=]else
:
[color=]icon_path
[color=]=
[color=]'icon.ico'
[color=]self
.
[color=]root
.iconbitmap(
[color=]icon_path
)
[color=]except
:
[color=]pass
[color=]def
[color=]get_ip_address
(
[color=]self
):
[color=]"""获取本机IP地址"""
[color=]try
:
[color=]s
[color=]=
[color=]socket
.
[color=]socket
(
[color=]socket
.
[color=]AF_INET
,
[color=]socket
.
[color=]SOCK_DGRAM
)
[color=]s
.
[color=]connect
((
[color=]"8.8.8.8"
,
[color=]80
))
[color=]ip_address
[color=]=
[color=]s
.
[color=]getsockname
()[
[color=]0
]
[color=]s
.
[color=]close
()
[color=]return
[color=]ip_address
[color=]except
:
[color=]return
[color=]"127.0.0.1"
[color=]def
[color=]get_monitors
(
[color=]self
):
[color=]"""获取所有显示器信息"""
[color=]with
[color=]mss
.
[color=]mss
()
[color=]as
[color=]sct
:
[color=]return
[color=]sct
.
[color=]monitors
[color=]def
[color=]load_config
(
[color=]self
):
[color=]"""加载上次的设置"""
[color=]config_path
[color=]=
[color=]os
.
[color=]path
.
[color=]join
(
[color=]os
.
[color=]path
.
[color=]expanduser
(
[color=]"~"
),
[color=]".screen_mirror_config.json"
)
[color=]try
:
[color=]if
[color=]os
.
[color=]path
.
[color=]exists
(
[color=]config_path
):
[color=]with
[color=]open
(
[color=]config_path
,
[color=]"r"
)
[color=]as
[color=]f
:
[color=]config
[color=]=
[color=]json
.
[color=]load
(
[color=]f
)
[color=]# 加载屏幕设置
[color=]last_screen
[color=]=
[color=]config
.get(
[color=]"last_screen"
,
[color=]1
)
[color=]if
[color=]1
[color=]last_screen
[color=]len
(
[color=]self
.
[color=]monitors
):
[color=]self
.
[color=]screen_var
.
[color=]set
(
[color=]last_screen
)
[color=]# 加载性能设置
[color=]quality
[color=]=
[color=]config
.get(
[color=]"quality"
,
[color=]70
)
[color=]if
[color=]30
[color=]quality
[color=]95
:
[color=]self
.
[color=]quality_var
.
[color=]set
(
[color=]quality
)
[color=]frame_rate
[color=]=
[color=]config
.get(
[color=]"frame_rate"
,
[color=]30
)
[color=]if
[color=]5
[color=]frame_rate
[color=]60
:
[color=]self
.
[color=]fps_var
.
[color=]set
(
[color=]frame_rate
)
[color=]resolution
[color=]=
[color=]config
.get(
[color=]"resolution"
,
[color=]0.7
)
[color=]if
[color=]0.3
[color=]resolution
[color=]1.0
:
[color=]self
.
[color=]res_var
.
[color=]set
(
[color=]resolution
)
[color=]self
.
[color=]status_var
.
[color=]set
(
[color=]"已加载上次的设置"
)
[color=]except
[color=]Exception
[color=]as
[color=]e
:
[color=]self
.
[color=]status_var
.
[color=]set
(
[color=]f
[color=]"加载配置失败:
[color=]{
[color=]str
(
[color=]e
)
[color=]}
[color=]"
)
[color=]def
[color=]save_config
(
[color=]self
):
[color=]"""保存当前设置到配置文件"""
[color=]config_path
[color=]=
[color=]os
.
[color=]path
.
[color=]join
(
[color=]os
.
[color=]path
.
[color=]expanduser
(
[color=]"~"
),
[color=]".screen_mirror_config.json"
)
[color=]try
:
[color=]config
[color=]=
{
[color=]"last_screen"
:
[color=]self
.
[color=]screen_var
.
[color=]get
(),
[color=]"quality"
:
[color=]self
.
[color=]quality_var
.
[color=]get
(),
[color=]"frame_rate"
:
[color=]self
.
[color=]fps_var
.
[color=]get
(),
[color=]"resolution"
:
[color=]self
.
[color=]res_var
.
[color=]get
()
}
[color=]os
.
[color=]makedirs
(
[color=]os
.
[color=]path
.
[color=]dirname
(
[color=]config_path
),
[color=]exist_ok
[color=]=
[color=]True
)
[color=]with
[color=]open
(
[color=]config_path
,
[color=]"w"
)
[color=]as
[color=]f
:
[color=]json
.
[color=]dump
(
[color=]config
,
[color=]f
)
[color=]except
[color=]Exception
[color=]as
[color=]e
:
[color=]self
.
[color=]status_var
.
[color=]set
(
[color=]f
[color=]"保存配置失败:
[color=]{
[color=]str
(
[color=]e
)
[color=]}
[color=]"
)
[color=]def
[color=]create_widgets
(
[color=]self
):
[color=]"""创建UI界面"""
[color=]# 标题
[color=]title_label
[color=]=
[color=]ttk
.
[color=]Label
(
[color=]self
.
[color=]root
,
[color=]text
[color=]=
[color=]"低延迟屏幕投屏工具"
,
[color=]font
[color=]=
(
[color=]"Arial"
,
[color=]16
,
[color=]"bold"
))
[color=]title_label
.
[color=]pack
(
[color=]pady
[color=]=
[color=]10
)
[color=]# 屏幕选择
[color=]screen_frame
[color=]=
[color=]ttk
.
[color=]LabelFrame
(
[color=]self
.
[color=]root
,
[color=]text
[color=]=
[color=]"选择投屏屏幕"
)
[color=]screen_frame
.
[color=]pack
(
[color=]pady
[color=]=
[color=]5
,
[color=]padx
[color=]=
[color=]20
,
[color=]fill
[color=]=
[color=]"x"
)
[color=]self
.
[color=]screen_var
[color=]=
[color=]tk
.
[color=]IntVar
(
[color=]value
[color=]=
[color=]1
)
[color=]screens
[color=]=
[
[color=]"主屏幕"
,
[color=]"屏幕2"
,
[color=]"屏幕3"
,
[color=]"屏幕4"
]
[color=]for
[color=]i
,
[color=]screen
[color=]in
[color=]enumerate
(
[color=]screens
):
[color=]rb
[color=]=
[color=]ttk
.
[color=]Radiobutton
(
[color=]screen_frame
,
[color=]text
[color=]=
[color=]screen
,
[color=]variable
[color=]=
[color=]self
.
[color=]screen_var
,
[color=]value
[color=]=
[color=]i
[color=]+
[color=]1
,
[color=]command
[color=]=
[color=]self
.
[color=]save_config
)
[color=]rb
.
[color=]grid
(
[color=]row
[color=]=
[color=]0
,
[color=]column
[color=]=
[color=]i
,
[color=]padx
[color=]=
[color=]10
,
[color=]pady
[color=]=
[color=]5
)
[color=]# 性能设置
[color=]perf_frame
[color=]=
[color=]ttk
.
[color=]LabelFrame
(
[color=]self
.
[color=]root
,
[color=]text
[color=]=
[color=]"性能设置"
)
[color=]perf_frame
.
[color=]pack
(
[color=]pady
[color=]=
[color=]5
,
[color=]padx
[color=]=
[color=]20
,
[color=]fill
[color=]=
[color=]"x"
)
[color=]# 图像质量
[color=]quality_frame
[color=]=
[color=]ttk
.
[color=]Frame
(
[color=]perf_frame
)
[color=]quality_frame
.
[color=]pack
(
[color=]fill
[color=]=
[color=]"x"
,
[color=]padx
[color=]=
[color=]10
,
[color=]pady
[color=]=
[color=]5
)
[color=]ttk
.
[color=]Label
(
[color=]quality_frame
,
[color=]text
[color=]=
[color=]"图像质量:"
).
[color=]pack
(
[color=]side
[color=]=
[color=]"left"
)
[color=]self
.
[color=]quality_var
[color=]=
[color=]tk
.
[color=]IntVar
(
[color=]value
[color=]=
[color=]70
)
[color=]quality_scale
[color=]=
[color=]ttk
.
[color=]Scale
(
[color=]quality_frame
,
[color=]from_
[color=]=
[color=]30
,
[color=]to
[color=]=
[color=]95
,
[color=]variable
[color=]=
[color=]self
.
[color=]quality_var
,
[color=]orient
[color=]=
[color=]"horizontal"
,
[color=]length
[color=]=
[color=]200
,
[color=]command
[color=]=
[color=]lambda
[color=]_
:
[color=]self
.
[color=]save_config
()
)
[color=]quality_scale
.
[color=]pack
(
[color=]side
[color=]=
[color=]"left"
,
[color=]padx
[color=]=
[color=]10
)
[color=]ttk
.
[color=]Label
(
[color=]quality_frame
,
[color=]textvariable
[color=]=
[color=]self
.
[color=]quality_var
).
[color=]pack
(
[color=]side
[color=]=
[color=]"left"
)
[color=]# 帧率
[color=]fps_frame
[color=]=
[color=]ttk
.
[color=]Frame
(
[color=]perf_frame
)
[color=]fps_frame
.
[color=]pack
(
[color=]fill
[color=]=
[color=]"x"
,
[color=]padx
[color=]=
[color=]10
,
[color=]pady
[color=]=
[color=]5
)
[color=]ttk
.
[color=]Label
(
[color=]fps_frame
,
[color=]text
[color=]=
[color=]"帧率:"
).
[color=]pack
(
[color=]side
[color=]=
[color=]"left"
)
[color=]self
.
[color=]fps_var
[color=]=
[color=]tk
.
[color=]IntVar
(
[color=]value
[color=]=
[color=]30
)
[color=]fps_scale
[color=]=
[color=]ttk
.
[color=]Scale
(
[color=]fps_frame
,
[color=]from_
[color=]=
[color=]5
,
[color=]to
[color=]=
[color=]60
,
[color=]variable
[color=]=
[color=]self
.
[color=]fps_var
,
[color=]orient
[color=]=
[color=]"horizontal"
,
[color=]length
[color=]=
[color=]200
,
[color=]command
[color=]=
[color=]lambda
[color=]_
:
[color=]self
.
[color=]save_config
()
)
[color=]fps_scale
.
[color=]pack
(
[color=]side
[color=]=
[color=]"left"
,
[color=]padx
[color=]=
[color=]10
)
[color=]ttk
.
[color=]Label
(
[color=]fps_frame
,
[color=]textvariable
[color=]=
[color=]self
.
[color=]fps_var
).
[color=]pack
(
[color=]side
[color=]=
[color=]"left"
)
[color=]# 分辨率
[color=]res_frame
[color=]=
[color=]ttk
.
[color=]Frame
(
[color=]perf_frame
)
[color=]res_frame
.
[color=]pack
(
[color=]fill
[color=]=
[color=]"x"
,
[color=]padx
[color=]=
[color=]10
,
[color=]pady
[color=]=
[color=]5
)
[color=]ttk
.
[color=]Label
(
[color=]res_frame
,
[color=]text
[color=]=
[color=]"分辨率:"
).
[color=]pack
(
[color=]side
[color=]=
[color=]"left"
)
[color=]self
.
[color=]res_var
[color=]=
[color=]tk
.
[color=]DoubleVar
(
[color=]value
[color=]=
[color=]0.7
)
[color=]res_scale
[color=]=
[color=]ttk
.
[color=]Scale
(
[color=]res_frame
,
[color=]from_
[color=]=
[color=]0.3
,
[color=]to
[color=]=
[color=]1.0
,
[color=]variable
[color=]=
[color=]self
.
[color=]res_var
,
[color=]orient
[color=]=
[color=]"horizontal"
,
[color=]length
[color=]=
[color=]200
,
[color=]command
[color=]=
[color=]lambda
[color=]_
:
[color=]self
.
[color=]save_config
()
)
[color=]res_scale
.
[color=]pack
(
[color=]side
[color=]=
[color=]"left"
,
[color=]padx
[color=]=
[color=]10
)
[color=]ttk
.
[color=]Label
(
[color=]res_frame
,
[color=]textvariable
[color=]=
[color=]self
.
[color=]res_var
).
[color=]pack
(
[color=]side
[color=]=
[color=]"left"
)
[color=]# 控制按钮
[color=]button_frame
[color=]=
[color=]ttk
.
[color=]Frame
(
[color=]self
.
[color=]root
)
[color=]button_frame
.
[color=]pack
(
[color=]pady
[color=]=
[color=]10
)
[color=]self
.
[color=]start_button
[color=]=
[color=]ttk
.
[color=]Button
(
[color=]button_frame
,
[color=]text
[color=]=
[color=]"启动投屏"
,
[color=]command
[color=]=
[color=]self
.
[color=]start_mirroring
,
[color=]width
[color=]=
[color=]15
)
[color=]self
.
[color=]start_button
.
[color=]grid
(
[color=]row
[color=]=
[color=]0
,
[color=]column
[color=]=
[color=]0
,
[color=]padx
[color=]=
[color=]10
)
[color=]self
.
[color=]stop_button
[color=]=
[color=]ttk
.
[color=]Button
(
[color=]button_frame
,
[color=]text
[color=]=
[color=]"停止投屏"
,
[color=]command
[color=]=
[color=]self
.
[color=]stop_mirroring
,
[color=]state
[color=]=
[color=]"disabled"
,
[color=]width
[color=]=
[color=]15
)
[color=]self
.
[color=]stop_button
.
[color=]grid
(
[color=]row
[color=]=
[color=]0
,
[color=]column
[color=]=
[color=]1
,
[color=]padx
[color=]=
[color=]10
)
[color=]# 链接显示
[color=]link_frame
[color=]=
[color=]ttk
.
[color=]LabelFrame
(
[color=]self
.
[color=]root
,
[color=]text
[color=]=
[color=]"投屏链接"
)
[color=]link_frame
.
[color=]pack
(
[color=]pady
[color=]=
[color=]5
,
[color=]padx
[color=]=
[color=]20
,
[color=]fill
[color=]=
[color=]"x"
)
[color=]self
.
[color=]link_var
[color=]=
[color=]tk
.
[color=]StringVar
(
[color=]value
[color=]=
[color=]"请先启动投屏"
)
[color=]link_label
[color=]=
[color=]ttk
.
[color=]Label
(
[color=]link_frame
,
[color=]textvariable
[color=]=
[color=]self
.
[color=]link_var
,
[color=]font
[color=]=
(
[color=]"Arial"
,
[color=]10
),
[color=]anchor
[color=]=
[color=]"center"
)
[color=]link_label
.
[color=]pack
(
[color=]pady
[color=]=
[color=]5
,
[color=]padx
[color=]=
[color=]10
)
[color=]# 复制链接按钮
[color=]copy_button
[color=]=
[color=]ttk
.
[color=]Button
(
[color=]link_frame
,
[color=]text
[color=]=
[color=]"复制链接"
,
[color=]command
[color=]=
[color=]self
.
[color=]copy_link
,
[color=]width
[color=]=
[color=]10
)
[color=]copy_button
.
[color=]pack
(
[color=]pady
[color=]=
[color=]5
)
[color=]# 性能信息
[color=]perf_info_frame
[color=]=
[color=]ttk
.
[color=]LabelFrame
(
[color=]self
.
[color=]root
,
[color=]text
[color=]=
[color=]"性能信息"
)
[color=]perf_info_frame
.
[color=]pack
(
[color=]pady
[color=]=
[color=]5
,
[color=]padx
[color=]=
[color=]20
,
[color=]fill
[color=]=
[color=]"x"
)
[color=]self
.
[color=]fps_info_var
[color=]=
[color=]tk
.
[color=]StringVar
(
[color=]value
[color=]=
[color=]"FPS: --"
)
[color=]self
.
[color=]latency_var
[color=]=
[color=]tk
.
[color=]StringVar
(
[color=]value
[color=]=
[color=]"延迟: --"
)
[color=]self
.
[color=]size_var
[color=]=
[color=]tk
.
[color=]StringVar
(
[color=]value
[color=]=
[color=]"帧大小: --"
)
[color=]ttk
.
[color=]Label
(
[color=]perf_info_frame
,
[color=]textvariable
[color=]=
[color=]self
.
[color=]fps_info_var
).
[color=]pack
(
[color=]anchor
[color=]=
[color=]"w"
,
[color=]padx
[color=]=
[color=]10
,
[color=]pady
[color=]=
[color=]2
)
[color=]ttk
.
[color=]Label
(
[color=]perf_info_frame
,
[color=]textvariable
[color=]=
[color=]self
.
[color=]latency_var
).
[color=]pack
(
[color=]anchor
[color=]=
[color=]"w"
,
[color=]padx
[color=]=
[color=]10
,
[color=]pady
[color=]=
[color=]2
)
[color=]ttk
.
[color=]Label
(
[color=]perf_info_frame
,
[color=]textvariable
[color=]=
[color=]self
.
[color=]size_var
).
[color=]pack
(
[color=]anchor
[color=]=
[color=]"w"
,
[color=]padx
[color=]=
[color=]10
,
[color=]pady
[color=]=
[color=]2
)
[color=]# 联系信息
[color=]contact_frame
[color=]=
[color=]ttk
.
[color=]Frame
(
[color=]self
.
[color=]root
)
[color=]contact_frame
.
[color=]pack
(
[color=]pady
[color=]=
[color=]5
,
[color=]padx
[color=]=
[color=]20
,
[color=]fill
[color=]=
[color=]"x"
)
[color=]contact_label
[color=]=
[color=]ttk
.
[color=]Label
(
[color=]contact_frame
,
[color=]text
[color=]=
[color=]"来自吾爱破解原创 52pojie.cn 如有问题请联系开发者VX: SoullesFox"
,
[color=]font
[color=]=
(
[color=]"Arial"
,
[color=]10
,
[color=]"bold"
),
[color=]foreground
[color=]=
[color=]"red"
,
[color=]anchor
[color=]=
[color=]"center"
)
[color=]contact_label
.
[color=]pack
(
[color=]fill
[color=]=
[color=]"x"
)
[color=]# 状态栏
[color=]self
.
[color=]status_var
[color=]=
[color=]tk
.
[color=]StringVar
(
[color=]value
[color=]=
[color=]"就绪"
)
[color=]status_bar
[color=]=
[color=]ttk
.
[color=]Label
(
[color=]self
.
[color=]root
,
[color=]textvariable
[color=]=
[color=]self
.
[color=]status_var
,
[color=]relief
[color=]=
[color=]"sunken"
,
[color=]anchor
[color=]=
[color=]"w"
)
[color=]status_bar
.
[color=]pack
(
[color=]side
[color=]=
[color=]"bottom"
,
[color=]fill
[color=]=
[color=]"x"
)
[color=]def
[color=]add_firewall_rule
(
[color=]self
):
[color=]"""添加防火墙规则允许端口5000"""
[color=]try
:
[color=]command
[color=]=
[color=]f
[color=]'netsh advfirewall firewall show rule name="ScreenMirrorPort5000"'
[color=]result
[color=]=
[color=]subprocess
.
[color=]run
(
[color=]command
,
[color=]capture_output
[color=]=
[color=]True
,
[color=]text
[color=]=
[color=]True
,
[color=]shell
[color=]=
[color=]True
)
[color=]if
[color=]"没有规则"
[color=]in
[color=]result
.
[color=]stdout
:
[color=]command
[color=]=
(
[color=]'netsh advfirewall firewall add rule name="ScreenMirrorPort5000" '
[color=]'dir=in action=allow protocol=TCP localport=5000'
)
[color=]subprocess
.
[color=]run
(
[color=]command
,
[color=]shell
[color=]=
[color=]True
)
[color=]self
.
[color=]status_var
.
[color=]set
(
[color=]"已添加防火墙规则"
)
[color=]except
[color=]Exception
[color=]as
[color=]e
:
[color=]self
.
[color=]status_var
.
[color=]set
(
[color=]f
[color=]"防火墙设置失败:
[color=]{
[color=]str
(
[color=]e
)
[color=]}
[color=]"
)
[color=]def
[color=]copy_link
(
[color=]self
):
[color=]"""复制链接到剪贴板"""
[color=]if
[color=]self
.
[color=]link_var
.
[color=]get
()
[color=]!=
[color=]"请先启动投屏"
:
[color=]self
.
[color=]root
.clipboard_clear()
[color=]self
.
[color=]root
.clipboard_append(
[color=]self
.
[color=]link_var
.
[color=]get
())
[color=]self
.
[color=]status_var
.
[color=]set
(
[color=]"链接已复制到剪贴板"
)
[color=]def
[color=]start_mirroring
(
[color=]self
):
[color=]"""启动投屏服务"""
[color=]if
[color=]self
.
[color=]mirroring
:
[color=]return
[color=]self
.
[color=]mirroring
[color=]=
[color=]True
[color=]self
.
[color=]start_button
.
[color=]config
(
[color=]state
[color=]=
[color=]"disabled"
)
[color=]self
.
[color=]stop_button
.
[color=]config
(
[color=]state
[color=]=
[color=]"enabled"
)
[color=]self
.
[color=]status_var
.
[color=]set
(
[color=]"loading..."
)
[color=]# 获取当前设置
[color=]self
.
[color=]quality
[color=]=
[color=]self
.
[color=]quality_var
.
[color=]get
()
[color=]self
.
[color=]frame_rate
[color=]=
[color=]self
.
[color=]fps_var
.
[color=]get
()
[color=]self
.
[color=]resolution
[color=]=
[color=]self
.
[color=]res_var
.
[color=]get
()
[color=]# 重置性能计数器
[color=]self
.
[color=]frame_count
[color=]=
[color=]0
[color=]self
.
[color=]start_time
[color=]=
[color=]time
.
[color=]time
()
[color=]# 创建Flask应用
[color=]self
.
[color=]flask_app
[color=]=
[color=]Flask
(
[color=]__name__
)
[color=]# 添加路由
[color=]@
[color=]self
[color=].
[color=]flask_app
[color=].
[color=]route
(
[color=]'/'
)
[color=]def
[color=]index
():
[color=]return
[color=]"""
[color=] body {
[color=] text-align: center;
[color=] background-color: #000;
[color=] margin: 0;
[color=] padding: 0;
[color=] overflow: hidden;
[color=] }
[color=] h1 {
[color=] color: #333;
[color=] margin-top: 10px;
[color=] }
[color=] img {
[color=] max-width: 100%;
[color=] max-height: 90vh;
[color=] box-shadow: 0 0 10px rgba(0,0,0,0.3);
[color=] cursor: pointer;
[color=] }
[color=] .status {
[color=] margin: 10px;
[color=] padding: 8px;
[color=] background-color: #e0e0e0;
[color=] border-radius: 5px;
[color=] }
[color=] .stats {
[color=] margin: 5px;
[color=] padding: 5px;
[color=] background-color: #d0d0d0;
[color=] border-radius: 5px;
[color=] display: inline-block;
[color=] }
[color=] .controls {
[color=] position: fixed;
[color=] top: 10px;
[color=] right: 10px;
[color=] background: rgba(255, 255, 255, 0.7);
[color=] padding: 5px;
[color=] border-radius: 5px;
[color=] }
[color=] .fullscreen-btn {
[color=] background: #4CAF50;
[color=] color: white;
[color=] border: none;
[color=] padding: 5px 10px;
[color=] border-radius: 3px;
[color=] cursor: pointer;
[color=] }
[color=] .fullscreen-btn:hover {
[color=] background: #45a049;
[color=] }
全屏显示
正在连接...
FPS: -- |
延迟: --
[color=] """
[color=]@
[color=]self
[color=].
[color=]flask_app
[color=].
[color=]route
(
[color=]'/screen'
)
[color=]def
[color=]screen
():
[color=]# 获取客户端唯一ID
[color=]client_id
[color=]=
[color=]request
.
[color=]args
.
[color=]get
(
[color=]'cid'
,
[color=]''
)
[color=]# 生成实时帧
[color=]return
[color=]Response
(
[color=]self
.
[color=]generate_frames
(
[color=]client_id
),
[color=]mimetype
[color=]=
[color=]'multipart/x-mixed-replace; boundary=frame'
)
[color=]# 启动屏幕捕获线程
[color=]self
.
[color=]start_capture_thread
()
[color=]# 在后台线程中运行Flask服务器
[color=]self
.
[color=]server_thread
[color=]=
[color=]threading
.
[color=]Thread
(
[color=]target
[color=]=
[color=]self
.
[color=]run_server
,
[color=]daemon
[color=]=
[color=]True
)
[color=]self
.
[color=]server_thread
.
[color=]start
()
[color=]# 更新链接显示
[color=]port
[color=]=
[color=]5000
[color=]self
.
[color=]link_var
.
[color=]set
(
[color=]f
[color=]"http://
[color=]{
[color=]self
.
[color=]ip_address
[color=]}
[color=]:
[color=]{
[color=]port
[color=]}
[color=]"
)
[color=]self
.
[color=]status_var
.
[color=]set
(
[color=]f
[color=]"投屏已启动 - 正在监听端口
[color=]{
[color=]port
[color=]}
[color=]"
)
[color=]# 启动性能监控
[color=]self
.
[color=]root
.after(
[color=]1000
,
[color=]self
.
[color=]update_performance
)
[color=]def
[color=]start_capture_thread
(
[color=]self
):
[color=]"""启动屏幕捕获线程"""
[color=]if
[color=]self
.
[color=]capture_thread
[color=]and
[color=]self
.
[color=]capture_thread
.
[color=]is_alive
():
[color=]self
.
[color=]stop_capture
.
[color=]set
()
[color=]self
.
[color=]capture_thread
.
[color=]join
(
[color=]timeout
[color=]=
[color=]1.0
)
[color=]# 清空队列
[color=]while
[color=]not
[color=]self
.
[color=]frame_queue
.
[color=]empty
():
[color=]try
:
[color=]self
.
[color=]frame_queue
.
[color=]get_nowait
()
[color=]except
[color=]queue
.
[color=]Empty
:
[color=]break
[color=]# 重置停止标志
[color=]self
.
[color=]stop_capture
.
[color=]clear
()
[color=]# 创建新线程
[color=]self
.
[color=]capture_thread
[color=]=
[color=]threading
.
[color=]Thread
(
[color=]target
[color=]=
[color=]self
.
[color=]capture_screen
,
[color=]args
[color=]=
(
[color=]self
.
[color=]screen_var
.
[color=]get
(),
[color=]self
.
[color=]quality
,
[color=]self
.
[color=]frame_rate
,
[color=]self
.
[color=]resolution
),
[color=]daemon
[color=]=
[color=]True
)
[color=]self
.
[color=]capture_thread
.
[color=]start
()
[color=]def
[color=]capture_screen
(
[color=]self
,
[color=]monitor_idx
,
[color=]quality
,
[color=]frame_rate
,
[color=]resolution
):
[color=]"""屏幕捕获线程 - 使用OpenCV优化版本"""
[color=]try
:
[color=]# 获取显示器信息
[color=]monitor
[color=]=
[color=]self
.
[color=]monitors
[
[color=]monitor_idx
]
[color=]# 计算目标尺寸
[color=]width
[color=]=
[color=]int
(
[color=]monitor
[
[color=]'width'
]
[color=]*
[color=]resolution
)
[color=]height
[color=]=
[color=]int
(
[color=]monitor
[
[color=]'height'
]
[color=]*
[color=]resolution
)
[color=]# 计算帧间隔
[color=]frame_interval
[color=]=
[color=]1.0
[color=]/
[color=]frame_rate
[color=]# 初始化性能计数器
[color=]last_time
[color=]=
[color=]time
.
[color=]time
()
[color=]frame_counter
[color=]=
[color=]0
[color=]# 使用OpenCV进行高效捕获
[color=]with
[color=]mss
.
[color=]mss
()
[color=]as
[color=]sct
:
[color=]while
[color=]not
[color=]self
.
[color=]stop_capture
.
[color=]is_set
():
[color=]start_time
[color=]=
[color=]time
.
[color=]time
()
[color=]try
:
[color=]# 捕获屏幕
[color=]screenshot
[color=]=
[color=]sct
.
[color=]grab
(
[color=]monitor
)
[color=]# 转换为numpy数组
[color=]img
[color=]=
[color=]np
.
[color=]array
(
[color=]screenshot
)
[color=]# 调整分辨率
[color=]if
[color=]resolution
[color=]1.0
:
[color=]# 使用OpenCV进行快速缩放
[color=]img
[color=]=
[color=]cv2
.
[color=]resize
(
[color=]img
, (
[color=]width
,
[color=]height
),
[color=]interpolation
[color=]=
[color=]cv2
.
[color=]INTER_AREA
)
[color=]# 转换为JPEG - 使用OpenCV高效编码
[color=]_
,
[color=]jpeg_data
[color=]=
[color=]cv2
.
[color=]imencode
(
[color=]'.jpg'
,
[color=]img
, [
[color=]int
(
[color=]cv2
.
[color=]IMWRITE_JPEG_QUALITY
),
[color=]quality
])
[color=]# 放入队列(如果队列已满则替换)
[color=]try
:
[color=]self
.
[color=]frame_queue
.
[color=]put
(
[color=]jpeg_data
.
[color=]tobytes
(),
[color=]block
[color=]=
[color=]False
)
[color=]except
[color=]queue
.
[color=]Full
:
[color=]try
:
[color=]self
.
[color=]frame_queue
.
[color=]get_nowait
()
[color=]except
[color=]queue
.
[color=]Empty
:
[color=]pass
[color=]self
.
[color=]frame_queue
.
[color=]put
(
[color=]jpeg_data
.
[color=]tobytes
(),
[color=]block
[color=]=
[color=]False
)
[color=]# 控制帧率 - 使用更精确的方法
[color=]elapsed
[color=]=
[color=]time
.
[color=]time
()
[color=]-
[color=]start_time
[color=]sleep_time
[color=]=
[color=]max
(
[color=]0
,
[color=]frame_interval
[color=]-
[color=]elapsed
)
[color=]# 如果处理时间超过帧间隔,跳过下一帧
[color=]if
[color=]sleep_time
[color=]>
[color=]0
:
[color=]time
.
[color=]sleep
(
[color=]sleep_time
)
[color=]# 性能计数
[color=]frame_counter
[color=]+=
[color=]1
[color=]current_time
[color=]=
[color=]time
.
[color=]time
()
[color=]if
[color=]current_time
[color=]-
[color=]last_time
[color=]>=
[color=]1.0
:
[color=]actual_fps
[color=]=
[color=]frame_counter
[color=]/
(
[color=]current_time
[color=]-
[color=]last_time
)
[color=]self
.
[color=]status_var
.
[color=]set
(
[color=]f
[color=]"捕获中:
[color=]{
[color=]actual_fps
[color=]:.1f}
[color=] FPS"
)
[color=]last_time
[color=]=
[color=]current_time
[color=]frame_counter
[color=]=
[color=]0
[color=]except
[color=]Exception
[color=]as
[color=]e
:
[color=]self
.
[color=]status_var
.
[color=]set
(
[color=]f
[color=]"捕获错误:
[color=]{
[color=]str
(
[color=]e
)
[color=]}
[color=]"
)
[color=]time
.
[color=]sleep
(
[color=]0.1
)
[color=]except
[color=]Exception
[color=]as
[color=]e
:
[color=]self
.
[color=]status_var
.
[color=]set
(
[color=]f
[color=]"捕获初始化错误:
[color=]{
[color=]str
(
[color=]e
)
[color=]}
[color=]"
)
[color=]def
[color=]update_performance
(
[color=]self
):
[color=]"""更新性能信息"""
[color=]if
[color=]self
.
[color=]mirroring
:
[color=]# 计算FPS
[color=]elapsed
[color=]=
[color=]time
.
[color=]time
()
[color=]-
[color=]self
.
[color=]start_time
[color=]fps
[color=]=
[color=]self
.
[color=]frame_count
[color=]/
[color=]elapsed
[color=]if
[color=]elapsed
[color=]>
[color=]0
[color=]else
[color=]0
[color=]self
.
[color=]fps_info_var
.
[color=]set
(
[color=]f
[color=]"FPS:
[color=]{
[color=]fps
[color=]:.1f}
[color=]"
)
[color=]# 重置计数器
[color=]self
.
[color=]frame_count
[color=]=
[color=]0
[color=]self
.
[color=]start_time
[color=]=
[color=]time
.
[color=]time
()
[color=]# 定期检查
[color=]self
.
[color=]root
.after(
[color=]1000
,
[color=]self
.
[color=]update_performance
)
[color=]def
[color=]stop_mirroring
(
[color=]self
):
[color=]"""停止投屏服务"""
[color=]if
[color=]not
[color=]self
.
[color=]mirroring
:
[color=]return
[color=]self
.
[color=]mirroring
[color=]=
[color=]False
[color=]self
.
[color=]start_button
.
[color=]config
(
[color=]state
[color=]=
[color=]"enabled"
)
[color=]self
.
[color=]stop_button
.
[color=]config
(
[color=]state
[color=]=
[color=]"disabled"
)
[color=]self
.
[color=]status_var
.
[color=]set
(
[color=]"投屏已停止"
)
[color=]# 停止捕获线程
[color=]self
.
[color=]stop_capture
.
[color=]set
()
[color=]if
[color=]self
.
[color=]capture_thread
[color=]and
[color=]self
.
[color=]capture_thread
.
[color=]is_alive
():
[color=]self
.
[color=]capture_thread
.
[color=]join
(
[color=]timeout
[color=]=
[color=]1.0
)
[color=]def
[color=]generate_frames
(
[color=]self
,
[color=]client_id
):
[color=]"""生成屏幕帧(JPEG格式)"""
[color=]while
[color=]self
.
[color=]mirroring
:
[color=]try
:
[color=]# 从队列获取帧数据
[color=]jpeg_data
[color=]=
[color=]self
.
[color=]frame_queue
.
[color=]get
(
[color=]timeout
[color=]=
[color=]0.1
)
[color=]# 缩短超时时间
[color=]# 保存最后一帧
[color=]self
.
[color=]last_frame
[color=]=
[color=]jpeg_data
[color=]# 更新帧计数
[color=]self
.
[color=]frame_count
[color=]+=
[color=]1
[color=]# 更新帧大小信息
[color=]self
.
[color=]size_var
.
[color=]set
(
[color=]f
[color=]"帧大小:
[color=]{
[color=]len
(
[color=]jpeg_data
)
[color=]/
[color=]1024
[color=]:.1f}
[color=] KB"
)
[color=]# 生成帧
[color=]yield
(
[color=]b
[color=]'--frame
[color=]\r\n
[color=]'
[color=]b
[color=]'Content-Type: image/jpeg
[color=]\r\n\r\n
[color=]'
[color=]+
[color=]jpeg_data
[color=]+
[color=]b
[color=]'
[color=]\r\n
[color=]'
)
[color=]except
[color=]queue
.
[color=]Empty
:
[color=]# 队列为空,等待下一帧
[color=]time
.
[color=]sleep
(
[color=]0.01
)
[color=]except
[color=]Exception
[color=]as
[color=]e
:
[color=]self
.
[color=]status_var
.
[color=]set
(
[color=]f
[color=]"传输错误:
[color=]{
[color=]str
(
[color=]e
)
[color=]}
[color=]"
)
[color=]time
.
[color=]sleep
(
[color=]0.1
)
[color=]# 投屏停止后发送黑屏图像
[color=]while
[color=]True
:
[color=]yield
(
[color=]b
[color=]'--frame
[color=]\r\n
[color=]'
[color=]b
[color=]'Content-Type: image/jpeg
[color=]\r\n\r\n
[color=]'
[color=]+
[color=]self
.
[color=]black_image
[color=]+
[color=]b
[color=]'
[color=]\r\n
[color=]'
)
[color=]time
.
[color=]sleep
(
[color=]0.1
)
[color=]def
[color=]run_server
(
[color=]self
):
[color=]"""运行Flask服务器"""
[color=]try
:
[color=]self
.
[color=]flask_app
.
[color=]run
(
[color=]host
[color=]=
[color=]'0.0.0.0'
,
[color=]port
[color=]=
[color=]5000
,
[color=]threaded
[color=]=
[color=]True
,
[color=]use_reloader
[color=]=
[color=]False
)
[color=]except
[color=]Exception
[color=]as
[color=]e
:
[color=]self
.
[color=]status_var
.
[color=]set
(
[color=]f
[color=]"服务器错误:
[color=]{
[color=]str
(
[color=]e
)
[color=]}
[color=]"
)
[color=]self
.
[color=]mirroring
[color=]=
[color=]False
[color=]self
.
[color=]start_button
.
[color=]config
(
[color=]state
[color=]=
[color=]"enabled"
)
[color=]self
.
[color=]stop_button
.
[color=]config
(
[color=]state
[color=]=
[color=]"disabled"
)
[color=]def
[color=]is_admin
():
[color=]"""检查是否以管理员权限运行"""
[color=]try
:
[color=]return
[color=]ctypes
.
[color=]windll
.shell32.IsUserAnAdmin()
[color=]except
:
[color=]return
[color=]False
[color=]if
[color=]__name__
[color=]==
[color=]"__main__"
:
[color=]# 检查是否以管理员权限运行
[color=]if
[color=]os
.
[color=]name
[color=]==
[color=]'nt'
[color=]and
[color=]not
[color=]is_admin
():
[color=]# 重新以管理员权限运行
[color=]ctypes
.
[color=]windll
.shell32.ShellExecuteW(
[color=]None
,
[color=]"runas"
,
[color=]sys
.
[color=]executable
,
[color=]" "
.
[color=]join
(
[color=]sys
.
[color=]argv
),
[color=]None
,
[color=]1
)
[color=]sys
.
[color=]exit
(
[color=]0
)
[color=]root
[color=]=
[color=]tk
.
[color=]Tk
()
[color=]app
[color=]=
[color=]ScreenMirrorApp
(
[color=]root
)
[color=]root
.
[color=]protocol
(
[color=]"WM_DELETE_WINDOW"
,
[color=]lambda
: (
[color=]app
.
[color=]stop_mirroring
(),
[color=]root
.
[color=]destroy
()))
[color=]root
.
[color=]mainloop
()

