c – 如何在MJPEG中使用boost.Asio?
我想将OpenCV图像(来自相机)实时广播到远程计算机,它必须通过以太网完成.在标准的OpenCV Mat对象中连续接收图像.最终代码必须集成到C(Qt)应用程序中.
我发现this Python script能够很好地完成这项工作. 现在我试图获得相当于该代码的C,我设法使用Boost Asio和Simple-Web-Server项目创建一个HTTP服务器.我能够显示static blue image /网络摄像头相机图像(未刷新). 我写了一段代码,但它没有用.我的猜测是数据仅在函数返回时发送(永不返回). #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 OKrn" "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 << "--jpgboundaryrn" << // Signal we start a new image "Content-type: image/jpeg" << "Content-Length: " << img_content.length() << "rn" << "rn" << img_content << "rn"; 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 OKrn" "Content-Length: " << content.length() << "rn" "rn" << 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; 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); // Fill image with blue std::vector<uchar> buf; cv::imencode(".jpg",std::vector<int>()); std::string img_content(buf.begin(),buf.end()); rep.headers.clear(); rep.content.clear(); rep.content.append("--jpgboundaryrn"); 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("rn"); 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标题/内容答案,它运行正常:
我添加了一个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=--jpgboundaryrn"; con.do_write(); while (true) // FIXME: How do I handle disconnection from the client? { cv::Mat image(200,buf.end()); rep.status = reply::none; rep.headers.resize(0); rep.content.clear(); rep.content.append("--jpgboundary"); rep.content.append("rn"); rep.content.append("Content-Type: image/jpeg"); rep.content.append("rn"); rep.content.append("Content-length: "+boost::lexical_cast<std::string>(img_content.length())); rep.content.append("rn"); rep.content.append("rn"); rep.content.append(img_content); rep.content.append("rn"); 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循环中. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |