- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我想实时将 OpenCV 图像(来自相机)广播到远程计算机,必须通过以太网来完成。图像在标准 OpenCV Mat 对象中连续接收。最终代码必须集成到 C++ (Qt) 应用程序中。
我找到了 this Python script这很好地完成了工作。
现在我试图获得该代码的 C++ 等价物,我设法使用 Boost Asio 和 Simple-Web-Server 创建了一个 HTTP 服务器。项目。我能够显示 static blue image/webcam 摄像头图像(未刷新)。
我写了一个代码,但它不工作。我的猜测是数据仅在函数返回时发送(永远不会返回)。如何在 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;
}
}
最佳答案
感谢 Firefox 网络分析器,我通过分析数据包让它工作,我复制了 Python header /内容答案并且它工作正常:
我添加了一个 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 循环。
关于c++ - 如何将 boost.Asio 与 MJPEG 一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34027210/
我是一名优秀的程序员,十分优秀!