向Windows子进程标准输入发送Ctrl+C等控制字符的可靠方案咨询
你遇到的偶发失效问题核心原因是:Windows平台下重定向stdin后,ffmpeg默认会在部分场景下关闭stdin监听,导致你写入的Ctrl+C(0x03)字符没有被进程处理,和你用匿名管道还是命名管道/套接字重定向没有关系。
最可靠的优雅停止方案
不要通过stdin发字符,直接使用Windows原生控制台信号机制向ffmpeg进程发送CTRL_C_EVENT,实现100%可靠触发ffmpeg正常退出逻辑。
1. 调整CreateProcess创建ffmpeg子进程的参数
创建子进程时必须新增CREATE_NEW_PROCESS_GROUP标志,为ffmpeg创建独立进程组,这是后续发送控制台信号的前提。如果需要隐藏控制台窗口,额外加CREATE_NO_WINDOW标志即可。
示例代码:
STARTUPINFO si = {0}; si.cb = sizeof(STARTUPINFO); PROCESS_INFORMATION pi = {0}; // 核心创建标志:单独进程组 + 可选隐藏窗口 DWORD createFlags = CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW; BOOL createRet = CreateProcess( NULL, (LPWSTR)your_ffmpeg_command_line, // 注意这里的命令行参数要可写 NULL, NULL, FALSE, createFlags, NULL, NULL, &si, &pi ); if (createRet) { // 保存ffmpeg进程ID和进程句柄供后续停止用 g_ffmpeg_pid = pi.dwProcessId; g_ffmpeg_process_hdl = pi.hProcess; // 线程句柄用不到直接关闭 CloseHandle(pi.hThread); }
2. 停止录制时的信号发送逻辑
直接调用GenerateConsoleCtrlEvent发送CTRL+C信号,之后等待ffmpeg正常退出即可:
// 向ffmpeg所在进程组发送CTRL+C信号 BOOL sendRet = GenerateConsoleCtrlEvent(CTRL_C_EVENT, g_ffmpeg_pid); if (sendRet) { // 等待最多5秒让ffmpeg写完视频文件尾部,时间可根据录制文件大小调整 WaitForSingleObject(g_ffmpeg_process_hdl, 5000); } // 兜底判断:如果进程仍未退出再考虑强制杀死,正常场景不会走到这一步 DWORD exitCode = 0; GetExitCodeProcess(g_ffmpeg_process_hdl, &exitCode); if (exitCode == STILL_ACTIVE) { TerminateProcess(g_ffmpeg_process_hdl, 0); } // 关闭进程句柄释放资源 CloseHandle(g_ffmpeg_process_hdl);
其他可选方案说明
如果你坚持要通过stdin发送停止信号,只需要在ffmpeg启动参数中新增-stdin,强制ffmpeg开启stdin监听即可,能大幅降低原有逻辑的失效率,但稳定性仍然不如控制台信号方案。
你之前尝试的套接字重定向方案无需继续调试,Win32的SOCKET句柄不支持直接传入WriteFile写入,需要调用send接口,且即使写成功仍然会遇到stdin监听失效的问题。
内容的提问来源于stack exchange,提问作者Keve
相关产品推荐
相关产品推荐

