Skip to content

Commit e81846a

Browse files
committed
asyncweb: enforce MjpegConfig.frameTimeout
1 parent e2d47c3 commit e81846a

File tree

4 files changed

+40
-24
lines changed

4 files changed

+40
-24
lines changed

src/esp32cam/asyncweb.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ StillResponse::_fillBuffer(uint8_t* buf, size_t buflen) {
118118
}
119119

120120
MjpegResponse::MjpegResponse(const MjpegConfig& cfg)
121-
: m_task(4)
121+
: m_task(2)
122122
, m_ctrl(cfg) {
123123
MJPEG_LOG("created");
124124
if (!m_task) {
@@ -147,6 +147,7 @@ MjpegResponse::_fillBuffer(uint8_t* buf, size_t buflen) {
147147
if (auto frame = m_task.retrieve(); frame) {
148148
m_ctrl.notifyReturn(std::move(frame));
149149
}
150+
m_sendSince = millis();
150151
m_sendNext = SIPartHeader;
151152
m_sendRemain = 0;
152153

@@ -160,6 +161,9 @@ MjpegResponse::_fillBuffer(uint8_t* buf, size_t buflen) {
160161
if (len == 0 && m_sendNext == SINone) {
161162
m_ctrl.notifySent(true);
162163
} else {
164+
if (static_cast<int>(millis() - m_sendSince) > m_ctrl.cfg.frameTimeout) {
165+
m_ctrl.notifySent(false);
166+
}
163167
return len;
164168
}
165169

@@ -190,11 +194,13 @@ MjpegResponse::sendPart(uint8_t* buf, size_t buflen) {
190194
m_sendRemain = m_hdr.size;
191195
m_sendNext = SIFrame;
192196
break;
193-
case SIFrame:
194-
m_sendBuf = m_ctrl.getFrame()->data();
195-
m_sendRemain = m_ctrl.getFrame()->size();
197+
case SIFrame: {
198+
Frame* frame = m_ctrl.getFrame();
199+
m_sendBuf = frame->data();
200+
m_sendRemain = frame->size();
196201
m_sendNext = SIPartTrailer;
197202
break;
203+
}
198204
case SIPartTrailer:
199205
m_hdr.preparePartTrailer();
200206
m_sendBuf = reinterpret_cast<const uint8_t*>(m_hdr.buf);

src/esp32cam/asyncweb.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ class MjpegResponse : public AsyncAbstractResponse {
113113
const uint8_t* m_sendBuf = nullptr;
114114
size_t m_sendRemain = 0;
115115
unsigned long m_createTime = millis();
116+
unsigned long m_sendSince = 0;
116117
};
117118

118119
/** @brief Handle HTTP request for MJPEG stream. */

src/esp32cam/mjpeg.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace esp32cam {
77
namespace detail {
88

99
MjpegController::MjpegController(MjpegConfig cfg)
10-
: m_cfg(cfg)
10+
: cfg(cfg)
1111
, m_nextCaptureTime(millis()) {}
1212

1313
int
@@ -25,7 +25,7 @@ MjpegController::decideAction() {
2525
void
2626
MjpegController::notifyCapture() {
2727
m_nextAction = RETURN;
28-
m_nextCaptureTime = millis() + static_cast<unsigned long>(m_cfg.minInterval);
28+
m_nextCaptureTime = millis() + static_cast<unsigned long>(cfg.minInterval);
2929
MC_LOG("notifyCapture next=%lu", m_nextCaptureTime);
3030
}
3131

@@ -51,7 +51,7 @@ MjpegController::notifySent(bool ok) {
5151
return;
5252
}
5353
m_frame.reset();
54-
m_nextAction = m_cfg.maxFrames < 0 || m_count < m_cfg.maxFrames ? CAPTURE : STOP;
54+
m_nextAction = cfg.maxFrames < 0 || m_count < cfg.maxFrames ? CAPTURE : STOP;
5555
}
5656

5757
void

src/esp32cam/mjpeg.hpp

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,21 @@
77

88
namespace esp32cam {
99

10+
/** MJPEG stream options. */
1011
struct MjpegConfig {
11-
/** @brief minimum interval between frame captures. */
12+
/**
13+
* @brief Minimum interval between frame captures in millis.
14+
*/
1215
int minInterval = 0;
13-
/** @brief maximum number of frames before disconnecting. */
16+
17+
/**
18+
* @brief Maximum number of frames before disconnecting.
19+
*
20+
* Negative value means unlimited.
21+
*/
1422
int maxFrames = -1;
15-
/** @brief time limit of writing one frame in millis. */
23+
24+
/** @brief Time limit of writing one frame in millis. */
1625
int frameTimeout = 10000;
1726
};
1827

@@ -23,23 +32,11 @@ class MjpegController {
2332
public:
2433
explicit MjpegController(MjpegConfig cfg);
2534

26-
/** @brief Retrieve config object. */
27-
const MjpegConfig& getConfig() const {
28-
return m_cfg;
29-
}
30-
3135
/** @brief Retrieve number of sent frames. */
3236
int countSentFrames() const {
3337
return m_count;
3438
}
3539

36-
enum {
37-
CAPTURE = -1,
38-
RETURN = -2,
39-
SEND = -3,
40-
STOP = -4,
41-
};
42-
4340
/**
4441
* @brief Decide what to do now.
4542
* @retval CAPTURE capture a frame.
@@ -72,6 +69,9 @@ class MjpegController {
7269
* @brief Notify that a frame is sent to the client.
7370
* @param ok whether sent successfully.
7471
* @post getFrame()==nullptr
72+
*
73+
* The caller is expected to enforce @c MjpegConfig::frameTimeout and call
74+
* `notifySent(false)` in case of send timeout.
7575
*/
7676
void notifySent(bool ok);
7777

@@ -82,8 +82,17 @@ class MjpegController {
8282
*/
8383
void notifyFail();
8484

85+
public:
86+
enum Action {
87+
CAPTURE = -1,
88+
RETURN = -2,
89+
SEND = -3,
90+
STOP = -4,
91+
};
92+
93+
const MjpegConfig cfg;
94+
8595
private:
86-
MjpegConfig m_cfg;
8796
std::unique_ptr<Frame> m_frame;
8897
unsigned long m_nextCaptureTime;
8998
int m_nextAction = CAPTURE;
@@ -105,7 +114,7 @@ class MjpegHeader {
105114

106115
public:
107116
size_t size = 0;
108-
char buf[160];
117+
char buf[120];
109118
};
110119

111120
} // namespace detail

0 commit comments

Comments
 (0)