如何解决使用 boost 将 ffmpeg 输出传送到 ffplay stdin
我正在尝试将 ffmpeg 进程的输出通过管道传输到 ffplay 进程(有点像播放)。我的问题如下:如果我逐个字符地复制输出(逐个字符我的意思是 import re
re.search("(?<=\t).*?(?=\t)",s)[0] # Output: "John"
),它可以正常工作,除了消耗大量 CPU 功率。但是,当我尝试将块通过管道传输到其中时(通过使用缓冲区),ffplay 由于某种原因甚至无法识别输入。
char
以下是用于比较的 2 个代码片段:
这里是通过bp::ipstream iso;
bp::ipstream ise;
bp::opstream in;
bp::child ffmpeg(bp::search_path("ffmpeg"),bp::args({"-loglevel","quiet","-f","pulse","-i","default","wav","-bitexact","-nostdin","-"}),bp::std_out > iso,bp::std_err > ise);
bp::child ffplay(bp::search_path("ffplay"),"verbose","-nodisp",bp::std_in < in,bp::std_out > bp::null);
复制char
char
这里是在缓冲区的帮助下进行复制
while(ffmpeg.running()) {
char c;
c = iso.get();
in << c;
}
如有必要,我可以提供 ffplay 输出,但是我没有看到任何错误或类似的东西。
解决方法
无需手动执行繁琐的工作,您只需连接相同的管道即可:
bp::child ffmpeg(
pg,bp::search_path(prod.cmd),bp::args(prod.args),bp::std_out > iso,bp::std_err > ise
);
bp::child ffplay(
pg,bp::search_path(cons.cmd),bp::args(cons.args),(bp::std_in < iso)
//,(bp::std_out> bp::null)
);
这将满足您的期望。这也意味着您不要选择 ipstream
/opstream
,因为角色是两者:
//bp::pstream iso,ise,in;
bp::pipe iso,in;
两者都有效,但您可能不需要流对象的复杂性。事实上,您可以使用异步版本,它的行为仍然相同(但为异步运行提供更多选项/控制):
在线演示
明显替换/简化了生产者/消费者进程的命令:
#include <boost/process.hpp>
namespace bp = boost::process;
using namespace std::chrono_literals;
using boost::system::error_code;
int main() {
//bp::pstream iso,in;
bp::pipe iso,in;
//boost::asio::io_context io;
//bp::async_pipe iso(io),ise(io),in(io);
bp::group pg;
struct { std::string cmd; std::vector<std::string> args; } tasks[] = {
#if 1
{ "bash",{ "-c","echo 'hello world'"} },{ "rev",{} },#else
{ "ffmpeg",{"-loglevel","quiet","-f","pulse","-i","default","wav",/*"-bitexact",*/ "-nostdin","-"} },{ "ffplay","verbose","-nodisp",#endif
};
auto& [prod,cons] = tasks;
bp::child ffmpeg(
pg,bp::std_err > ise
);
bp::child ffplay(
pg,(bp::std_in < iso)
//,(bp::std_out> bp::null)
);
if (!pg.wait_for(4s))
pg.terminate();
}
按预期打印“hello world”的反面:
dlrow olleh
做坏事
只是为了说明,这里是您如何手动执行 IO 泵。
#include <boost/process.hpp>
#include <boost/asio.hpp>
#include <iostream>
namespace bp = boost::process;
using namespace std::chrono_literals;
using boost::system::error_code;
int main() {
//bp::pstream iso,in;
//bp::pipe iso,in;
boost::asio::io_context io;
bp::async_pipe iso(io),"echo -e 'hello world\\nYOHOHO\\nMOHOHO\\n'"} },{ "xxd",cons] = tasks;
bp::child ffmpeg(
io,pg,bp::std_err > ise
);
bp::child ffplay(
io,(bp::std_in < in)
//,(bp::std_out> bp::null)
);
std::function<void()> stream_pump;
stream_pump = [&,buf=std::vector<char>(1024)]() mutable {
boost::asio::async_read(iso,boost::asio::buffer(buf),[&](error_code ec,size_t const nread) {
bool const eof = (ec == boost::asio::error::eof);
std::cerr << "nread: " << nread << " (eof:" << eof << ")\n";
if (ec && !eof)
std::cerr << "async_read: " << ec.message() << " (" << nread << ")\n";
else
boost::asio::async_write(in,boost::asio::buffer(buf,nread),[=,&in,&stream_pump](error_code ec,size_t /*nwritten*/) {
if (ec || eof) {
std::cerr << "Closing in\n";
in.close();
}
else
stream_pump(); // continue the pump
});
});
};
stream_pump(); // prime the pump
auto nhandlers = io.run_for(4s);
std::cerr << "Handlers executed: " << nhandlers << "\n";
ffmpeg.terminate();
if (ffplay.running())
ffplay.wait_for(1s);
if (ffplay.running())
pg.terminate();
}
印刷品
nread: 27 (eof:1)
Closing in
Handlers executed: 6
消费者子进程标准输出包含
00000000: 6865 6c6c 6f20 776f 726c 640a 594f 484f hello world.YOHO
00000010: 484f 0a4d 4f48 4f48 4f0a 0a HO.MOHOHO..
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。