gpt4 book ai didi

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

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:22:17 24 4
gpt4 key购买 nike

我想实时将 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/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com