修复 Rust 程序中文乱码问题 - 添加 UTF-8 编码设置
This commit is contained in:
251
push_screen_rust/src/main.rs
Normal file
251
push_screen_rust/src/main.rs
Normal file
@@ -0,0 +1,251 @@
|
||||
use eframe::egui;
|
||||
use std::process::{Command, Stdio};
|
||||
use std::sync::mpsc::{channel, Receiver};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use tracing::{info, error};
|
||||
|
||||
// Windows API 用于设置控制台编码
|
||||
#[cfg(windows)]
|
||||
extern "system" {
|
||||
fn SetConsoleOutputCP(wCodePageID: u32) -> i32;
|
||||
fn SetConsoleCP(wCodePageID: u32) -> i32;
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
const CP_UTF8: u32 = 65001;
|
||||
|
||||
fn set_utf8_encoding() {
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
SetConsoleCP(CP_UTF8);
|
||||
}
|
||||
}
|
||||
|
||||
struct PushScreenApp {
|
||||
server_ip: String,
|
||||
server_port: String,
|
||||
ffmpeg_path: String,
|
||||
device_name: String,
|
||||
status: String,
|
||||
is_streaming: bool,
|
||||
rx: Receiver<StatusMessage>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum StatusMessage {
|
||||
Status(String),
|
||||
Error(String),
|
||||
}
|
||||
|
||||
impl PushScreenApp {
|
||||
fn new(_cc: &eframe::CreationContext<'_>) -> Self {
|
||||
let (tx, rx) = channel();
|
||||
|
||||
// 启动状态监控线程
|
||||
let tx_clone = tx.clone();
|
||||
thread::spawn(move || {
|
||||
loop {
|
||||
if let Err(e) = tx_clone.send(StatusMessage::Status("运行中".to_string())) {
|
||||
error!("状态发送失败: {}", e);
|
||||
break;
|
||||
}
|
||||
thread::sleep(Duration::from_secs(5));
|
||||
}
|
||||
});
|
||||
|
||||
Self {
|
||||
server_ip: "192.168.1.100".to_string(),
|
||||
server_port: "8080".to_string(),
|
||||
ffmpeg_path: r"C:\ffmpeg\bin\ffmpeg.exe".to_string(),
|
||||
device_name: "会议室主屏".to_string(),
|
||||
status: "就绪".to_string(),
|
||||
is_streaming: false,
|
||||
rx,
|
||||
}
|
||||
}
|
||||
|
||||
fn start_stream(&mut self) {
|
||||
if self.is_streaming {
|
||||
return;
|
||||
}
|
||||
|
||||
info!("开始推流: {}:{}", self.server_ip, self.server_port);
|
||||
|
||||
// 构建 FFmpeg 命令
|
||||
let output_url = format!(
|
||||
"rtmp://{}:{}/live/{}",
|
||||
self.server_ip, self.server_port, self.device_name
|
||||
);
|
||||
|
||||
let args = vec![
|
||||
"-f", "gdigrab",
|
||||
"-framerate", "30",
|
||||
"-i", "desktop",
|
||||
"-c:v", "libx264",
|
||||
"-preset", "ultrafast",
|
||||
"-tune", "zerolatency",
|
||||
"-f", "flv",
|
||||
&output_url,
|
||||
];
|
||||
|
||||
match Command::new(&self.ffmpeg_path)
|
||||
.args(&args)
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::null())
|
||||
.spawn()
|
||||
{
|
||||
Ok(mut child) => {
|
||||
info!("FFmpeg 进程启动成功, PID: {:?}", child.id());
|
||||
self.is_streaming = true;
|
||||
self.status = format!("推流中 - {}", self.device_name);
|
||||
|
||||
// 监控进程
|
||||
thread::spawn(move || {
|
||||
match child.wait() {
|
||||
Ok(status) => {
|
||||
info!("FFmpeg 进程结束: {:?}", status);
|
||||
}
|
||||
Err(e) => {
|
||||
error!("等待 FFmpeg 进程失败: {}", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
Err(e) => {
|
||||
error!("启动 FFmpeg 失败: {}", e);
|
||||
self.status = format!("错误: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn stop_stream(&mut self) {
|
||||
if !self.is_streaming {
|
||||
return;
|
||||
}
|
||||
|
||||
info!("停止推流");
|
||||
|
||||
// 查找并终止 FFmpeg 进程
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let _ = Command::new("taskkill")
|
||||
.args(&["/F", "/IM", "ffmpeg.exe"])
|
||||
.output();
|
||||
}
|
||||
|
||||
self.is_streaming = false;
|
||||
self.status = "已停止".to_string();
|
||||
}
|
||||
}
|
||||
|
||||
impl eframe::App for PushScreenApp {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
// 接收状态更新
|
||||
while let Ok(msg) = self.rx.try_recv() {
|
||||
match msg {
|
||||
StatusMessage::Status(s) => {
|
||||
if self.is_streaming {
|
||||
self.status = format!("推流中 - {}", s);
|
||||
}
|
||||
}
|
||||
StatusMessage::Error(e) => {
|
||||
self.status = format!("错误: {}", e);
|
||||
self.is_streaming = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
ui.heading("投屏源控制系统");
|
||||
ui.add_space(20.0);
|
||||
|
||||
// 服务器设置
|
||||
ui.group(|ui| {
|
||||
ui.label("服务器设置");
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("服务器 IP:");
|
||||
ui.text_edit_singleline(&mut self.server_ip);
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("端口:");
|
||||
ui.text_edit_singleline(&mut self.server_port);
|
||||
});
|
||||
});
|
||||
|
||||
ui.add_space(10.0);
|
||||
|
||||
// FFmpeg 设置
|
||||
ui.group(|ui| {
|
||||
ui.label("FFmpeg 设置");
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("FFmpeg 路径:");
|
||||
ui.text_edit_singleline(&mut self.ffmpeg_path);
|
||||
});
|
||||
});
|
||||
|
||||
ui.add_space(10.0);
|
||||
|
||||
// 设备设置
|
||||
ui.group(|ui| {
|
||||
ui.label("设备设置");
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("设备名称:");
|
||||
ui.text_edit_singleline(&mut self.device_name);
|
||||
});
|
||||
});
|
||||
|
||||
ui.add_space(20.0);
|
||||
|
||||
// 状态显示
|
||||
ui.group(|ui| {
|
||||
ui.label("状态:");
|
||||
ui.label(&self.status);
|
||||
});
|
||||
|
||||
ui.add_space(20.0);
|
||||
|
||||
// 控制按钮
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("开始推流").clicked() {
|
||||
self.start_stream();
|
||||
}
|
||||
|
||||
if ui.button("停止推流").clicked() {
|
||||
self.stop_stream();
|
||||
}
|
||||
|
||||
if ui.button("退出").clicked() {
|
||||
self.stop_stream();
|
||||
std::process::exit(0);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// 设置 UTF-8 编码,解决中文乱码问题
|
||||
set_utf8_encoding();
|
||||
|
||||
// 初始化日志
|
||||
tracing_subscriber::fmt::init();
|
||||
info!("应用程序启动");
|
||||
|
||||
let options = eframe::NativeOptions {
|
||||
viewport: egui::ViewportBuilder::default()
|
||||
.with_inner_size([520.0, 420.0])
|
||||
.with_resizable(false),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
if let Err(e) = eframe::run_native(
|
||||
"投屏源控制",
|
||||
options,
|
||||
Box::new(|cc| Box::new(PushScreenApp::new(cc))),
|
||||
) {
|
||||
eprintln!("应用程序错误: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user