如何向boost::process发送Ctrl+C信号触发FFmpeg数据刷新?
解决boost::process终止FFmpeg时无法获取刷新数据的问题
你用GenerateConsoleCtrlEvent(CTRL_C_EVENT, c.id())无效的核心原因是:FFmpeg进程和主进程不在同一个控制台进程组。Windows的GenerateConsoleCtrlEvent默认向指定进程组的所有进程发信号,但boost::process默认启动子进程时会创建新的控制台组,导致信号无法传到FFmpeg。
以下是两种可行的解决办法:
方法一:确保FFmpeg与主进程同属一个控制台组
启动FFmpeg时不设置CREATE_NEW_PROCESS_GROUP标志(boost::process默认行为),让它继承主进程的控制台组。发送信号时,将第二个参数设为0(表示当前控制台组),同时主进程要先忽略自身的Ctrl+C信号,避免被连带终止:
#include <boost/process.hpp> #include <windows.h> namespace bp = boost::process; int main() { // 启动FFmpeg,不创建新控制台组 bp::child ffmpeg_proc("ffmpeg -i input.mp4 -f rawvideo pipe:1", bp::std_out > bp::pipe(), bp::creation_flags(CREATE_NO_WINDOW) // 仅隐藏窗口,不创建新进程组 ); // 主进程忽略Ctrl+C信号,避免自身被终止 SetConsoleCtrlHandler(nullptr, TRUE); // 向当前控制台组发送Ctrl+C信号(FFmpeg会收到) GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); // 等待FFmpeg自行退出,确保它完成stdout刷新 ffmpeg_proc.wait(); // 读取管道中剩余的输出数据 // ... }
如果需要单独给FFmpeg的进程组发信号,可以启动时设置CREATE_NEW_PROCESS_GROUP,此时子进程ID就是进程组ID:
bp::child ffmpeg_proc("ffmpeg -i input.mp4 -f rawvideo pipe:1", bp::std_out > bp::pipe(), bp::creation_flags(CREATE_NO_WINDOW | CREATE_NEW_PROCESS_GROUP) ); // 发送信号到FFmpeg的进程组 GenerateConsoleCtrlEvent(CTRL_C_EVENT, ffmpeg_proc.id());
方法二:用boost::process的POSIX信号接口发送SIGINT
boost::process封装了跨平台的信号发送接口,Windows下底层会处理控制台组问题,直接调用即可:
#include <boost/process.hpp> #include <boost/process/signal.hpp> namespace bp = boost::process; int main() { bp::child ffmpeg_proc("ffmpeg -i input.mp4 -f rawvideo pipe:1", bp::std_out > bp::pipe() ); // 发送SIGINT信号(等效于Ctrl+C) bp::signal::send(SIGINT, ffmpeg_proc); ffmpeg_proc.wait(); // 读取剩余输出... }
重要提示
发送信号后不要立刻调用terminate(),必须等待FFmpeg自行退出,这样它才有足够时间将缓存的数据刷新到stdout。
内容的提问来源于stack exchange,提问作者Mike
相关产品推荐
相关产品推荐

