0

我正在尝试从我的 C++ 进程中调用 FFMPEG 以从 IP 摄像机流式传输视频。我使用的 FFMPEG 命令是ffmpeg.exe -rtsp_transport tcp -i rtsp://10.0.1.21/ONVIF/MediaInput?profile=1_def_profile4 -f image2pipe -pix_fmt rgb24 -vcodec rawvideo -r 15 -. 我已经在命令提示符下验证了这个命令,它确实启动了一个视频流并将帧转储到stdout. 我还在 Python 中编写了类似的代码,并且可以正常工作。

这是我用来使用 C++ 中上一段中的参数调用 FFMPEG 并从stdout.

bool build_ffmpeg_arguments(const std::string &uri, std::vector<std::string> &args)
{
    args.push_back("-rtsp_transport");
    args.push_back("tcp");
    args.push_back("-i");
    args.push_back(uri);
    args.push_back("-f");
    args.push_back("image2pipe");
    args.push_back("-pix_fmt");
    args.push_back("rgb24");
    args.push_back("-vcodec");
    args.push_back("rawvideo");
    args.push_back("-r");
    args.push_back("15");
    args.push_back("-");

    return true;
}


boost::process::child start_ffmpeg(const std::string &uri,
                                   const std::string &ffmpeg_path = "c:\\Tools\\ffmpeg.exe")
{
    std::vector<std::string> args;
    build_ffmpeg_arguments(uri, args);

    boost::process::context ctx;
    ctx.stdout_behavior = boost::process::capture_stream();
    ctx.stderr_behavior = boost::process::capture_stream();

    return boost::process::launch(ffmpeg_path, args, ctx);
}

bool read_frame(boost::process::pistream &is, int frame_size, std::vector<char> &frame_bytes)
{
    char *buffer = new char[frame_size];

    frame_bytes.clear();
    is.read(buffer, frame_size);
    int bytes_read = is.gcount();
    frame_bytes.assign(buffer, buffer + bytes_read);

//    std::cout << "Is Bad: " << is.bad() << std::endl;
//    std::cout << "Is EOF: " << is.eof() << std::endl;
//    std::cout << "gcount: " << bytes_read << std::endl;

    delete[] buffer;
    if(is.bad() || is.eof() || bytes_read < frame_size)
    {
        //We read in gunk, skip this time.
        is.clear();
        return false;
    }
    else
    {
        return true;
    }
}


//This is where the code is invoked.
BOOST_AUTO_TEST_CASE(test_ffmpeg_stream)
{
    std::string uri = "rtsp://10.0.1.21/ONVIF/MediaInput?profile=1_def_profile4";
    int width = 320;
    int height = 240;
    int bpp = 3;
    int bytes_expected = width * height * 3;
    boost::process::child c = start_ffmpeg(uri);
    boost::process::pistream &is = c.get_stdout();
    boost::process::pistream &err = c.get_stderr();

    std::vector<char> buffer;
    bool result = read_frame(is, bytes_expected, buffer);
    //BOOST_CHECK_EQUAL(true, result);
    std::cout << "Buffer size: " << buffer.size() << std::endl;

    std::string line;
    while (std::getline(err, line))
        std::cout << line << std::endl;
}

的输出stderr表明参数可能传递错误。

ffmpeg version 2.8.3 Copyright (c) 2000-2015 the FFmpeg developers
  built with gcc 5.2.0 (GCC)
  configuration: --enable-gpl --enable-version3 --disable-w32threads --enable-av
isynth --enable-bzlib --enable-fontconfig --enable-frei0r --enable-gnutls --enab
le-iconv --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --
enable-libdcadec --enable-libfreetype --enable-libgme --enable-libgsm --enable-l
ibilbc --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enab
le-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-librtmp --en
able-libschroedinger --enable-libsoxr --enable-libspeex --enable-libtheora --ena
ble-libtwolame --enable-libvidstab --enable-libvo-aacenc --enable-libvo-amrwbenc
 --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enabl
e-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-lzma --ena
ble-decklink --enable-zlib
  libavutil      54. 31.100 / 54. 31.100
  libavcodec     56. 60.100 / 56. 60.100
  libavformat    56. 40.101 / 56. 40.101
  libavdevice    56.  4.100 / 56.  4.100
  libavfilter     5. 40.101 /  5. 40.101
  libswscale      3.  1.101 /  3.  1.101
  libswresample   1.  2.101 /  1.  2.101
  libpostproc    53.  3.100 / 53.  3.100
rtsp://10.0.1.21/ONVIF/MediaInput?profile=1_def_profile4: Unknown error

有没有办法显示带有boost::process::launch正在调用的参数的完整命令行?有什么明显的我做错了boost::process吗?

更新

怀疑它可能是错误传递的命令行参数,我创建了一个虚拟可执行文件,打印出它接收到的命令行参数。它是 pure 的直接替代品,ffmpeg.exe因此我可以看到正在传递哪些命令行。我得到的命令行是-rtsp_transport tcp -i rtsp://10.0.1.21/ONVIF/MediaInput?profile=1_def_profile4 -f image2pipe -pix_fmt rgb24 -vcodec rawvideo -r 15 -. 使用该命令行手动调用 ffmpeg 可以按预期工作。然而不知何故,当通过boost::process.

** 解决方案 **

看起来我需要设置上下文的环境字段。不知道为什么这可以解决问题,但确实可以。

boost::process::context ctx;
ctx.environment = boost::process::self::get_environment();
ctx.stdout_behavior = boost::process::capture_stream();
ctx.stderr_behavior = boost::process::capture_stream();
4

0 回答 0