OpenCV MJPG Streamer无法正常工作

时间:2017-11-18 17:50:51

标签: c++ opencv mjpeg

我正在尝试使用OpenCV 3.1版,Windows x64中的OpenCV VideoCapture类打开视频流。在我的覆盆子pi上我运行了mjpg_streamer,我可以通过http://192.168.1.245:8080/?action=stream看到输出,但是当我尝试在OpenCV中打开视频流时,它无法打开流。

这是我用来调试的代码,显然也适用于有连接问题的其他人。

#include <opencv2\core.hpp>
#include <opencv2\videoio.hpp>
#include <string>
#include <iostream>
using namespace std;

int main()
{
    cv::VideoCapture vcap;
    cv::Mat raw_image;

    const string videoStreamAddress = "http://192.168.1.245:8080/?action=stream";

    if (!vcap.open(videoStreamAddress))
    {

        cout << "Error opening video stream" << endl;
        system("pause");
        return -1;
    }

    cout << "Stream opened" << endl;
    system("pause");
    return 0;
}

在线,人们都说OpenCV必须在链接中有视频扩展名。我试图使用其他人正在使用的扩展技巧,例如http://192.168.1.245:8080/?action=stream?dummy=param.mjpghttp://192.168.1.245:8080/?action=stream&type=.mjpg,&amp; channel = 0&amp; .mjpg,以及&amp; type = .mjpeg,但这不起作用。另外,我在cmake中启用了ffmpeg并使用它构建。在这一点上,它似乎适用于其他人,并且似乎在该主题上没有任何其他内容。解决方案是什么?

1 个答案:

答案 0 :(得分:0)

感谢@ api55的建议,我能够获取流,然后将原始jpg数据传递给opencv,并在第一时间做我想做的事情。

以下是链接@ api55提供的解决方案的c ++代码(link to python solution)。

    try
    {

        boost::asio::io_service io_service;

        tcp::resolver resolver(io_service);
        tcp::resolver::query query("192.168.1.245", "8080");
        tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);

        tcp::socket socket(io_service);
        boost::asio::connect(socket, endpoint_iterator);

        std::string jpgimg = "";

        std::stringstream request_;

        request_ << "GET /?action=stream HTTP/1.1\r\n";
        request_ << "Host: 192.168.1.245\r\n";
        request_ << "Accept-Encoding: *\r\n";
        request_ << "\r\n";

        boost::system::error_code ignored_error;
        boost::asio::write(socket, boost::asio::buffer(request_.str()), ignored_error);

        for (;;)
        {
            char buf[1025];
            buf[1024] = '\0';
            boost::system::error_code error;

            size_t len = socket.read_some(boost::asio::buffer(buf,1024), error);

            if (error == boost::asio::error::eof)
                break; // Connection closed cleanly by peer.
            else if (error)
                throw boost::system::system_error(error); // Some other error.

            jpgimg.append(buf,buf+len);

            int a = jpgimg.find("\xff\xd8");
            int b = jpgimg.find("\xff\xd9");

            if (a != -1 && b != -1)
            {
                Mat rawData(1, b-a+2, CV_8UC1, (void*)(&jpgimg[a]));

                Mat i = cv::imdecode(rawData, CV_LOAD_IMAGE_COLOR);
                cv::imshow("i", i);
                if (cv::waitKey(1) == 27)
                break;

                jpgimg = jpgimg.substr(b+2);
            }

        }
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }

它绝不是优化的,纯粹是其他地方实施的基础。它与Boost ASIO 1.65.1配合使用,在我的覆盆子pi上打开一个流到mjpg_streamer(在端口8080上),向原始链接的/?action = stream部分发送一个HTTP GET请求,寻找jpg数据的开头和结束标志(“\ xff \ xd8”和“\ xff \ xd9”),然后通过imdecode将此数据发送到OpenCV。

资源:

  

提升ASIO客户端代码:   http://www.boost.org/doc/libs/1_65_1/doc/html/boost_asio/tutorial/tutdaytime1.html

     

有关jpgs如何工作的信息:   How to parse MJPEG HTTP Stream within C++?

     

在OpenCV中使用原始jpg数据:   opencv read jpeg image from buffer

希望OpenCV将来会有更好的mjpg支持。