Skip to content

Commit acb08aa

Browse files
committed
graceful shutdown costumized target
1 parent 26c80fa commit acb08aa

File tree

4 files changed

+68
-42
lines changed

4 files changed

+68
-42
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.1)
44
## PROJECT
55
## name and version
66
##
7-
project(nadjieb_mjpeg_streamer VERSION 1.0.0 LANGUAGES CXX)
7+
project(nadjieb_mjpeg_streamer VERSION 1.1.0 LANGUAGES CXX)
88

99
##
1010
## DEPENDENCIES

README.md

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* Set different streams depending on HTTP GET path
66
* Multi-threaded streaming
77
* Single Header-only library
8-
* graceful shutdown
8+
* Graceful shutdown
99

1010
## CMake Integration
1111
### External
@@ -50,11 +50,18 @@ int main()
5050
std::vector<int> params = {cv::IMWRITE_JPEG_QUALITY, 90};
5151

5252
MJPEGStreamer streamer(8080);
53-
// By default 1 worker is used for streaming, if you want to use 4 workers
54-
// MJPEGStreamer streamer(8080, 4);
53+
// By default 1 worker is used for streaming
54+
// if you want to use 4 workers:
55+
// MJPEGStreamer streamer(8080, 4);
56+
57+
// By default /shutdown is the target to graceful shutdown the streamer
58+
// if you want to change target to graceful shutdown:
59+
// streamer.setShutdownTarget("/stop");
5560

5661
streamer.start();
57-
while (true)
62+
63+
// Visit /shutdown or another defined target to stop the loop and graceful shutdown
64+
while (streamer.isAlive())
5865
{
5966
cv::Mat frame;
6067
cap >> frame;
@@ -76,13 +83,8 @@ int main()
7683
std::vector<uchar> buff_hsv;
7784
cv::imencode(".jpg", hsv, buff_hsv, params);
7885
streamer.publish("/hsv", std::string(buff_hsv.begin(), buff_hsv.end()));
79-
80-
// Visit /shutdown to break from the loop and graceful shutdown
81-
if (streamer.shutdownFromBrowser())
82-
{
83-
break;
84-
}
8586
}
87+
8688
streamer.stop();
8789
}
8890
```

examples/example.cpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,18 @@ int main()
1717
std::vector<int> params = {cv::IMWRITE_JPEG_QUALITY, 90};
1818

1919
MJPEGStreamer streamer(8080);
20-
// By default 1 worker is used for streaming, if you want to use 4 workers
21-
// MJPEGStreamer streamer(8080, 4);
20+
// By default 1 worker is used for streaming
21+
// if you want to use 4 workers:
22+
// MJPEGStreamer streamer(8080, 4);
23+
24+
// By default /shutdown is the target to graceful shutdown the streamer
25+
// if you want to change target to graceful shutdown:
26+
// streamer.setShutdownTarget("/stop");
2227

2328
streamer.start();
24-
while (true)
29+
30+
// Visit /shutdown or another defined target to stop the loop and graceful shutdown
31+
while (streamer.isAlive())
2532
{
2633
cv::Mat frame;
2734
cap >> frame;
@@ -43,12 +50,7 @@ int main()
4350
std::vector<uchar> buff_hsv;
4451
cv::imencode(".jpg", hsv, buff_hsv, params);
4552
streamer.publish("/hsv", std::string(buff_hsv.begin(), buff_hsv.end()));
46-
47-
// Visit /shutdown to break from the loop and graceful shutdown
48-
if (streamer.shutdownFromBrowser())
49-
{
50-
break;
51-
}
5253
}
54+
5355
streamer.stop();
5456
}

include/nadjieb/mjpeg_streamer.hpp

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,23 @@ SOFTWARE.
4545
#include <utility>
4646
#include <vector>
4747

48+
/// The major version number
49+
#define NADJIEB_MJPEG_STREAMER_VERSION_MAJOR 1
50+
51+
/// The minor version number
52+
#define NADJIEB_MJPEG_STREAMER_VERSION_MINOR 1
53+
54+
/// The patch number
55+
#define NADJIEB_MJPEG_STREAMER_VERSION_PATCH 0
56+
57+
/// The complete version number
58+
#define NADJIEB_MJPEG_STREAMER_VERSION_CODE \
59+
(NADJIEB_MJPEG_STREAMER_VERSION_MAJOR * 10000 + NADJIEB_MJPEG_STREAMER_VERSION_MINOR * 100 + \
60+
NADJIEB_MJPEG_STREAMER_VERSION_PATCH)
61+
62+
/// Version number as string
63+
#define NADJIEB_MJPEG_STREAMER_VERSION_STRING "10100"
64+
4865
namespace nadjieb
4966
{
5067
constexpr int NUM_SEND_MUTICES = 100;
@@ -57,7 +74,8 @@ class MJPEGStreamer
5774
void start();
5875
void stop();
5976
void publish(const std::string &path, const std::string &buffer);
60-
bool shutdownFromBrowser();
77+
void setShutdownTarget(const std::string &target);
78+
bool isAlive();
6179

6280
private:
6381
struct Payload
@@ -70,8 +88,8 @@ class MJPEGStreamer
7088
int port_;
7189
int master_socket_ = -1;
7290
int num_workers_;
73-
bool shutdownFlag = false;
7491
struct sockaddr_in address_;
92+
std::string shutdown_target_ = "/shutdown";
7593

7694
std::thread thread_listener_;
7795
std::mutex clients_mutex_;
@@ -128,7 +146,7 @@ void MJPEGStreamer::start()
128146
for (auto i = 0; i < num_workers_; ++i)
129147
{
130148
workers_.emplace_back([this]() {
131-
while (this->master_socket_ > 0)
149+
while (this->isAlive())
132150
{
133151
Payload payload;
134152

@@ -190,7 +208,7 @@ void MJPEGStreamer::start()
190208
to.tv_sec = 1;
191209
to.tv_usec = 0;
192210

193-
while (this->master_socket_ > 0)
211+
while (this->isAlive())
194212
{
195213
FD_SET(this->master_socket_, &fd);
196214

@@ -207,19 +225,19 @@ void MJPEGStreamer::start()
207225
std::string req(4096, 0);
208226
::read(new_socket, &req[0], req.size());
209227

210-
std::string path;
211-
if (!req.empty())
228+
if (req.empty())
212229
{
213-
path = req.substr(req.find("GET") + 4, req.find("HTTP/") - req.find("GET") - 5);
214-
215-
if (path == "/shutdown")
216-
{
217-
shutdownFlag = true;
218-
}
230+
::close(new_socket);
231+
continue;
219232
}
220-
else
233+
234+
auto path = req.substr(req.find("GET") + 4, req.find("HTTP/") - req.find("GET") - 5);
235+
if (path == this->shutdown_target_)
221236
{
222237
::close(new_socket);
238+
std::unique_lock<std::mutex> lock(this->payloads_mutex_);
239+
this->master_socket_ = -1;
240+
this->condition_.notify_all();
223241
continue;
224242
}
225243

@@ -239,7 +257,7 @@ void MJPEGStreamer::start()
239257

240258
void MJPEGStreamer::stop()
241259
{
242-
if (master_socket_ > 0)
260+
if (isAlive())
243261
{
244262
std::unique_lock<std::mutex> lock(payloads_mutex_);
245263
master_socket_ = -1;
@@ -288,18 +306,22 @@ void MJPEGStreamer::publish(const std::string &path, const std::string &buffer)
288306
clients = path2clients_[path];
289307
}
290308

309+
for (auto i : path2clients_[path])
291310
{
292-
for (auto i : path2clients_[path])
293-
{
294-
std::unique_lock<std::mutex> lock(payloads_mutex_);
295-
payloads_.emplace(Payload({buffer, path, i}));
296-
condition_.notify_one();
297-
}
311+
std::unique_lock<std::mutex> lock(payloads_mutex_);
312+
payloads_.emplace(Payload({buffer, path, i}));
313+
condition_.notify_one();
298314
}
299315
}
300316

301-
bool MJPEG_streamer_module::shutdownFromBrowser()
317+
void MJPEGStreamer::setShutdownTarget(const std::string &target)
318+
{
319+
shutdown_target_ = target;
320+
}
321+
322+
bool MJPEGStreamer::isAlive()
302323
{
303-
return shutdownFlag;
324+
std::unique_lock<std::mutex> lock(payloads_mutex_);
325+
return master_socket_ > 0;
304326
}
305327
} // namespace nadjieb

0 commit comments

Comments
 (0)