如何在MJPEG中使用boost.Asio?

时间:2015-12-01 18:11:49

标签: c++ http opencv boost-asio mjpeg

我想将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;
  }
}

2 个答案:

答案 0 :(得分:0)

由于使用了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;
  }

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

答案 1 :(得分:0)

<强> 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;
}    

用法