Blackjack Decision Maker
libcamera_app.hpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3  * Copyright (C) 2020-2021, Raspberry Pi (Trading) Ltd.
4  *
5  * libcamera_app.hpp - base class for libcamera apps.
6  */
7 
8 #pragma once
9 
10 #include <sys/mman.h>
11 
12 #include <condition_variable>
13 #include <iostream>
14 #include <memory>
15 #include <mutex>
16 #include <queue>
17 #include <set>
18 #include <string>
19 #include <thread>
20 #include <variant>
21 #include <any>
22 #include <map>
23 #include <iomanip>
24 
25 #include <libcamera/base/span.h>
26 #include <libcamera/camera.h>
27 #include <libcamera/camera_manager.h>
28 #include <libcamera/control_ids.h>
29 #include <libcamera/controls.h>
30 #include <libcamera/formats.h>
31 #include <libcamera/framebuffer_allocator.h>
32 #include <libcamera/property_ids.h>
33 
34 class Options;
35 struct CompletedRequest;
36 using CompletedRequestPtr = std::shared_ptr<CompletedRequest>;
37 
38 namespace controls = libcamera::controls;
39 namespace properties = libcamera::properties;
40 
42 {
43 public:
44  using Stream = libcamera::Stream;
45  using FrameBuffer = libcamera::FrameBuffer;
46  using ControlList = libcamera::ControlList;
47  using Request = libcamera::Request;
48  using CameraManager = libcamera::CameraManager;
49  using Camera = libcamera::Camera;
50  using CameraConfiguration = libcamera::CameraConfiguration;
51  using FrameBufferAllocator = libcamera::FrameBufferAllocator;
52  using StreamRole = libcamera::StreamRole;
53  using StreamRoles = libcamera::StreamRoles;
54  using PixelFormat = libcamera::PixelFormat;
55  using StreamConfiguration = libcamera::StreamConfiguration;
56  using BufferMap = Request::BufferMap;
57  using Size = libcamera::Size;
58  using Rectangle = libcamera::Rectangle;
59  enum class MsgType
60  {
62  Quit
63  };
64  typedef std::variant<CompletedRequestPtr> MsgPayload;
65  struct Msg
66  {
67  Msg(MsgType const &t) : type(t) {}
68  template <typename T>
69  Msg(MsgType const &t, T p) : type(t), payload(std::forward<T>(p))
70  {
71  }
74  };
75 
76  // Some flags that can be used to give hints to the camera configuration.
77  static constexpr unsigned int FLAG_STILL_NONE = 0;
78  static constexpr unsigned int FLAG_STILL_BGR = 1; // supply BGR images, not YUV
79  static constexpr unsigned int FLAG_STILL_RGB = 2; // supply RGB images, not YUV
80  static constexpr unsigned int FLAG_STILL_RAW = 4; // request raw image stream
81  static constexpr unsigned int FLAG_STILL_DOUBLE_BUFFER = 8; // double-buffer stream
82  static constexpr unsigned int FLAG_STILL_TRIPLE_BUFFER = 16; // triple-buffer stream
83  static constexpr unsigned int FLAG_STILL_BUFFER_MASK = 24; // mask for buffer flags
84 
85  static constexpr unsigned int FLAG_VIDEO_NONE = 0;
86  static constexpr unsigned int FLAG_VIDEO_RAW = 1; // request raw image stream
87  static constexpr unsigned int FLAG_VIDEO_JPEG_COLOURSPACE = 2; // force JPEG colour space
88 
89  LibcameraApp(std::unique_ptr<Options> const opts = nullptr);
90  virtual ~LibcameraApp();
91 
92  Options *GetOptions() const { return options_.get(); }
93 
94  std::string const &CameraId() const;
95  void OpenCamera();
96  void CloseCamera();
97 
98  void ConfigureStill(unsigned int flags = FLAG_STILL_NONE);
99  void ConfigureViewfinder();
100 
101  void Teardown();
102  void StartCamera();
103  void StopCamera();
104 
105  Msg Wait();
106  void PostMessage(MsgType &t, MsgPayload &p);
107 
108  Stream *GetStream(std::string const &name, unsigned int *w = nullptr, unsigned int *h = nullptr,
109  unsigned int *stride = nullptr) const;
110  Stream *ViewfinderStream(unsigned int *w = nullptr, unsigned int *h = nullptr,
111  unsigned int *stride = nullptr) const;
112  Stream *StillStream(unsigned int *w = nullptr, unsigned int *h = nullptr, unsigned int *stride = nullptr) const;
113  Stream *RawStream(unsigned int *w = nullptr, unsigned int *h = nullptr, unsigned int *stride = nullptr) const;
114  Stream *VideoStream(unsigned int *w = nullptr, unsigned int *h = nullptr, unsigned int *stride = nullptr) const;
115  Stream *LoresStream(unsigned int *w = nullptr, unsigned int *h = nullptr, unsigned int *stride = nullptr) const;
116  Stream *GetMainStream() const;
117 
118  std::vector<libcamera::Span<uint8_t>> Mmap(FrameBuffer *buffer) const;
119 
120  void SetControls(ControlList &controls);
121  void StreamDimensions(Stream const *stream, unsigned int *w, unsigned int *h, unsigned int *stride) const;
122 
123 protected:
124  std::unique_ptr<Options> options_;
125 
126 private:
127  template <typename T>
128  class MessageQueue
129  {
130  public:
131  template <typename U>
132  void Post(U &&msg)
133  {
134  std::unique_lock<std::mutex> lock(mutex_);
135  queue_.push(std::forward<U>(msg));
136  cond_.notify_one();
137  }
138  T Wait()
139  {
140  std::unique_lock<std::mutex> lock(mutex_);
141  cond_.wait(lock, [this] { return !queue_.empty(); });
142  T msg = std::move(queue_.front());
143  queue_.pop();
144  return msg;
145  }
146  void Clear()
147  {
148  std::unique_lock<std::mutex> lock(mutex_);
149  queue_ = {};
150  }
151 
152  private:
153  std::queue<T> queue_;
154  std::mutex mutex_;
155  std::condition_variable cond_;
156  };
157 
158  void setupCapture();
159  void makeRequests();
160  void queueRequest(CompletedRequest *completed_request);
161  void requestComplete(Request *request);
162  void configureDenoise(const std::string &denoise_mode);
163 
164  std::unique_ptr<CameraManager> camera_manager_;
165  std::shared_ptr<Camera> camera_;
166  bool camera_acquired_ = false;
167  std::unique_ptr<CameraConfiguration> configuration_;
168  std::map<FrameBuffer *, std::vector<libcamera::Span<uint8_t>>> mapped_buffers_;
169  std::map<std::string, Stream *> streams_;
170  FrameBufferAllocator *allocator_ = nullptr;
171  std::map<Stream *, std::queue<FrameBuffer *>> frame_buffers_;
172  std::queue<Request *> free_requests_;
173  std::vector<std::unique_ptr<Request>> requests_;
174  std::mutex completed_requests_mutex_;
175  std::set<CompletedRequest *> completed_requests_;
176  bool camera_started_ = false;
177  std::mutex camera_stop_mutex_;
178  MessageQueue<Msg> msg_queue_;
179  // For setting camera controls.
180  std::mutex control_mutex_;
181  ControlList controls_;
182  // Other:
183  uint64_t last_timestamp_;
184  uint64_t sequence_ = 0;
185 };
186 
187 struct FrameInfo
188 {
189  FrameInfo(libcamera::ControlList &ctrls)
190  : exposure_time(0.0), digital_gain(0.0), colour_gains({ { 0.0f, 0.0f } }), focus(0.0), aelock(false)
191  {
192  auto exp = ctrls.get(libcamera::controls::ExposureTime);
193  if (exp)
194  exposure_time = *exp;
195 
196  auto ag = ctrls.get(libcamera::controls::AnalogueGain);
197  if (ag)
198  analogue_gain = *ag;
199 
200  auto dg = ctrls.get(libcamera::controls::DigitalGain);
201  if (dg)
202  digital_gain = *dg;
203 
204  auto cg = ctrls.get(libcamera::controls::ColourGains);
205  if (cg)
206  {
207  colour_gains[0] = (*cg)[0], colour_gains[1] = (*cg)[1];
208  }
209 
210  auto fom = ctrls.get(libcamera::controls::FocusFoM);
211  if (fom)
212  focus = *fom;
213 
214  auto ae = ctrls.get(libcamera::controls::AeLocked);
215  if (ae)
216  aelock = *ae;
217  }
218 
219  std::string ToString(std::string &info_string) const
220  {
221  std::string parsed(info_string);
222 
223  for (auto const &t : tokens)
224  {
225  std::size_t pos = parsed.find(t);
226  if (pos != std::string::npos)
227  {
228  std::stringstream value;
229  value << std::fixed << std::setprecision(2);
230 
231  if (t == "%frame")
232  value << sequence;
233  else if (t == "%fps")
234  value << fps;
235  else if (t == "%exp")
236  value << exposure_time;
237  else if (t == "%ag")
238  value << analogue_gain;
239  else if (t == "%dg")
240  value << digital_gain;
241  else if (t == "%rg")
242  value << colour_gains[0];
243  else if (t == "%bg")
244  value << colour_gains[1];
245  else if (t == "%focus")
246  value << focus;
247  else if (t == "%aelock")
248  value << aelock;
249 
250  parsed.replace(pos, t.length(), value.str());
251  }
252  }
253 
254  return parsed;
255  }
256 
257  unsigned int sequence;
261  std::array<float, 2> colour_gains;
262  float focus;
263  float fps;
264  bool aelock;
265 
266 private:
267  // Info text tokens.
268  inline static const std::string tokens[] = { "%frame", "%fps", "%exp", "%ag", "%dg",
269  "%rg", "%bg", "%focus", "%aelock" };
270 };
271 
272 class Metadata
273 {
274 public:
275  Metadata() = default;
276 
277  Metadata(Metadata const &other)
278  {
279  std::scoped_lock other_lock(other.mutex_);
280  data_ = other.data_;
281  }
282 
284  {
285  std::scoped_lock other_lock(other.mutex_);
286  data_ = std::move(other.data_);
287  other.data_.clear();
288  }
289 
290  template <typename T>
291  void Set(std::string const &tag, T &&value)
292  {
293  std::scoped_lock lock(mutex_);
294  data_.insert_or_assign(tag, std::forward<T>(value));
295  }
296 
297  template <typename T>
298  int Get(std::string const &tag, T &value) const
299  {
300  std::scoped_lock lock(mutex_);
301  auto it = data_.find(tag);
302  if (it == data_.end())
303  return -1;
304  value = std::any_cast<T>(it->second);
305  return 0;
306  }
307 
308  void Clear()
309  {
310  std::scoped_lock lock(mutex_);
311  data_.clear();
312  }
313 
314  Metadata &operator=(Metadata const &other)
315  {
316  std::scoped_lock lock(mutex_, other.mutex_);
317  data_ = other.data_;
318  return *this;
319  }
320 
322  {
323  std::scoped_lock lock(mutex_, other.mutex_);
324  data_ = std::move(other.data_);
325  other.data_.clear();
326  return *this;
327  }
328 
329  void Merge(Metadata &other)
330  {
331  std::scoped_lock lock(mutex_, other.mutex_);
332  data_.merge(other.data_);
333  }
334 
335  template <typename T>
336  T *GetLocked(std::string const &tag)
337  {
338  // This allows in-place access to the Metadata contents,
339  // for which you should be holding the lock.
340  auto it = data_.find(tag);
341  if (it == data_.end())
342  return nullptr;
343  return std::any_cast<T>(&it->second);
344  }
345 
346  template <typename T>
347  void SetLocked(std::string const &tag, T &&value)
348  {
349  // Use this only if you're holding the lock yourself.
350  data_.insert_or_assign(tag, std::forward<T>(value));
351  }
352 
353  // Note: use of (lowercase) lock and unlock means you can create scoped
354  // locks with the standard lock classes.
355  // e.g. std::lock_guard<RPiController::Metadata> lock(metadata)
356  void lock() { mutex_.lock(); }
357  void unlock() { mutex_.unlock(); }
358 
359 private:
360  mutable std::mutex mutex_;
361  std::map<std::string, std::any> data_;
362 };
363 
365 {
366  using BufferMap = libcamera::Request::BufferMap;
367  using ControlList = libcamera::ControlList;
368  using Request = libcamera::Request;
369 
370  CompletedRequest(unsigned int seq, Request *r)
371  : sequence(seq), buffers(r->buffers()), metadata(r->metadata()), request(r)
372  {
373  r->reuse();
374  }
375  unsigned int sequence;
379  float framerate;
381 };
Class for initialising a Camera object and capturing frames.
Definition: Camera.h:45
Definition: libcamera_app.hpp:42
void StopCamera()
Definition: libcamera_app.cpp:250
libcamera::ControlList ControlList
Definition: libcamera_app.hpp:46
libcamera::Rectangle Rectangle
Definition: libcamera_app.hpp:58
void ConfigureViewfinder()
Definition: libcamera_app.cpp:123
static constexpr unsigned int FLAG_STILL_DOUBLE_BUFFER
Definition: libcamera_app.hpp:81
static constexpr unsigned int FLAG_VIDEO_JPEG_COLOURSPACE
Definition: libcamera_app.hpp:87
Stream * StillStream(unsigned int *w=nullptr, unsigned int *h=nullptr, unsigned int *stride=nullptr) const
Definition: libcamera_app.cpp:348
static constexpr unsigned int FLAG_STILL_BUFFER_MASK
Definition: libcamera_app.hpp:83
Stream * ViewfinderStream(unsigned int *w=nullptr, unsigned int *h=nullptr, unsigned int *stride=nullptr) const
Definition: libcamera_app.cpp:343
libcamera::CameraConfiguration CameraConfiguration
Definition: libcamera_app.hpp:50
libcamera::Size Size
Definition: libcamera_app.hpp:57
Stream * LoresStream(unsigned int *w=nullptr, unsigned int *h=nullptr, unsigned int *stride=nullptr) const
Definition: libcamera_app.cpp:363
libcamera::StreamConfiguration StreamConfiguration
Definition: libcamera_app.hpp:55
static constexpr unsigned int FLAG_STILL_NONE
Definition: libcamera_app.hpp:77
void Teardown()
Definition: libcamera_app.cpp:150
virtual ~LibcameraApp()
Definition: libcamera_app.cpp:20
libcamera::StreamRoles StreamRoles
Definition: libcamera_app.hpp:53
void CloseCamera()
Definition: libcamera_app.cpp:62
libcamera::StreamRole StreamRole
Definition: libcamera_app.hpp:52
Options * GetOptions() const
Definition: libcamera_app.hpp:92
static constexpr unsigned int FLAG_STILL_TRIPLE_BUFFER
Definition: libcamera_app.hpp:82
void PostMessage(MsgType &t, MsgPayload &p)
Definition: libcamera_app.cpp:328
std::unique_ptr< Options > options_
Definition: libcamera_app.hpp:124
static constexpr unsigned int FLAG_STILL_RAW
Definition: libcamera_app.hpp:80
void OpenCamera()
Definition: libcamera_app.cpp:32
libcamera::FrameBufferAllocator FrameBufferAllocator
Definition: libcamera_app.hpp:51
libcamera::Request Request
Definition: libcamera_app.hpp:47
LibcameraApp(std::unique_ptr< Options > const opts=nullptr)
Definition: libcamera_app.cpp:11
void StreamDimensions(Stream const *stream, unsigned int *w, unsigned int *h, unsigned int *stride) const
Definition: libcamera_app.cpp:393
Request::BufferMap BufferMap
Definition: libcamera_app.hpp:56
static constexpr unsigned int FLAG_VIDEO_NONE
Definition: libcamera_app.hpp:85
libcamera::PixelFormat PixelFormat
Definition: libcamera_app.hpp:54
std::variant< CompletedRequestPtr > MsgPayload
Definition: libcamera_app.hpp:64
std::vector< libcamera::Span< uint8_t > > Mmap(FrameBuffer *buffer) const
Definition: libcamera_app.cpp:379
Stream * VideoStream(unsigned int *w=nullptr, unsigned int *h=nullptr, unsigned int *stride=nullptr) const
Definition: libcamera_app.cpp:358
static constexpr unsigned int FLAG_STILL_BGR
Definition: libcamera_app.hpp:78
Msg Wait()
Definition: libcamera_app.cpp:284
Stream * GetStream(std::string const &name, unsigned int *w=nullptr, unsigned int *h=nullptr, unsigned int *stride=nullptr) const
Definition: libcamera_app.cpp:333
void ConfigureStill(unsigned int flags=FLAG_STILL_NONE)
Definition: libcamera_app.cpp:76
static constexpr unsigned int FLAG_VIDEO_RAW
Definition: libcamera_app.hpp:86
std::string const & CameraId() const
Definition: libcamera_app.cpp:27
libcamera::Stream Stream
Definition: libcamera_app.hpp:44
libcamera::FrameBuffer FrameBuffer
Definition: libcamera_app.hpp:45
void SetControls(ControlList &controls)
Definition: libcamera_app.cpp:387
Stream * RawStream(unsigned int *w=nullptr, unsigned int *h=nullptr, unsigned int *stride=nullptr) const
Definition: libcamera_app.cpp:353
MsgType
Definition: libcamera_app.hpp:60
Stream * GetMainStream() const
Definition: libcamera_app.cpp:368
libcamera::CameraManager CameraManager
Definition: libcamera_app.hpp:48
void StartCamera()
Definition: libcamera_app.cpp:174
static constexpr unsigned int FLAG_STILL_RGB
Definition: libcamera_app.hpp:79
Definition: libcamera_app.hpp:273
void lock()
Definition: libcamera_app.hpp:356
Metadata & operator=(Metadata const &other)
Definition: libcamera_app.hpp:314
void Merge(Metadata &other)
Definition: libcamera_app.hpp:329
void SetLocked(std::string const &tag, T &&value)
Definition: libcamera_app.hpp:347
void Set(std::string const &tag, T &&value)
Definition: libcamera_app.hpp:291
Metadata(Metadata const &other)
Definition: libcamera_app.hpp:277
T * GetLocked(std::string const &tag)
Definition: libcamera_app.hpp:336
void Clear()
Definition: libcamera_app.hpp:308
int Get(std::string const &tag, T &value) const
Definition: libcamera_app.hpp:298
Metadata(Metadata &&other)
Definition: libcamera_app.hpp:283
Metadata()=default
void unlock()
Definition: libcamera_app.hpp:357
Metadata & operator=(Metadata &&other)
Definition: libcamera_app.hpp:321
Definition: libcamera_app_options.hpp:45
std::shared_ptr< CompletedRequest > CompletedRequestPtr
Definition: libcamera_app.hpp:36
Definition: libcamera_app.hpp:365
libcamera::Request Request
Definition: libcamera_app.hpp:368
CompletedRequest(unsigned int seq, Request *r)
Definition: libcamera_app.hpp:370
float framerate
Definition: libcamera_app.hpp:379
libcamera::ControlList ControlList
Definition: libcamera_app.hpp:367
Metadata post_process_metadata
Definition: libcamera_app.hpp:380
Request * request
Definition: libcamera_app.hpp:378
ControlList metadata
Definition: libcamera_app.hpp:377
libcamera::Request::BufferMap BufferMap
Definition: libcamera_app.hpp:366
BufferMap buffers
Definition: libcamera_app.hpp:376
unsigned int sequence
Definition: libcamera_app.hpp:375
Definition: libcamera_app.hpp:188
std::array< float, 2 > colour_gains
Definition: libcamera_app.hpp:261
float digital_gain
Definition: libcamera_app.hpp:260
float exposure_time
Definition: libcamera_app.hpp:258
float focus
Definition: libcamera_app.hpp:262
float analogue_gain
Definition: libcamera_app.hpp:259
std::string ToString(std::string &info_string) const
Definition: libcamera_app.hpp:219
bool aelock
Definition: libcamera_app.hpp:264
float fps
Definition: libcamera_app.hpp:263
unsigned int sequence
Definition: libcamera_app.hpp:257
FrameInfo(libcamera::ControlList &ctrls)
Definition: libcamera_app.hpp:189
Definition: libcamera_app.hpp:66
MsgPayload payload
Definition: libcamera_app.hpp:73
Msg(MsgType const &t)
Definition: libcamera_app.hpp:67
Msg(MsgType const &t, T p)
Definition: libcamera_app.hpp:69
MsgType type
Definition: libcamera_app.hpp:72