首页 > 解决方案 > 完全读取命名管道后,防止 FFmpeg 关闭

问题描述

我正在为一个大学项目做一个 C++ 应用程序,该项目需要一个视频文件(例如 matroska)并使用 FFmpeg(在std::system()指令中嵌入命令)应用这些步骤:

我需要将我的流分成几块,因为我最终需要满足实时约束,所以我不能在我的整个输入视频文件之前应用过滤器,然后才开始流式传输到客户端。我的主要问题是,一旦 FFmpeg 清空了两个管道,它就会关闭;但其他视频和音频块仍需通过管道传输和流式传输。我需要 FFmpeg 来监听等待新数据的管道。

在 bash 中,我使用以下命令实现了这一点。

开始在提示中侦听 RTSP 流:

ffplay -rtsp_flags listen rtsp://127.0.0.1@127.0.0.1:8090

创建一个名为管道的视频和一个名为管道的音频:

mkfifo video_pipe
mkfifo audio_pipe

使用此命令可防止 FFmpeg 在视频管道清空时关闭:

exec 7<>video_pipe

(将其应用于管道视频就足够了,音频管道也不会出现问题)

激活 FFmpeg 命令

ffmpeg -probesize 2147483647 -re -s 1280x720 -pix_fmt rgb24 -i pipe:0 -vsync 0 -i audio_pipe -r 25 -vcodec libx264 -crf 23 -preset ultrafast -f rtsp -rtsp_transport tcp rtsp://127.0.0.1@127.0.0.1:8090 < video_pipe

然后在另一个提示中输入管道:

cat audiochunk.aac > audio_pipe & cat frame*.bmp > video_pipe

这些命令使用 3 个提示运行良好,然后我在 C++ 中尝试将它们嵌入指令中的std::system()命令(使用不同的线程);一切正常,但是一旦 ffmpeg 命令清空视频管道(完成第一个块),它就会关闭。 exec命令在这里似乎无效。如何防止 FFmpeg 关闭?

两天在这个问题上苦苦挣扎,查看所有可能的互联网解决方案。尽管很头疼,但我希望我很清楚,提前感谢您的建议。

更新: 我的 C++ 代码是这样的;我将它放在单个线程上的单个函数中,但它不会改变它的行为。我在 Ubuntu 18.04.2

void CameraThread::ffmpegJob()
{
    std::string strvideo_length, command, timing;
    long video_length, begin_chunk, end_chunk;
    int begin_h, begin_m, begin_s, end_h, end_m, end_s;

    command = "ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 " + Configurations::file_name;
    strvideo_length = execCmd(command.c_str());
    strvideo_length.pop_back(); // remove \n character
    video_length = strToPositiveDigit(strvideo_length);

    if(video_length == -1)
    {
        std::cout << "Invalid input file";
        return;
    }

    std::system("bash -c \"rm mst-temp/mst_video_pipe\"");
    std::system("bash -c \"rm mst-temp/mst_audio_pipe\"");
    std::system("bash -c \"mkfifo mst-temp/mst_video_pipe\"");
    std::system("bash -c \"mkfifo mst-temp/mst_audio_pipe\"");
    // Keep video pipe opened
    std::system("bash -c \"exec 7<>mst-temp/mst_video_pipe\"");

    std::string rtsp_url = "rtsp://" + Configurations::my_own_used_ip + "@" + Configurations::client_ip +
            ":" + std::to_string(Configurations::port + 1);

    command = "ffmpeg -probesize 2147483647 -re -s 1280x720 -pix_fmt rgb24 -i pipe:0 "
              "-i mst-temp/mst_audio_pipe -r 25 -vcodec libx264 -crf 23 -preset ultrafast -f rtsp "
              "-rtsp_transport tcp " + rtsp_url + " < mst-temp/mst_video_pipe &"; // Using & to continue without block on command
    std::system(command.c_str());

    begin_chunk = -1 * VIDEO_CHUNK;
    end_chunk = 0;

    // Extract the complete audio track
    command = "bash -c \"ffmpeg -i " + Configurations::file_name + " -vn mst-temp/audio/complete.aac -y\"";
    std::system(command.c_str());

    while(true)
    {
        // Define the actual video chunk (in seconds) to use, if EOF is reached, exit
        begin_chunk += (end_chunk - begin_chunk);
        if(begin_chunk == video_length)
            break;
        if(end_chunk + VIDEO_CHUNK <= video_length)
            end_chunk += VIDEO_CHUNK;
        else
            end_chunk += (video_length - end_chunk);

        // Set begin and end H, M, S variables
        begin_h = static_cast<int>(begin_chunk / 3600);
        begin_chunk -= (begin_h * 3600);
        begin_m = static_cast<int>(begin_chunk / 60);
        begin_chunk -= (begin_m * 60);
        begin_s = static_cast<int>(begin_chunk);
        end_h = static_cast<int>(end_chunk / 3600);
        end_chunk -= (end_h * 3600);
        end_m = static_cast<int>(end_chunk / 60);
        end_chunk -= (end_m * 60);
        end_s = static_cast<int>(end_chunk);

        // Extract bmp frames and audio from video chunk
        // Extract frames
        timing = " -ss " + std::to_string(begin_h) + ":" + std::to_string(begin_m) +
                ":" + std::to_string(begin_s) + " -to " + std::to_string(end_h) +
                ":" + std::to_string(end_m) + ":" + std::to_string(end_s);
        command = "bash -c \"ffmpeg -i " + Configurations::file_name + timing +
                " -compression_algo raw -pix_fmt rgb24 mst-temp/frames/output%03d.bmp\"";
        std::system(command.c_str());
        // Extract audio
        command = "bash -c \"ffmpeg -i mst-temp/audio/complete.aac" + timing +
                " -vn mst-temp/audio/audiochunk.aac -y\"";
        std::system(command.c_str());

        // Apply elaborations on audio and frames.........................

        // Write modified audio and frames to streaming pipes
        command = "bash -c \"cat mst-temp/audio/audiochunk.aac > mst-temp/mst_audio_pipe & "
                  "cat mst-temp/frames/output*.bmp > mst-temp/mst_video_pipe\"";
        std::system(command.c_str());
    }
}

标签: c++bashffmpegnamed-pipesfifo

解决方案


推荐阅读