11#include <promeki/config.h>
12#if PROMEKI_ENABLE_HTTP
31PROMEKI_NAMESPACE_BEGIN
69class MjpegStreamSubscriber {
72 virtual ~MjpegStreamSubscriber() =
default;
90 virtual void onFrame(
const Buffer &jpeg,
const TimeStamp &ts) = 0;
101 virtual void onClosed() = 0;
114struct MjpegStreamSnapshot {
116 int64_t framesEncoded = 0;
118 int64_t framesRateLimited = 0;
120 int64_t framesEncodeError = 0;
122 int64_t totalEncodeUs = 0;
124 int64_t peakEncodeUs = 0;
126 int64_t encodeSamples = 0;
128 int64_t totalEncodedBytes = 0;
198class MjpegStreamMediaIO :
public DedicatedThreadMediaIO {
199 PROMEKI_OBJECT(MjpegStreamMediaIO, DedicatedThreadMediaIO)
202 static const String HttpBoundary;
205 static const String LatestJpegContentType;
208 MjpegStreamMediaIO(ObjectBase *parent =
nullptr);
218 ~MjpegStreamMediaIO()
override;
247 int attachSubscriber(MjpegStreamSubscriber *s);
263 void detachSubscriber(
int id);
272 bool isStreaming()
const;
289 Buffer latestJpeg()
const;
303 TimeStamp latestJpegTimestamp()
const;
315 MjpegStreamSnapshot snapshot()
const;
363 void registerHttpRoute(HttpServer &server,
const String &path);
390 static HttpHandlerFunc buildMultipartHandler(MjpegStreamMediaIO *sink);
392 Error proposeInput(
const MediaDesc &offered, MediaDesc *preferred)
const override;
395 Error executeCmd(MediaIOCommandOpen &cmd)
override;
396 Error executeCmd(MediaIOCommandClose &cmd)
override;
397 Error executeCmd(MediaIOCommandWrite &cmd)
override;
398 Error executeCmd(MediaIOCommandStats &cmd)
override;
403 Error encodeFrame(
const Frame &frame, Buffer *out, TimeStamp *ts);
406 bool latestRingEntry(Buffer *out, TimeStamp *outTs)
const;
409 void publishEncoded(
const Buffer &jpeg,
const TimeStamp &ts);
416 bool _isOpen =
false;
420 UniquePtr<VideoEncoder> _encoder;
424 TimeStamp _lastEncoded;
425 bool _hasLastEncoded =
false;
426 int64_t _frameSerial = 0;
434 mutable Mutex _stateMutex;
435 List<RingEntry> _ring;
436 Map<int, MjpegStreamSubscriber *> _subscribers;
437 int _nextSubscriberId = 1;
438 MjpegStreamSnapshot _stats;
442 bool _isStreaming =
false;
449class MjpegStreamFactory :
public MediaIOFactory {
451 MjpegStreamFactory() =
default;
453 String name()
const override {
return String(
"MjpegStream"); }
454 String displayName()
const override {
return String(
"MJPEG Preview Stream"); }
455 String description()
const override {
456 return String(
"Frame-rate-limited motion-JPEG preview sink "
457 "(HTTP multipart-friendly).");
460 bool canBeSink()
const override {
return true; }
462 Config::SpecMap configSpecs()
const override;
464 MediaIO *create(
const Config &config, ObjectBase *parent =
nullptr)
const override;