簡體   English   中英

將 ffmpeg output 管道連接到帶升壓的 ffplay 標准輸入

[英]Piping ffmpeg output into ffplay stdin with boost

我正在嘗試將 ffmpeg 進程的 output 進程轉換為 ffplay 進程(有點像播放)。 我的問題如下:如果我逐個字符地復制 output 字符(按字符我的意思是char )它可以正常工作,除了它會消耗大量的 CPU 功率。 但是,當我嘗試將 pipe 塊放入其中(通過使用緩沖區)時,ffplay 出於某種原因甚至無法識別輸入。

bp::ipstream iso;
bp::ipstream ise;
bp::opstream in;
    
bp::child ffmpeg(bp::search_path("ffmpeg"), bp::args({"-loglevel", "quiet", "-f", "pulse", "-i", "default", "-f", "wav", "-bitexact", "-nostdin", "-"}), bp::std_out > iso, bp::std_err > ise);
bp::child ffplay(bp::search_path("ffplay"), bp::args({"-loglevel", "verbose", "-nodisp", "-f", "wav", "-i", "-"}), bp::std_in < in, bp::std_out > bp::null);

以下是用於比較的 2 個代碼片段:

這里是逐個char地復制char

while(ffmpeg.running()) {
    char c;
    c = iso.get();
    in << c;
}

在這里它是在緩沖區的幫助下復制的

char buffer[1024];
while(ffmpeg.running()) {
    iso.get(buffer, 1024);
    in << buffer;
}

如有必要,我可以提供 ffplay output,但是我沒有看到任何錯誤或類似的東西。

無需手動完成這項工作,您只需連接相同的管道:

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, ise, in;

兩者都有效,但您可能不需要 stream 對象的復雜性。 事實上,您可以使用異步版本,它的行為仍然相同(但為您提供更多選項/控制異步運行):

在此處輸入圖像描述

現場在線演示

對於生產者/消費者進程,明顯替換/簡化了命令:

住在科利魯

#include <boost/process.hpp>

namespace bp = boost::process;
using namespace std::chrono_literals;
using boost::system::error_code;

int main() {
    //bp::pstream iso, ise, in;
    bp::pipe iso, ise, 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", "-f", "wav", /*"-bitexact",*/ "-nostdin", "-"} },
         { "ffplay", {"-loglevel", "verbose", "-nodisp", "-f", "wav", "-i", "-"} },
#endif
    };

    auto& [prod, cons] = tasks;

    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)
    );

    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, ise, in;
    //bp::pipe iso, ise, 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 -e 'hello world\\nYOHOHO\\nMOHOHO\\n'"} },
         { "xxd", {} },
#else
         { "ffmpeg", {"-loglevel", "quiet", "-f", "pulse", "-i", "default", "-f", "wav", /*"-bitexact",*/ "-nostdin", "-"} },
         { "ffplay", {"-loglevel", "verbose", "-nodisp", "-f", "wav", "-i", "-"} },
#endif
    };

    auto& [prod, cons] = tasks;

    bp::child ffmpeg(
        io, pg, bp::search_path(prod.cmd), bp::args(prod.args),
        bp::std_out > iso,
        bp::std_err > ise
    );

    bp::child ffplay(
        io, pg, bp::search_path(cons.cmd), bp::args(cons.args),
        (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..

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM