如何将 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?