在C++中使用opencv创建网络摄像头的RTSP流

vawmfj5a  于 2023-04-12  发布在  其他
关注(0)|答案(1)|浏览(702)

我试图从我的摄像头捕捉视频,并通过RTSP流使用C中的开放CV将其发送到。我在C上工作不多,所以请避免错误,他们下面是我的代码,将摄像头流写入文件,但我想将其流到RTSP服务器。

cv::VideoWriter virtualWebcam;
HRESULT hr = CoInitialize(NULL);
if (SUCCEEDED(hr)) {
    virtualWebcam.open(
        "./file.avi", cv::CAP_ANY,
        cv::VideoWriter::fourcc('M', 'J', 'P', 'G'),
        camera_frame_rate,
        cv::Size(static_cast < int > (camera_frame_width), static_cast < int > (camera_frame_height)),
        true);

    if (!virtualWebcam.isOpened()) {
        cerr << "Error opening virtual webcam\n";
        return 1;
    }
} else {
    cerr << "Error initializing COM library for virtual webcam\n";
    return 1;
}

我也尝试过做一些像virtualWebcam.open("rtsp://localhost:8554/stream", cv::CAP_FFMPEG,cv::VideoWriter::fourcc('M', 'J','P', 'G'),camera_frame_rate,cv::Size(static_cast < int > (camera_frame_width), static_cast < int > (camera_frame_height)), true);cv::CAP_GSTREAMER,但这也是行不通的
任何帮助都非常感谢。谢谢
我想发送网络摄像头视频流到RTSP服务器/从这里只做一个RTSP服务器,并通过它发送流

ncecgwcz

ncecgwcz1#

cv::CAP_GSTREAMER后端支持cv::VideoWriter创建RTSP流,cv::CAP_FFMPEG后端不支持。
使用GStreamer后端很复杂,需要使用GStreamer构建OpenCV。
following post展示了一个使用GStreamer后端创建RTSP流的示例。
由于某种原因,创建的流可以使用GStreamer捕获,但不能使用其他应用程序捕获(我找不到缺少的内容)。
我们可以使用FFmpeg CLI代替cv::VideoWriter
我们可以执行FFmpeg作为子进程,并将视频帧写入标准输入管道-使用与我的following answer中描述的相同的技术。
我们可以使用FFmpeg命令行如下:
ffmpeg -re -f rawvideo -r 10 -video_size 640x480 -pixel_format bgr24 -i pipe: -vcodec libx264 -crf 24 -pix_fmt yuv420p -f rtsp rtsp://localhost:8554/stream

  • -re用于“实时流媒体”-将传输速度降低到帧速率(用于模拟“虚拟网络摄像头”)。
  • -r 10 -video_size 640x480 -pixel_format bgr24-定义10 fps、640 x480分辨率和BGR像素格式。
  • -i pipe:-定义FFmpeg输入为标准输入管道。
  • -vcodec libx264 -crf 24 -pix_fmt yuv420p-定义H.264编解码器,具有标称质量(和YUV 420的颜色子采样)。
  • -f rtsp rtsp://localhost:8554/stream-定义RTSP输出格式和输出流端口和名称。

要使用FFplay捕获RTSP流,请在执行C代码之前执行FFplay:
ffplay -rtsp_flags listen -i rtsp://localhost:8554/stream
下面的C
代码示例将合成OpenCV图像发送到RTSP视频流:

#include <stdio.h>
#include "opencv2/opencv.hpp"
#include <string>

//For receiving the RTSP video stream with FFplay, execute: "ffplay -rtsp_flags listen -i rtsp://localhost:8554/stream" before exectuing this program.
int main()
{
    // 10000 frames, resolution 640x480, and 10 fps
    int width = 640;
    int height = 480;
    int n_frames = 10000;
    int fps = 10;

    const std::string output_stream = "rtsp://localhost:8554/stream";   //Send RTSP to port 8554 of "localhost", with stream named "stream".

    //Open FFmpeg application as sub-process.
    //FFmpeg input PIPE : RAW images in BGR color format.
    //FFmpeg output: RTSP stream encoded with H.264 codec (using libx264 encoder).
    //Adding '-re' slows down the transmission to rate of the fps (for simulating a "virtual webcam").
    std::string ffmpeg_cmd = std::string("ffmpeg -re -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 -f rtsp " + output_stream;

    //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

    cv::Mat frame = cv::Mat(height, width, CV_8UC3); //Initialize frame.

    for (int i = 0; i < n_frames; i++)
    {
        //Build synthetic image for testing ("render" a video frame):
        frame = cv::Scalar(60, 60, 60); //Fill background with dark gray
        cv::putText(frame, std::to_string(i+1), cv::Point(width/2 - 100*(int)(std::to_string(i+1).length()), height/2+100), cv::FONT_HERSHEY_DUPLEX, 10, cv::Scalar(255, 30, 30), 20);  // Draw a blue 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, (size_t)width*height*3, pipeout);
    }

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

    return 0;
}

注意事项:
为了避免提前执行FFplay,我们可以将MediaMTX作为“rtsp-simple-server”执行(保持其在后台运行)。
比它也可以接收流使用VLC视频播放器(例如).
VLC示例:

相关问题