news 2026/3/23 17:46:28

2.智梯云枢・全维管控广告系统——解决串口卡顿 + 优化稳定性

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
2.智梯云枢・全维管控广告系统——解决串口卡顿 + 优化稳定性

之前代码 不能停止 只能kill进程pid停止

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <signal.h> #include <dirent.h> #include <sys/types.h> #include <sys/wait.h> #include <pthread.h> #include <stdbool.h> #include <sys/stat.h> #define VIDEO_DIR "/userdata/videos" #define LOG_FILE "/tmp/ad_player.log" #define PID_FILE "/tmp/ad_player.pid" volatile sig_atomic_t stop_flag = 0; void signal_handler(int sig) { if (sig == SIGINT || sig == SIGTERM) { printf("接收到停止信号\n"); stop_flag = 1; } } // 获取视频文件列表 int get_video_files(char ***file_list) { DIR *dir; struct dirent *ent; int count = 0; dir = opendir(VIDEO_DIR); if (dir == NULL) { printf("无法打开视频目录: %s\n", VIDEO_DIR); return 0; } // 第一遍:计算文件数量 while ((ent = readdir(dir)) != NULL) { char *ext = strrchr(ent->d_name, '.'); if (ext && (strcmp(ext, ".mp4") == 0 || strcmp(ext, ".MP4") == 0 || strcmp(ext, ".avi") == 0 || strcmp(ext, ".mkv") == 0)) { count++; } } rewinddir(dir); // 分配内存 *file_list = malloc(count * sizeof(char *)); // 第二遍:存储文件名 int i = 0; while ((ent = readdir(dir)) != NULL && i < count) { char *ext = strrchr(ent->d_name, '.'); if (ext && (strcmp(ext, ".mp4") == 0 || strcmp(ext, ".MP4") == 0 || strcmp(ext, ".avi") == 0 || strcmp(ext, ".mkv") == 0)) { (*file_list)[i] = malloc(strlen(VIDEO_DIR) + strlen(ent->d_name) + 2); sprintf((*file_list)[i], "%s/%s", VIDEO_DIR, ent->d_name); i++; } } closedir(dir); return count; } // 播放单个视频 void play_video(const char *video_path) { char command[1024]; // 使用gst-play-1.0播放,使用kmssink用于MIPI屏幕 snprintf(command, sizeof(command), "gst-play-1.0 \"%s\" --videosink=kmssink --audiosink=alsasink --volume=0.8 2>> %s", video_path, LOG_FILE); printf("播放: %s\n", video_path); system(command); } // 保存PID到文件 void save_pid() { FILE *fp = fopen(PID_FILE, "w"); if (fp) { fprintf(fp, "%d\n", getpid()); fclose(fp); } } // 删除PID文件 void remove_pid() { remove(PID_FILE); } int main(int argc, char *argv[]) { printf("=== 电梯广告播放系统 ===\n"); printf("视频目录: %s\n", VIDEO_DIR); // 设置信号处理 signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); // 保存PID save_pid(); // 检查视频目录 DIR *dir = opendir(VIDEO_DIR); if (dir == NULL) { printf("错误: 视频目录不存在,创建目录...\n"); mkdir(VIDEO_DIR, 0755); printf("请将MP4视频文件放入: %s\n", VIDEO_DIR); remove_pid(); return 1; } closedir(dir); // 主循环 while (!stop_flag) { char **video_files = NULL; int video_count = get_video_files(&video_files); if (video_count == 0) { printf("没有找到视频文件,等待10秒...\n"); sleep(10); continue; } printf("找到 %d 个视频文件\n", video_count); // 循环播放所有视频 for (int i = 0; i < video_count && !stop_flag; i++) { if (video_files[i]) { play_video(video_files[i]); free(video_files[i]); } } if (video_files) { free(video_files); } printf("一轮播放完成\n"); } printf("停止播放系统\n"); remove_pid(); return 0; }

停止播放后终端卡顿

卡顿代码

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <signal.h> #include <dirent.h> #include <sys/types.h> #include <sys/wait.h> #include <pthread.h> #include <stdbool.h> #include <sys/stat.h> #include <fcntl.h> #include <termios.h> // 新增:终端模式控制头文件 #define VIDEO_DIR "/userdata/videos" #define LOG_FILE "/tmp/ad_player.log" #define PID_FILE "/tmp/ad_player.pid" volatile sig_atomic_t stop_flag = 0; pid_t play_child_pid = -1; struct termios orig_termios; // 新增:保存终端初始模式 // 新增:恢复终端初始模式(解决串口卡顿核心函数) void restore_terminal() { // 忽略恢复失败的情况(避免程序退出时崩溃) tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios); } // 信号处理函数(优化:恢复终端+强制退出) void signal_handler(int sig) { if (sig == SIGINT || sig == SIGTERM) { printf("\n接收到停止信号,正在终止播放...\n"); stop_flag = 1; // 终止播放子进程 if (play_child_pid > 0) { kill(play_child_pid, SIGKILL); waitpid(play_child_pid, NULL, WNOHANG); play_child_pid = -1; } // 关键:恢复终端模式,解决串口卡顿 restore_terminal(); remove(PID_FILE); // 清理PID文件 printf("播放系统已停止,串口已恢复正常\n"); exit(0); // 强制退出程序,避免阻塞 } } // 获取视频文件列表(原代码不变) int get_video_files(char ***file_list) { DIR *dir; struct dirent *ent; int count = 0; dir = opendir(VIDEO_DIR); if (dir == NULL) { printf("无法打开视频目录: %s\n", VIDEO_DIR); return 0; } while ((ent = readdir(dir)) != NULL) { char *ext = strrchr(ent->d_name, '.'); if (ext && (strcmp(ext, ".mp4") == 0 || strcmp(ext, ".MP4") == 0 || strcmp(ext, ".avi") == 0 || strcmp(ext, ".mkv") == 0)) { count++; } } rewinddir(dir); *file_list = malloc(count * sizeof(char *)); int i = 0; while ((ent = readdir(dir)) != NULL && i < count) { char *ext = strrchr(ent->d_name, '.'); if (ext && (strcmp(ext, ".mp4") == 0 || strcmp(ext, ".MP4") == 0 || strcmp(ext, ".avi") == 0 || strcmp(ext, ".mkv") == 0)) { (*file_list)[i] = malloc(strlen(VIDEO_DIR) + strlen(ent->d_name) + 2); sprintf((*file_list)[i], "%s/%s", VIDEO_DIR, ent->d_name); i++; } } closedir(dir); return count; } // 播放单个视频(原逻辑不变,仅优化日志重定向) void play_video(const char *video_path) { if (stop_flag) return; char *cmd_args[] = { "gst-play-1.0", (char *)video_path, "--videosink=kmssink", "--audiosink=alsasink", "--volume=0.8", NULL }; printf("播放: %s\n", video_path); play_child_pid = fork(); if (play_child_pid == 0) { // 重定向日志(优化:创建日志文件时设置权限) int log_fd = open(LOG_FILE, O_WRONLY | O_APPEND | O_CREAT, 0644); if (log_fd >= 0) { dup2(log_fd, STDERR_FILENO); close(log_fd); } execvp("gst-play-1.0", cmd_args); perror("执行播放命令失败"); exit(1); } else if (play_child_pid < 0) { perror("创建播放进程失败"); play_child_pid = -1; return; } // 非阻塞等待子进程,及时响应停止信号 while (play_child_pid > 0 && !stop_flag) { int status; pid_t ret = waitpid(play_child_pid, &status, WNOHANG); if (ret != 0) { play_child_pid = -1; break; } usleep(100000); } } // 保存PID到文件(原代码不变) void save_pid() { FILE *fp = fopen(PID_FILE, "w"); if (fp) { fprintf(fp, "%d\n", getpid()); fclose(fp); } } // 删除PID文件(原代码不变) void remove_pid() { remove(PID_FILE); } int main(int argc, char *argv[]) { // 第一步:保存终端初始模式(核心!) if (tcgetattr(STDIN_FILENO, &orig_termios) == -1) { perror("保存终端模式失败"); exit(1); } // 注册退出清理函数:即使程序异常退出,也会恢复终端 atexit(restore_terminal); printf("=== 电梯广告播放系统 ===\n"); printf("视频目录: %s\n", VIDEO_DIR); printf("提示:按 Ctrl+C 可立即停止播放并退出程序\n"); // 设置信号处理(支持Ctrl+C和kill命令) signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); // 保存PID save_pid(); // 检查视频目录(优化:退出时恢复终端) DIR *dir = opendir(VIDEO_DIR); if (dir == NULL) { printf("错误: 视频目录不存在,创建目录...\n"); mkdir(VIDEO_DIR, 0755); printf("请将MP4视频文件放入: %s\n", VIDEO_DIR); remove_pid(); restore_terminal(); // 恢复终端 return 1; } closedir(dir); // 主循环(原逻辑不变) while (!stop_flag) { char **video_files = NULL; int video_count = get_video_files(&video_files); if (video_count == 0) { printf("没有找到视频文件,等待10秒...\n"); sleep(10); continue; } printf("找到 %d 个视频文件\n", video_count); for (int i = 0; i < video_count && !stop_flag; i++) { if (video_files[i]) { play_video(video_files[i]); free(video_files[i]); } } if (video_files) { free(video_files); } if (!stop_flag) { printf("一轮播放完成,继续循环...\n"); } } // 正常退出时的清理 restore_terminal(); remove_pid(); printf("停止播放系统\n"); return 0; } 在这个代码的基础上改正卡顿 其他功能保留

核心原因:play_video函数只重定向了标准错误(STDERR_FILENO),但没有重定向标准输出(STDOUT_FILENO)。这会导致gst-play-1.0的输出(包括控制字符)仍然会发送到终端,从而造成卡顿。

最终不卡顿代码 按上下键可控制音量

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <signal.h> #include <dirent.h> #include <sys/types.h> #include <sys/wait.h> #include <pthread.h> #include <stdbool.h> #include <sys/stat.h> #include <fcntl.h> #include <termios.h> // 新增:终端模式控制头文件 #define VIDEO_DIR "/userdata/videos" #define LOG_FILE "/tmp/ad_player.log" #define PID_FILE "/tmp/ad_player.pid" volatile sig_atomic_t stop_flag = 0; pid_t play_child_pid = -1; struct termios orig_termios; // 新增:保存终端初始模式 // 新增:恢复终端初始模式(解决串口卡顿核心函数) void restore_terminal() { // 忽略恢复失败的情况(避免程序退出时崩溃) tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios); } // 信号处理函数(优化:恢复终端+强制退出) void signal_handler(int sig) { if (sig == SIGINT || sig == SIGTERM) { printf("\n接收到停止信号,正在终止播放...\n"); stop_flag = 1; // 终止播放子进程 if (play_child_pid > 0) { kill(play_child_pid, SIGKILL); waitpid(play_child_pid, NULL, WNOHANG); play_child_pid = -1; } // 关键:恢复终端模式,解决串口卡顿 restore_terminal(); remove(PID_FILE); // 清理PID文件 printf("播放系统已停止,串口已恢复正常\n"); exit(0); // 强制退出程序,避免阻塞 } } // 获取视频文件列表(原代码不变) int get_video_files(char ***file_list) { DIR *dir; struct dirent *ent; int count = 0; dir = opendir(VIDEO_DIR); if (dir == NULL) { printf("无法打开视频目录: %s\n", VIDEO_DIR); return 0; } while ((ent = readdir(dir)) != NULL) { char *ext = strrchr(ent->d_name, '.'); if (ext && (strcmp(ext, ".mp4") == 0 || strcmp(ext, ".MP4") == 0 || strcmp(ext, ".avi") == 0 || strcmp(ext, ".mkv") == 0)) { count++; } } rewinddir(dir); *file_list = malloc(count * sizeof(char *)); int i = 0; while ((ent = readdir(dir)) != NULL && i < count) { char *ext = strrchr(ent->d_name, '.'); if (ext && (strcmp(ext, ".mp4") == 0 || strcmp(ext, ".MP4") == 0 || strcmp(ext, ".avi") == 0 || strcmp(ext, ".mkv") == 0)) { (*file_list)[i] = malloc(strlen(VIDEO_DIR) + strlen(ent->d_name) + 2); sprintf((*file_list)[i], "%s/%s", VIDEO_DIR, ent->d_name); i++; } } closedir(dir); return count; } // 播放单个视频(关键修改:重定向标准输出和标准错误) void play_video(const char *video_path) { if (stop_flag) return; char *cmd_args[] = { "gst-play-1.0", (char *)video_path, "--videosink=kmssink", "--audiosink=alsasink", "--volume=0.8", NULL}; printf("播放: %s\n", video_path); play_child_pid = fork(); if (play_child_pid == 0) { // 重定向日志(关键修改:同时重定向标准输出和标准错误) int log_fd = open(LOG_FILE, O_WRONLY | O_APPEND | O_CREAT, 0644); if (log_fd >= 0) { // 修复点:重定向标准输出和标准错误 dup2(log_fd, STDOUT_FILENO); // 重定向标准输出 dup2(log_fd, STDERR_FILENO); // 重定向标准错误 close(log_fd); } execvp("gst-play-1.0", cmd_args); perror("执行播放命令失败"); exit(1); } else if (play_child_pid < 0) { perror("创建播放进程失败"); play_child_pid = -1; return; } // 非阻塞等待子进程,及时响应停止信号 while (play_child_pid > 0 && !stop_flag) { int status; pid_t ret = waitpid(play_child_pid, &status, WNOHANG); if (ret != 0) { play_child_pid = -1; break; } usleep(100000); } } // 保存PID到文件(原代码不变) void save_pid() { FILE *fp = fopen(PID_FILE, "w"); if (fp) { fprintf(fp, "%d\n", getpid()); fclose(fp); } } // 删除PID文件(原代码不变) void remove_pid() { remove(PID_FILE); } int main(int argc, char *argv[]) { // 第一步:保存终端初始模式(核心!) if (tcgetattr(STDIN_FILENO, &orig_termios) == -1) { perror("保存终端模式失败"); exit(1); } // 注册退出清理函数:即使程序异常退出,也会恢复终端 atexit(restore_terminal); printf("=== 电梯广告播放系统 ===\n"); printf("视频目录: %s\n", VIDEO_DIR); printf("提示:按 Ctrl+C 可立即停止播放并退出程序\n"); // 设置信号处理(支持Ctrl+C和kill命令) signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); // 保存PID save_pid(); // 检查视频目录(优化:退出时恢复终端) DIR *dir = opendir(VIDEO_DIR); if (dir == NULL) { printf("错误: 视频目录不存在,创建目录...\n"); mkdir(VIDEO_DIR, 0755); printf("请将MP4视频文件放入: %s\n", VIDEO_DIR); remove_pid(); restore_terminal(); // 恢复终端 return 1; } closedir(dir); // 主循环(原逻辑不变) while (!stop_flag) { char **video_files = NULL; int video_count = get_video_files(&video_files); if (video_count == 0) { printf("没有找到视频文件,等待10秒...\n"); sleep(10); continue; } printf("找到 %d 个视频文件\n", video_count); for (int i = 0; i < video_count && !stop_flag; i++) { if (video_files[i]) { play_video(video_files[i]); free(video_files[i]); } } if (video_files) { free(video_files); } if (!stop_flag) { printf("一轮播放完成,继续循环...\n"); } } // 正常退出时的清理 restore_terminal(); remove_pid(); printf("停止播放系统\n"); return 0; }

正常关闭不卡顿

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/21 12:58:38

低成本蜂鸣器电路设计方案新手教程

蜂鸣器电路设计从零开始&#xff1a;新手也能搞懂的低成本发声方案你有没有遇到过这样的情况&#xff1f;想给自己的智能小车加个提示音&#xff0c;结果一通电&#xff0c;蜂鸣器没响&#xff0c;MCU却莫名其妙重启了&#xff1b;或者明明代码写对了&#xff0c;蜂鸣器声音微弱…

作者头像 李华
网站建设 2026/3/15 8:47:17

Java爬虫api接口测试

下面给出一份“Java 爬虫 API 接口测试”端到端实战笔记&#xff0c;覆盖签名生成 → 抓包回放 → 自动化断言 → Mock 容错 → 性能压测完整闭环。示例代码均基于 2025 年最新版依赖&#xff0c;可直接拷贝到 IDE 跑通。一、场景说明 目标&#xff1a;对「淘宝运费接口」taob…

作者头像 李华
网站建设 2026/3/20 19:13:06

贴片LED灯正负极判断技巧:新手友好教程

贴片LED灯正负极怎么认&#xff1f;别再焊反了&#xff01;一文讲透识别技巧你有没有遇到过这种情况&#xff1a;辛辛苦苦把贴片LED焊上去了&#xff0c;通电一试——不亮。检查电源、查线路都没问题&#xff0c;最后才发现&#xff0c;原来是极性接反了。更糟的是&#xff0c;…

作者头像 李华
网站建设 2026/3/19 6:26:39

Vivado IP核在软件定义无线电中的应用:系统剖析

Vivado IP核在软件定义无线电中的实战解析&#xff1a;从模块到系统你有没有遇到过这样的情况&#xff1f;手头有一个SDR项目&#xff0c;要求支持多频段、多协议切换&#xff0c;时间紧任务重。你想用FPGA实现完整的数字前端处理链——下变频、滤波、FFT分析、上变频发射……但…

作者头像 李华
网站建设 2026/3/19 17:19:12

利用Keil调试优化工控程序启动时间的方法

如何用Keil“看穿”工控程序的启动黑箱&#xff1f;实战优化全过程揭秘你有没有遇到过这样的场景&#xff1a;设备上电后&#xff0c;LED迟迟不亮&#xff0c;HMI界面卡在“正在启动”界面半秒甚至好几秒&#xff1f;在自动化产线中&#xff0c;这短短几百毫秒可能就意味着节拍…

作者头像 李华
网站建设 2026/3/19 11:38:59

数字电路与时分复用系统构建:操作指南

构建高效时分复用系统&#xff1a;从数字电路到工程实现你有没有遇到过这样的问题——多个传感器的数据要同时上传&#xff0c;但MCU的引脚不够、布线复杂到像蜘蛛网&#xff1f;或者在音频采集系统中&#xff0c;多个麦克风信号干扰严重&#xff0c;同步困难&#xff1f;其实&…

作者头像 李华