如何将 boost.Asio 与 MJPEG 一起使用?

Posted

技术标签:

【中文标题】如何将 boost.Asio 与 MJPEG 一起使用?【英文标题】:How to use boost.Asio with MJPEG? 【发布时间】:2016-03-05 18:39:39 【问题描述】:

我想将 OpenCV 图像(来自相机)实时广播到远处的计算机,它必须通过以太网完成。图像在标准 OpenCV Mat 对象中连续接收。最终代码必须集成到 C++ (Qt) 应用程序中。

我发现 this Python script 做得很好。

现在我正在尝试获取与该代码等效的 C++,我设法使用 Boost Asio 和 Simple-Web-Server 项目创建了一个 HTTP 服务器。我能够显示static blue image/网络摄像头图像(未刷新)。

我写了一段代码,但它不起作用。我的猜测是数据仅在函数返回时发送(永远不会返回)。 如何在 while 循环的每次迭代后强制发送数据?

#include "server_http.hpp"

#include <thread>
#include <boost/chrono.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#include <opencv2/opencv.hpp>
//#include <opencv/cv.h>

using namespace boost::posix_time;
typedef SimpleWeb::Server<SimpleWeb::HTTP> HttpServer;

cv::Mat image;
cv::VideoCapture cap;

int main()

  cap.open(0);
  if (!cap.isOpened ())
  
    std::cerr << "Could not initialize capturing" << std::endl;
    return (-1);
  
  cap >> image;

  HttpServer server(8080, 2);

  // Image resource is requested
  server.resource["^/cam.mjpg"]["GET"] =
      [=](HttpServer::Response& response, std::shared_ptr<HttpServer::Request> request)
      
        time_facet *facet = new time_facet("%d-%b-%Y %H:%M:%S");
        std::cout.imbue(std::locale(std::cout.getloc(), facet));
        std::cout << second_clock::local_time() << " | " << "Camera image requested!" << std::endl;

        response <<
        "HTTP/1.1 200 OK\r\n"
        "Content-type: multipart/x-mixed-replace; boundary=--jpgboundary";
        //TODO: Send header

        while (1) // TODO: Allow exiting this
        
          std::cout << "Send image" << std::endl;
          cap >> image;
          // Encode mat to jpg and copy it to content
          std::vector<uchar> buf;
          cv::imencode(".jpg", image, buf, std::vector<int>());
          std::string img_content(buf.begin(), buf.end());

          response << "--jpgboundary\r\n" << // Signal we start a new image
              "Content-type: image/jpeg" <<
              "Content-Length: " << img_content.length() << "\r\n" <<
              "\r\n" << img_content << "\r\n";
          std::this_thread::sleep_for(std::chrono::milliseconds(400));
        
      ;

  // Anything else is requested
  server.default_resource["GET"] = [](HttpServer::Response& response, std::shared_ptr<HttpServer::Request> request)
  
    time_facet *facet = new time_facet("%d-%b-%Y %H:%M:%S");
    std::cout.imbue(std::locale(std::cout.getloc(), facet));
    std::cout << second_clock::local_time() << " | " << request->path << std::endl;

    std::string content =
    "<html><head></head><body>"
    "<img src=\"cam.mjpg\"/>"
    "</body></html>";
    response <<
    "HTTP/1.1 200 OK\r\n"
    "Content-Length: " << content.length() << "\r\n"
    "\r\n" << content;
  ;

  std::thread server_thread([&server]()
  
    server.start();
  );

  std::this_thread::sleep_for(std::chrono::seconds(1));
  server_thread.join();
  return 0;


编辑 1

根据 Technik Empire 的评论,我回到了boost examples; 在 HTTP 服务器示例中,当回调返回时发送响应,因此我修改了回调以允许对套接字进行 do_write() 操作。

HTML 页面正确显示,但图像未显示(显示损坏的图像图标),我试图查看 Wireshark 发生了什么,但我不知道出了什么问题。

这是我的 handle_request 函数:(request_handler.cpp):

void request_handler::handle_request(const request& req, reply& rep, connection &con)

  // Decode url to path.
  std::string request_path;
  if (!url_decode(req.uri, request_path))
  
    rep = reply::stock_reply(reply::bad_request);
    return;
  

  // Request path must be absolute and not contain "..".
  if (request_path.empty() || request_path[0] != '/'
      || request_path.find("..") != std::string::npos)
  
    rep = reply::stock_reply(reply::bad_request);
    return;
  

  // Determine the file extension.
  std::size_t last_slash_pos = request_path.find_last_of("/");
  std::string filename;
  if (last_slash_pos != std::string::npos)
    filename = request_path.substr(last_slash_pos + 1);

  if (filename == "cam.mjpg") // Image is requested
  
    rep.status = reply::ok;
    rep.headers.resize(1);
    rep.headers[0].name = "Content-Type";
    rep.headers[0].value = "multipart/x-mixed-replace; boundary=--jpgboundary";
    rep.content.empty();
    con.do_write();
    rep.status = reply::none;

    while (true) // FIXME: How do I handle disconnection from the client?
    
      cv::Mat image(200, 300, CV_8UC3);
      int random = rand() % 255 + 1;
      image = cv::Scalar(random, 0, 0); // Fill image with blue
      std::vector<uchar> buf;
      cv::imencode(".jpg", image, buf, std::vector<int>());
      std::string img_content(buf.begin(), buf.end());

      rep.headers.clear();
      rep.content.clear();

      rep.content.append("--jpgboundary\r\n");
      con.do_write();

      rep.content.clear();
      rep.headers.resize(2);
      rep.headers[0].name = "Content-Type";
      rep.headers[0].value = mime_types::extension_to_type("jpg");
      rep.headers[1].name = "Content-length";
      rep.headers[1].value = img_content.size();
      rep.content.append(img_content);
      rep.content.append("\r\n");
      con.do_write();

      boost::this_thread::sleep(boost::posix_time::milliseconds(500));
    
  
  else // Anything but the image is requested
  
    std::string content =
    "<html><head></head><body>"
    "Hello :)<br>"
    "<img src=\"cam.mjpg\"/>"
    "</body></html>";

    rep.status = reply::ok;
    rep.headers.resize(2);
    rep.headers[0].name = "Content-Length";
    rep.headers[0].value = content.length();
    rep.headers[1].name = "Content-Type";
    rep.headers[1].value = mime_types::extension_to_type("html");
    rep.content.append(content);
    con.do_write();
    return;
  

【问题讨论】:

imo 你通过依赖 Simple-Web-Server 使这变得比它需要的复杂得多。应该只是一个 tcp 侦听器和套接字并启动异步读取,然后在读取(请求)处理程序中写入。查看 boost http 服务器示例。此外,您不需要将向量复制到字符串中,这样做完全是浪费。如果 Simple-Web-Server 强加于您的设计,我会为此重新考虑。 我已经更新了我的问题,我现在使用的是 Boost HTTP 服务器示例。 我认为你的问题是你有一些不应该出现的 CRLF (\r\n) 空格。您需要从服务器获取几帧输出,例如使用 curl,并确保它遵循 MJPEG over HTTP 格式。幸运的是,您已经有一个可以工作的 Python 服务器,因此您可以与它的输出进行比较。 是的!你知道我该如何处理与客户端的断开连接吗? 【参考方案1】:

感谢 Firefox 网络分析器,我通过分析数据包使其工作,我复制了 Python 标头/内容答案,它工作正常:

我添加了reply::none 回复类型,并确保如果提供了此回复,则不会发送 HTTP 状态。所以在reply::to_buffers() 函数中我添加了这个:

  if (status != none) // Don't add status to buffer if status is "none"
    buffers.push_back(status_strings::to_buffer(status));

request_handler.cpp 代码如下所示:

  if (filename == "cam.mjpg") // Image is requested
  
    rep.status = reply::ok;
    rep.headers.resize(1);
    rep.headers[0].name = "Content-Type";
    rep.headers[0].value = "multipart/x-mixed-replace; boundary=--jpgboundary\r\n";
    con.do_write();

    while (true) // FIXME: How do I handle disconnection from the client?
    
      cv::Mat image(200, 300, CV_8UC3);
      int random = rand() % 255 + 1;
      image = cv::Scalar(random, 0, 0); // Fill image with blue
      std::vector<uchar> buf;
      cv::imencode(".jpg", image, buf, std::vector<int>());
      std::string img_content(buf.begin(), buf.end());

      rep.status = reply::none;
      rep.headers.resize(0);
      rep.content.clear();
      rep.content.append("--jpgboundary");
      rep.content.append("\r\n");
      rep.content.append("Content-Type: image/jpeg");
      rep.content.append("\r\n");
      rep.content.append("Content-length: "+boost::lexical_cast<std::string>(img_content.length()));
      rep.content.append("\r\n");
      rep.content.append("\r\n");
      rep.content.append(img_content);
      rep.content.append("\r\n");
      con.do_write();
      boost::this_thread::sleep(boost::posix_time::milliseconds(100));
    
  
  else // Anything but the image is requested
  
    std::string content =
    "<html><head></head><body>"
    "<img src=\"cam.mjpg\"/>"
    "</body></html>";

    rep.status = reply::ok;
    rep.headers.resize(2);
    rep.headers[0].name = "Content-Length";
    rep.headers[0].value = content.length();
    rep.headers[1].name = "Content-Type";
    rep.headers[1].value = mime_types::extension_to_type("html");
    rep.content.append(content);
    con.do_write();
    return;
  

欢迎在 cmets 中提出改进建议。我不知道如何处理与客户端的断开连接(退出 while 循环),所以目前服务器只能处理 1 个请求;之后它就卡在了while循环中。

【讨论】:

如果图像很重,此代码不起作用,只有部分图像会显示在网络浏览器中。【参考方案2】:

Http_server.hpp

#ifndef HTTPSERVER_HPP_INCLUDED
#define HTTPSERVER_HPP_INCLUDED

#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <opencv2/core/core.hpp>
#include <boost/thread.hpp>
using boost::asio::ip::tcp;
typedef boost::shared_ptr<tcp::socket> socket_ptr;
class HttpServer

public:
  std::map<std::string, std::string> winnames;
  std::map<std::string,int> requestcounts;
  std::map<std::string,std::vector<unsigned char> > jpegbuffers;
  short port;
  HttpServer();
  void run(int portno);
  boost::shared_mutex mut;
  boost::condition_variable_any cond;
  int httpdelay;
  void IMSHOW(std::string win, cv::Mat mat);
  int compression;
  bool is_debug;

private:
  int it;
  void server(int port);
  void session(socket_ptr sock);

  void handleinfo(socket_ptr sock);
  void handlewindows(socket_ptr sock);
  void handlemjpeg(socket_ptr sock,std::string winname);
  void handlejpg(socket_ptr sock,std::string winname);
  void handle404(socket_ptr sock);
;

#endif

Http_server.cpp

#include "http_server.hpp"
#include <fstream>
#include <boost/filesystem.hpp>
#include <boost/format.hpp> 
#include <opencv2/opencv.hpp>
#include <boost/lexical_cast.hpp>

namespace bfs= boost::filesystem; 
using namespace std;
using boost::lexical_cast;

// Helper functions
#if defined(unix)        || defined(__unix)      || defined(__unix__) \
  || defined(linux)       || defined(__linux)     || defined(__linux__) \
  || defined(sun)         || defined(__sun) \
  || defined(BSD)         || defined(__OpenBSD__) || defined(__NetBSD__) \
  || defined(__FreeBSD__) || defined __DragonFly__ \
  || defined(sgi)         || defined(__sgi) \
  || defined(__MACOSX__)  || defined(__APPLE__) \
  || defined(__CYGWIN__)
#define is_nix
#endif

#if defined(_MSC_VER) || defined(WIN32)  || defined(_WIN32) || defined(__WIN32__) \
  || defined(WIN64)    || defined(_WIN64) || defined(__WIN64__)
#define is_win
#endif

#ifdef is_win 
#include <windows.h>
#define SLEEP(ms) Sleep(ms)
#endif

#ifdef is_nix 
#define SLEEP(ms) usleep(ms*1000)
#endif

std::vector<std::string> &dssplit(const std::string &s, char delim, std::vector<std::string> &elems) 
  std::stringstream ss(s);
  std::string item;
  while (getline(ss, item, delim)) 
    elems.push_back(item);
  
  return elems;


std::vector<std::string> dssplit(const std::string &s, char delim) 
  std::vector<std::string> elems;
  return dssplit(s, delim, elems);


void removeEmptyStrings(std::vector<std::string>& strings)

  std::vector<std::string>::iterator it = remove_if(strings.begin(), strings.end(),     mem_fun_ref(&std::string::empty));
  strings.erase(it, strings.end());


bool hasEnding(std::string const &fullString, std::string const &ending)

  if (fullString.length() >= ending.length()) 
    return (0 == fullString.compare(fullString.length() - ending.length(), ending.length(), ending));
  
  else 
    return false;
  


bool startswith(std::string const &src, std::string const &start)


  if (src.compare(0, start.length(), start) == 0)
  
    return true;
  
  return false;


std::string urldecode(std::string &src) 
  std::string ret;
  char ch;
  int ii;
  for (size_t i = 0; i<src.length(); i++) 
    if (int(src[i]) == 37) 
      sscanf(src.substr(i + 1, 2).c_str(), "%x", &ii);
      ch = static_cast<char>(ii);
      ret += ch;
      i = i + 2;
    
    else 
      ret += src[i];
    
  
  return (ret);


// Server implementation
HttpServer::HttpServer() :compression(70), is_debug(true), httpdelay(100)




void HttpServer::IMSHOW(std::string win, cv::Mat mat)



  winnames[win] = lexical_cast<string>(mat.cols) + "," + lexical_cast<string>(mat.rows);

  if (is_debug)
  
    cv::imshow(win, mat);
  
  else
  
    //cvDestroyWindow(win.c_str());
  

  if (requestcounts[win] > 0)
  
    cv::Mat towrite;
    if (mat.type() == CV_8UC1)
    
      cvtColor(mat, towrite, CV_GRAY2BGR);
    
    else if (mat.type() == CV_32FC3)
    
      double minVal, maxVal;
      minMaxLoc(mat, &minVal, &maxVal);
      mat.convertTo(towrite, CV_8U, 255.0 / (maxVal - minVal), -minVal * 255.0 / (maxVal - minVal));
    
    else
      towrite = mat;
    

    std::vector<uchar> buffer;
    std::vector<int> param(2);
    param[0] = CV_IMWRITE_JPEG_QUALITY;
    param[1] = compression;
    imencode(".jpg", towrite, buffer, param);
    jpegbuffers[win].swap(buffer);

  

void HttpServer::run(int portno)

  port=portno;
  boost::thread t(boost::bind(&HttpServer::server,this,port));

void HttpServer::server(int port)

  try
  

    boost::asio::io_service io_service;
    io_service.run();
    tcp::acceptor a(io_service, tcp::endpoint(tcp::v4(), port));
    for (;;)
    
      socket_ptr sock(new tcp::socket(io_service));
      a.accept(*sock);
      boost::thread t(boost::bind(&HttpServer::session, this, sock));
    
  
  catch (boost::exception & e)
  
    std::cout << "OMG!" << boost::diagnostic_information(e)<<endl;
  

void HttpServer::session(socket_ptr sock)

  try
  
    boost::system::error_code ec;
    boost::asio::streambuf sbuffer;
    boost::asio::read_until(* sock, sbuffer, "\0", ec ); 
    const char* header=boost::asio::buffer_cast<const char*>(sbuffer.data());
    std::string reqStr(header,header+sbuffer.size());   
    sbuffer.consume(sbuffer.size());
    std::vector<std::string> strs;
    strs = dssplit(reqStr,' ');
    if(strs.size()>1)
    
      std::string requesturl = urldecode(strs[1]);
      std::vector<std::string> splited=dssplit(requesturl,'/');
      removeEmptyStrings(splited);
      if(splited.size()==1)
      
        if(startswith(splited[0],"windows"))
        
          handlewindows(sock);
        else if(startswith(splited[0],"info"))
        
          handleinfo(sock);
        else if(hasEnding(splited[0],".mjpg"))
        
          handlemjpeg(sock,splited[0].substr(0,splited[0].size()-5));
        else if(hasEnding(splited[0],".jpg") || splited[0].find(".jpg?")!=string::npos)
        
          handlejpg(sock,splited[0]);
        else
        
          handle404(sock);
        
      else
      
        handle404(sock);
      
      sock->shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
    

  catch(const std::exception& ex)
  
    boost::system::error_code ec;
    boost::asio::ip::tcp::endpoint endpoint = sock->remote_endpoint(ec);
    if(!ec)
    
      sock->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
    
    //DPRINTERR(ex.what());
  catch(const  std::string& ex)
  
    boost::system::error_code ec;
    boost::asio::ip::tcp::endpoint endpoint = sock->remote_endpoint(ec);
    if(!ec)
    
      sock->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
    
  


void HttpServer::handleinfo(socket_ptr sock)


  boost::system::error_code error;
  boost::asio::streambuf sbuffer;
  std::ostream response_stream(&sbuffer);
  string retstr;
  for (std::map<std::string,std::string>::iterator it=winnames.begin(); it!=winnames.end(); ++it)
  
    string wname =it->first;
    int rcnt = 0;
    if(requestcounts.find(wname)!=requestcounts.end())
    
      rcnt=requestcounts[wname];
    

    retstr+=boost::str(boost::format(""
      "\"name\":\"%s\","
      "\"reqCnt\":%d,"
      "\"size\":\"%s\""
      ","
      )
      %wname
      %rcnt
      %it->second
      );
  
  if(retstr.size()>0) retstr.resize(retstr.size()-1);

  retstr=boost::str(boost::format(""
    "\"windows\":[%s],"
    "\"version\":\"%s\","
    "\"fps\":%s"
    ""
    )
    %retstr
    %"0.0"
    % to_string(0.)
    );
  response_stream << "HTTP/1.1 200 OK\r\n";
  response_stream << "Access-Control-Allow-Origin: *\r\n";
  response_stream << "Content-Type: text/plain\r\n\r\n";
  response_stream << retstr << "\r\n\r\n";

  boost::asio::write(*sock, sbuffer);

void HttpServer::handlewindows(socket_ptr sock)


  boost::system::error_code error;
  boost::asio::streambuf sbuffer;
  std::ostream response_stream(&sbuffer);
  string retstr;
  for (std::map<std::string,std::string>::iterator it=winnames.begin(); it!=winnames.end(); ++it)
  
    string wname =it->first;
    int rcnt = 0;
    if(requestcounts.find(wname)!=requestcounts.end())
    
      rcnt=requestcounts[wname];
    

    retstr+=boost::str(boost::format(""
      "\"name\":\"%s\","
      "\"reqCnt\":%d,"
      "\"size\":\"%s\""
      ","
      )
      %wname
      %rcnt
      %it->second
      );
  
  if(retstr.size()>0) retstr.resize(retstr.size()-1);

  retstr="\"windows\":["+retstr+"]";
  response_stream<<"HTTP/1.1 200 OK\r\n"
    "Content-Type: text/plain\r\n\r\n"<<
    retstr<<"\r\n\r\n";

  boost::asio::write(*sock, sbuffer);


void HttpServer::handlemjpeg(socket_ptr sock,std::string winname)

  if(requestcounts.find(winname)==requestcounts.end())
  
    handle404(sock);
    return;
  
  std::string frame=winname;
  //boost::shared_lock<boost::shared_mutex> lock(mut);
  //lock.lock();
  requestcounts[frame]++;
  //lock.unlock();
  boost::system::error_code error;
  boost::asio::streambuf sbuffer;
  std::ostream response_stream(&sbuffer);
  response_stream<<"HTTP/1.1 200 OK\r\n";
  response_stream<<"Content-Type: multipart/mixed;boundary=b\r\n";
  response_stream<<"Cache-Control: no-store\r\n";
  response_stream<<"Pragma: no-cache\r\n";
  response_stream<<"Audio Mode : None\r\n";
  response_stream<<"Connection: close\r\n";
  response_stream<<"\r\n";
  boost::asio::write(*sock, sbuffer); 
  for(;;)
  
    try
    
      if( (jpegbuffers.count(frame)<0 ||
        jpegbuffers[frame].size()<4) || 
        (jpegbuffers[frame][0]!=0xff && jpegbuffers[frame][1]!=0xd8 &&
        jpegbuffers[frame][jpegbuffers[frame].size()-2]!=0xff && jpegbuffers[frame][jpegbuffers[frame].    size()-1]!=0xd9))
      

        SLEEP(10);
        continue;
      
      //boost::shared_lock<boost::shared_mutex> lock(mut);
      response_stream<<"--b\r\n"; 
      response_stream<<"Content-Type: image/jpeg\r\n";
      response_stream<<"Content-length: "<<jpegbuffers[frame].size()<<"\r\n";
      response_stream<<"\r\n";
      boost::asio::write(*sock, sbuffer);
      boost::asio::write(*sock,boost::asio::buffer(jpegbuffers[frame], jpegbuffers[frame].size()));
      //lock.unlock();
      SLEEP(httpdelay);
    
    catch (std::exception& e)
    
      SLEEP(50);
      //lock.lock();
      requestcounts[frame]--;
      //lock.unlock();
      return;
    
  
  //lock.lock();
  requestcounts[frame]--;
  //lock.unlock();


void HttpServer::handlejpg(socket_ptr sock,std::string winname)

  if(winname.find("?")!=string::npos)
  
    winname = winname.substr(0,winname.find("?"));
  
  winname =winname.substr(0,winname.size()-4);
  std::string frame=winname;
  requestcounts[frame]++;
  boost::system::error_code error;
  boost::asio::streambuf sbuffer;
  std::ostream response_stream(&sbuffer);

  jpegbuffers[frame].clear();
  for(;;)
  
    try
    
      if( (jpegbuffers.count(frame)<0 ||
        jpegbuffers[frame].size()<4) || 
        (jpegbuffers[frame][0]!=0xff && jpegbuffers[frame][1]!=0xd8 &&
        jpegbuffers[frame][jpegbuffers[frame].size()-2]!=0xff && jpegbuffers[frame][jpegbuffers[frame].    size()-1]!=0xd9))
      

        SLEEP(10);
        continue;
      
      response_stream<<"HTTP/1.1 200 OK\r\n";
      response_stream<<"Content-Type:  image/jpeg\r\n";
      response_stream<<"Cache-Control: no-store\r\n";
      response_stream<<"Access-Control-Allow-Origin: *\r\n";
      response_stream<<"Pragma: no-cache\r\n";
      response_stream<<"Content-length: "<<jpegbuffers[frame].size()<<"\r\n";
      response_stream<<"Connection: close\r\n";

      response_stream<<"\r\n";
      boost::asio::write(*sock, sbuffer);
      boost::asio::write(*sock,boost::asio::buffer(jpegbuffers[frame], jpegbuffers[frame].size()));

      break;
    
    catch (std::exception& e)
    

      //DPRINTERR( "net exceptoin:"+std::string(e.what()));
      SLEEP(50);
      requestcounts[frame]--;
      return;
    
  
  requestcounts[frame]--;

void HttpServer::handle404(socket_ptr sock)



  boost::system::error_code error;
  boost::asio::streambuf sbuffer;
  std::ostream response_stream(&sbuffer);
  response_stream<<"HTTP/1.1 404 Not Found\r\n"
    "Content-Type: text/html\r\n"
    "Connection: close\r\n"
    "Content-Length: 132\r\n\r\n"
    "<html>\r\n"
    "<head><title>404 Not Found</title></head>\r\n"
    "<body bgcolor=\"white\">\r\n"
    "<center><h1>404 Not Found</h1></center>\r\n"   
    "</body>\r\n"
    "</html>\r\n";
  boost::asio::write(*sock, sbuffer);

Main.cpp

#include <opencv2/opencv.hpp>
#include "http_server.hpp"
#include <iostream>
#include <fstream>

using namespace cv;
#define MJPGFILE_BUFFER_SIZE 10240
class MjpgFileCapture
public:
  static double lastframeseen;
  MjpgFileCapture() ;
  MjpgFileCapture(std::string filepath)
  
    filepath_ = filepath;
    is_inited_ = false;
    skip_ = true;
    imgready_ = false;
    ff_ = false;
    readbytes_ = -2;
    i_ = 0;
  ;

  void init();
  MjpgFileCapture& operator >>(cv::Mat& out);
private:
  std::string filepath_;
  bool is_inited_;
  std::ifstream ifstream_;
  std::vector<char> data_;
  bool skip_;
  bool imgready_;
  bool ff_;//have we seen ff byte?
  long long readbytes_;
  char ca_[MJPGFILE_BUFFER_SIZE];
  int i_;//loop index
;

void MjpgFileCapture::init()

  is_inited_ = true;
  ifstream_ = std::ifstream(filepath_.c_str(), std::ios::binary);


MjpgFileCapture& MjpgFileCapture::operator >> (cv::Mat& out)

  out = Mat();
  if (!is_inited_)
  
    init();
  


  while (1)
  
    uchar c;
    if (readbytes_ != 0 && readbytes_ != -1)
    
      if (i_ >= readbytes_)
      
        ifstream_.read(ca_, MJPGFILE_BUFFER_SIZE);
        readbytes_ = ifstream_.gcount();
        i_ = 0;
      
      for (; i_ < readbytes_; i_++)
      
        c = ca_[i_];
        if (ff_ && c == 0xd8)
        
          skip_ = false;
          data_.push_back((uchar)0xff);
        
        if (ff_ && c == 0xd9)
        
          imgready_ = true;
          data_.push_back((uchar)0xd9);
          skip_ = true;
        
        ff_ = c == 0xff;
        if (!skip_)
        
          data_.push_back(c);
        
        if (imgready_)
        
          if (data_.size() != 0)
          
            cv::Mat data_mat(data_);
            cv::Mat frame(imdecode(data_mat, 1));
            out = frame;
          
          else
          
            printf("warning:image is ready and data is empty. Likely bug.");
          
          imgready_ = false;
          skip_ = true;
          data_.clear();
          return *this;
        
      
    
    else
    
      //own exception class
      throw std::string("zero byte read:probably end of file.");
    
  
  return *this;

HttpServer* server = 0;
void file_loop()


  MjpgFileCapture cap("C:/v/frame.mjpg");
  while (true)
  
    Mat im;
    cap >> im;
    server->IMSHOW("im", im);
    imshow("im", im);
    if (waitKey(1) == 27)
      exit(0);
  

int main(int argc, char** argv)

  server = new HttpServer;
  //server->port = 8080;
  server->run(8080);
  while (true)
  
    try
      file_loop();
    
    catch (...)
    

    
  
  return 0;
    

用法

server->IMSHOW("im",mat);//将mat注册为服务器中的窗口名im,可以通过浏览器访问http://localhost:8080/im.jpg或http://localhost:8080/im.mjpg http://localhost:8080/windows(显示所有注册的窗口)

【讨论】:

只是对内容类型的说明,如果数据流是从chrome消费的,可能通过java applet或flash,它不能x-mixed-replace。 chrome 一旦在标题中看到它就会立即终止连接。这可能会为您节省几个小时(或更多..)

以上是关于如何将 boost.Asio 与 MJPEG 一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

将 fork() 与 boost::asio::ip::tcp::iostream 一起使用是不是安全?

如何使用 boost::asio::serial_port 支持硬件流控制?

boost::asio 与 boost::unique_future

如何在 Qt 中使用 boost::asio::deadline_timer?

如何将 boost::asio::tcp::io_stream 附加到我的 io_service?

boost::asio 扩展 TCP 套接字