首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何将帧从OpenCV C++代码流到Video4Linux或ffmpeg?

如何将帧从OpenCV C++代码流到Video4Linux或ffmpeg?
EN

Stack Overflow用户
提问于 2022-07-06 13:53:10
回答 1查看 251关注 0票数 1

我正在试验OpenCV来处理来自视频流的帧。目标是从流中获取一个框架,对其进行处理,然后将处理后的帧放到一个新的/新的流中。

我已经能够成功地使用OpenCV视频捕获功能读取流。但是我不知道如何用处理过的帧创建输出流。

为了进行一些基本测试,我使用ffmpeg创建了一个本地视频文件流,如下所示:

代码语言:javascript
复制
ffmpeg -i sample.mp4 -v 0 -vcodec mpeg4 -f mpegts \
        "udp://@127.0.0.1:23000?overrun_nonfatal=1&fifo_size=50000000"

在使用C++库的VideoCapture功能的VideoCapture代码中,我能够捕获上面创建的流。以下是我所要达到的基本目标:

代码语言:javascript
复制
cv::VideoCapture capture("udp://@127.0.0.1:23000?overrun_nonfatal=1&fifo_size=50000000", cv::CAP_FFMPEG);

cv::Mat frame;

while (true) 
{
    // use the above stream to capture a frame
    capture >> frame;
    
    // process the frame (not relevant here)
    ...

    // finally, after all the processing is done I 
    // want to put this frame on a new stream say at
    // udp://@127.0.0.1:25000, I don't know how to do
    // this, ideally would like to use Video4Linux but
    // solutions with ffmpeg are appreciated as well
}

从上述代码中的注释中可以看出,我甚至不知道该如何开始处理这个问题,我尝试搜索类似的问题,但我所能找到的只是如何使用流来执行VideoCapture,与流输出无关。

我对此比较陌生,对你们中的许多人来说,这似乎是一个非常基本的问题,请原谅我。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-07-06 21:13:32

我们可以使用与我的following Python code sample相同的技术。

  • 作为子进程执行FFmpeg,打开stdin管道进行写入。

文件*pipeout = popen(ffmpeg_cmd.c_str(),"w")

  • frame.data写入FFmpeg子进程的stdin管道(在循环中)

(frame.data,1,宽度*高度*3,管道输出);

  • 在结束时关闭管道(它将关闭子进程)

pclose(pipeout);

下面的示例是一个通用示例--构建编号的帧,并将编码的视频写入MKV输出文件。

该示例使用以下等效命令行:

ffmpeg -y -f rawvideo -r 10 -video_size 320x240 -pixel_format bgr24 -i pipe: -vcodec libx264 -crf 24 -pix_fmt yuv420p output.mkv

您可以调整特定需求的参数(将output.mkv替换为udp://@127.0.0.1:25000)。

capture >> frame替换编号的框架,并调整大小和框架。

代码示例:

代码语言:javascript
复制
#include <stdio.h>
#include <chrono>
#include <thread>
#include "opencv2/opencv.hpp"

int main()
{
    int width = 320;
    int height = 240;
    int n_frames = 100;
    int fps = 10;

    //Use a "generic" example (write the output video in output.mkv video file).
    //ffmpeg -y -f rawvideo -r 10 -video_size 320x240 -pixel_format bgr24 -i pipe: -vcodec libx264 -crf 24 -pix_fmt yuv420p output.mkv
    std::string ffmpeg_cmd = std::string("ffmpeg -y -f rawvideo -r ") + std::to_string(fps) +
                             " -video_size " + std::to_string(width) + "x" + std::to_string(height) +
                             " -pixel_format bgr24 -i pipe: -vcodec libx264 -crf 24 -pix_fmt yuv420p output.mkv";

    //Execute FFmpeg as sub-process, open stdin pipe (of FFmpeg sub-process) for writing.
    //In Windows we need to use _popen and in Linux popen
#ifdef _MSC_VER
    FILE *pipeout = _popen(ffmpeg_cmd.c_str(), "wb");   //Windows (ffmpeg.exe must be in the execution path)
#else
    //https://batchloaf.wordpress.com/2017/02/12/a-simple-way-to-read-and-write-audio-and-video-files-in-c-using-ffmpeg-part-2-video/
    FILE *pipeout = popen(ffmpeg_cmd.c_str(), "w");     //Linux (assume ffmpeg exist in /usr/bin/ffmpeg (and in path).
#endif

    for (int i = 0; i < n_frames; i++)
    {
        cv::Mat frame = cv::Mat(height, width, CV_8UC3);
        frame = cv::Scalar(60, 60, 60); //Fill background with dark gray
        cv::putText(frame, std::to_string(i+1), cv::Point(width/2-50*(int)(std::to_string(i+1).length()), height/2+50), cv::FONT_HERSHEY_DUPLEX, 5, cv::Scalar(30, 255, 30), 10);  // Draw a green number

        cv::imshow("frame", frame);cv::waitKey(1); //Show the frame for testing

        //Write width*height*3 bytes to stdin pipe of FFmpeg sub-process (assume frame data is continuous in the RAM).
        fwrite(frame.data, 1, width*height*3, pipeout);
    }

    // Flush and close input and output pipes
    fflush(pipeout);

#ifdef _MSC_VER
    _pclose(pipeout);   //Windows
#else
    pclose(pipeout);    //Linux
#endif

    //It looks like we need to wait one more second at the end. //https://stackoverflow.com/a/62804585/4926757
    std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // sleep for 1 second

    return 0;
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72884815

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档