summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorDaniel Scally <dan.scally@ideasonboard.com>2023-01-10 08:49:30 +0000
committerDaniel Scally <dan.scally@ideasonboard.com>2023-01-16 15:22:38 +0000
commit29be8034518c0babbf6334d3ef6fc9ffe30e6b70 (patch)
treed1e58680f71b270e3b94dad162e5c45c645f6967 /include
parent3a4e214882b362dc6dccd28d0862a258af75cf33 (diff)
lib/mjpeg_encoder: Add an MJPEG encoder for YUV420 data
MJPEG is an extremely useful format given its compression allows high framerates even over limited bandwith USB connections. Add an MJPEG encoder class that converts YUV420 data into MJPEG data. Where a libcamera-source does not support MJPEG natively, convert YUV420 into MJPEG if the user tries to set MJPEG format. Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com>
Diffstat (limited to 'include')
-rw-r--r--include/uvcgadget/meson.build1
-rw-r--r--include/uvcgadget/mjpeg_encoder.hpp89
2 files changed, 90 insertions, 0 deletions
diff --git a/include/uvcgadget/meson.build b/include/uvcgadget/meson.build
index a9e4384..af795c4 100644
--- a/include/uvcgadget/meson.build
+++ b/include/uvcgadget/meson.build
@@ -9,6 +9,7 @@ uvcgadget_public_headers = files([
'timer.h',
'v4l2-source.h',
'video-source.h',
+ 'mjpeg_encoder.hpp',
])
diff --git a/include/uvcgadget/mjpeg_encoder.hpp b/include/uvcgadget/mjpeg_encoder.hpp
new file mode 100644
index 0000000..a3e92fc
--- /dev/null
+++ b/include/uvcgadget/mjpeg_encoder.hpp
@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (C) 2020, Raspberry Pi (Trading) Ltd.
+ *
+ * mjpeg_encoder.hpp - mjpeg video encoder.
+ */
+
+#pragma once
+
+#include <condition_variable>
+#include <mutex>
+#include <queue>
+#include <thread>
+#include <functional>
+
+struct jpeg_compress_struct;
+typedef std::function<void(void *, size_t, int64_t, unsigned int)> OutputReadyCallback;
+
+struct StreamInfo
+{
+ StreamInfo() : width(0), height(0), stride(0) {}
+ unsigned int width;
+ unsigned int height;
+ unsigned int stride;
+ libcamera::PixelFormat pixel_format;
+ std::optional<libcamera::ColorSpace> colour_space;
+};
+
+class MjpegEncoder
+{
+public:
+ MjpegEncoder();
+ ~MjpegEncoder();
+
+ void EncodeBuffer(void *mem, void *dest, unsigned int size,
+ StreamInfo const &info, int64_t timestamp_us,
+ unsigned int cookie);
+ StreamInfo getStreamInfo(libcamera::Stream *stream);
+ void SetOutputReadyCallback(OutputReadyCallback callback) { output_ready_callback_ = callback; }
+
+private:
+ static const int NUM_ENC_THREADS = 4;
+
+ void encodeThread(int num);
+
+ /*
+ * Handle the output buffers in another thread so as not to block the
+ * encoders. The application can take its time, after which we return
+ * this buffer to the encoder for re-use.
+ */
+ void outputThread();
+
+ bool abortEncode_;
+ bool abortOutput_;
+ uint64_t index_;
+
+ struct EncodeItem
+ {
+ void *mem;
+ void *dest;
+ unsigned int size;
+ StreamInfo info;
+ int64_t timestamp_us;
+ uint64_t index;
+ unsigned int cookie;
+ };
+
+ std::queue<EncodeItem> encode_queue_;
+ std::mutex encode_mutex_;
+ std::condition_variable encode_cond_var_;
+ std::thread encode_thread_[NUM_ENC_THREADS];
+ void encodeJPEG(struct jpeg_compress_struct &cinfo, EncodeItem &item,
+ uint8_t *&encoded_buffer, size_t &buffer_len);
+
+ struct OutputItem
+ {
+ void *mem;
+ size_t bytes_used;
+ int64_t timestamp_us;
+ uint64_t index;
+ unsigned int cookie;
+ };
+
+ std::queue<OutputItem> output_queue_[NUM_ENC_THREADS];
+ std::mutex output_mutex_;
+ std::condition_variable output_cond_var_;
+ std::thread output_thread_;
+ OutputReadyCallback output_ready_callback_ ;
+};