diff options
author | Daniel Scally <dan.scally@ideasonboard.com> | 2023-01-10 08:49:30 +0000 |
---|---|---|
committer | Daniel Scally <dan.scally@ideasonboard.com> | 2023-01-16 15:22:38 +0000 |
commit | 29be8034518c0babbf6334d3ef6fc9ffe30e6b70 (patch) | |
tree | d1e58680f71b270e3b94dad162e5c45c645f6967 /include/uvcgadget | |
parent | 3a4e214882b362dc6dccd28d0862a258af75cf33 (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/uvcgadget')
-rw-r--r-- | include/uvcgadget/meson.build | 1 | ||||
-rw-r--r-- | include/uvcgadget/mjpeg_encoder.hpp | 89 |
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_ ; +}; |