blob: 4906d8e2402c560f82485a82128e1a11b8b41d05 [file] [log] [blame]
Jim Ostrowski977850f2022-01-22 21:04:22 -08001#ifndef FRC971_VISION_V4L2_READER_H_
2#define FRC971_VISION_V4L2_READER_H_
Brian Silverman9dd793b2020-01-31 23:52:21 -08003
4#include <array>
5#include <string>
6
7#include "absl/types/span.h"
Philipp Schrader790cb542023-07-05 21:06:52 -07008#include "glog/logging.h"
9
Ravago Jonesc6b919f2023-01-01 21:34:12 -080010#include "aos/containers/ring_buffer.h"
Ravago Jonesdc524752022-12-27 01:15:13 -080011#include "aos/events/epoll.h"
Brian Silverman9dd793b2020-01-31 23:52:21 -080012#include "aos/events/event_loop.h"
Austin Schuhe4acc1e2022-12-26 14:01:34 -080013#include "aos/ftrace.h"
Ravago Jonesc6b919f2023-01-01 21:34:12 -080014#include "aos/realtime.h"
Brian Silverman9dd793b2020-01-31 23:52:21 -080015#include "aos/scoped/scoped_fd.h"
Ravago Jonesc6b919f2023-01-01 21:34:12 -080016#include "aos/util/threaded_consumer.h"
Jim Ostrowski977850f2022-01-22 21:04:22 -080017#include "frc971/vision/vision_generated.h"
Brian Silverman9dd793b2020-01-31 23:52:21 -080018
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -080019namespace frc971::vision {
Brian Silverman9dd793b2020-01-31 23:52:21 -080020
21// Reads images from a V4L2 capture device (aka camera).
Austin Schuh77d0bbd2022-12-26 14:00:51 -080022class V4L2ReaderBase {
Brian Silverman9dd793b2020-01-31 23:52:21 -080023 public:
24 // device_name is the name of the device file (like "/dev/video0").
milind-ufd08c432023-02-05 15:15:21 -080025 // image_channel is the channel to send images on
26 V4L2ReaderBase(aos::EventLoop *event_loop, std::string_view device_name,
27 std::string_view image_channel);
Brian Silverman9dd793b2020-01-31 23:52:21 -080028
Austin Schuh77d0bbd2022-12-26 14:00:51 -080029 V4L2ReaderBase(const V4L2ReaderBase &) = delete;
30 V4L2ReaderBase &operator=(const V4L2ReaderBase &) = delete;
Brian Silverman9dd793b2020-01-31 23:52:21 -080031
32 // Reads the latest image.
33 //
Brian Silverman967e5df2020-02-09 16:43:34 -080034 // Returns false if no image was available since the last image was read.
35 // Call LatestImage() to get a reference to the data, which will be valid
36 // until this method is called again.
37 bool ReadLatestImage();
Brian Silverman9dd793b2020-01-31 23:52:21 -080038
Ravago Jones65469be2023-01-13 21:28:23 -080039 void MaybeEnqueue();
40
Brian Silverman9dd793b2020-01-31 23:52:21 -080041 // Sends the latest image.
42 //
43 // ReadLatestImage() must have returned a non-empty span the last time it was
44 // called. After calling this, the data which was returned from
45 // ReadLatestImage() will no longer be valid.
46 void SendLatestImage();
47
Brian Silverman967e5df2020-02-09 16:43:34 -080048 const CameraImage &LatestImage() {
49 Buffer *const buffer = &buffers_[saved_buffer_.index];
50 return *flatbuffers::GetTemporaryPointer(*buffer->builder.fbb(),
51 buffer->message_offset);
52 }
53
milind-udaebe9b2022-01-09 18:25:24 -080054 // Sets the exposure duration of the camera. duration is the number of 100
55 // microsecond units.
Ravago Jones65469be2023-01-13 21:28:23 -080056 virtual void SetExposure(size_t duration);
milind-udaebe9b2022-01-09 18:25:24 -080057
58 // Switches from manual to auto exposure.
59 void UseAutoExposure();
60
Austin Schuh77d0bbd2022-12-26 14:00:51 -080061 protected:
62 void StreamOff();
63 void StreamOn();
64
Ravago Jonesc6b919f2023-01-01 21:34:12 -080065 // Enqueues a buffer for v4l2 to stream into (expensive).
66 void EnqueueBuffer(int buffer_index);
67
68 // Initializations that need to happen in the main thread.
69 //
70 // Implementations of MarkBufferToBeEnqueued should call this before calling
71 // EnqueueBuffer.
72 void ReinitializeBuffer(int buffer_index) {
73 CHECK_GE(buffer_index, 0);
74 CHECK_LT(buffer_index, static_cast<int>(buffers_.size()));
75 buffers_[buffer_index].InitializeMessage(ImageSize());
76 }
77
78 // Submits a buffer to be enqueued later in a lower priority thread.
79 // Legacy V4L2Reader still does this in the main thread.
80 virtual void MarkBufferToBeEnqueued(int buffer_index);
81
Austin Schuh77d0bbd2022-12-26 14:00:51 -080082 int Ioctl(unsigned long number, void *arg);
83
84 bool multiplanar() const { return multiplanar_; }
85
86 // TODO(Brian): This concept won't exist once we start using variable-size
87 // H.264 frames.
milind-u6b094092023-01-09 19:26:12 -080088 size_t ImageSize() const { return ImageSize(rows_, cols_); }
89 static size_t ImageSize(int rows, int cols) {
90 return rows * cols * 2 /* bytes per pixel */;
91 }
Austin Schuh77d0bbd2022-12-26 14:00:51 -080092
Ravago Jonesdc524752022-12-27 01:15:13 -080093 const aos::ScopedFD &fd() { return fd_; };
94
Austin Schuh77d0bbd2022-12-26 14:00:51 -080095 static constexpr int kNumberBuffers = 4;
Brian Silverman9dd793b2020-01-31 23:52:21 -080096
Ravago Jonesc6b919f2023-01-01 21:34:12 -080097 private:
Brian Silverman9dd793b2020-01-31 23:52:21 -080098 struct Buffer {
Brian Silverman967e5df2020-02-09 16:43:34 -080099 void InitializeMessage(size_t max_image_size);
Brian Silverman9dd793b2020-01-31 23:52:21 -0800100
Brian Silverman967e5df2020-02-09 16:43:34 -0800101 void PrepareMessage(int rows, int cols, size_t image_size,
102 aos::monotonic_clock::time_point monotonic_eof);
103
104 void Send() {
Ravago Jonesda1b0082023-01-21 15:33:19 -0800105 builder.CheckOk(builder.Send(message_offset));
Brian Silverman967e5df2020-02-09 16:43:34 -0800106 message_offset = flatbuffers::Offset<CameraImage>();
Brian Silverman9dd793b2020-01-31 23:52:21 -0800107 }
108
109 absl::Span<const char> DataSpan(size_t image_size) {
Austin Schuh6bdcc372024-06-27 14:49:11 -0700110 CHECK(data_pointer != nullptr);
111 return absl::Span<const char>(reinterpret_cast<char *>(data_pointer),
112 image_size);
Brian Silverman9dd793b2020-01-31 23:52:21 -0800113 }
114
115 aos::Sender<CameraImage> sender;
116 aos::Sender<CameraImage>::Builder builder;
Brian Silverman967e5df2020-02-09 16:43:34 -0800117 flatbuffers::Offset<CameraImage> message_offset;
Brian Silverman9dd793b2020-01-31 23:52:21 -0800118
119 uint8_t *data_pointer = nullptr;
milind-ufd08c432023-02-05 15:15:21 -0800120
121 std::string_view image_channel_;
Brian Silverman9dd793b2020-01-31 23:52:21 -0800122 };
123
Brian Silverman967e5df2020-02-09 16:43:34 -0800124 struct BufferInfo {
125 int index = -1;
126 aos::monotonic_clock::time_point monotonic_eof =
127 aos::monotonic_clock::min_time;
128
129 explicit operator bool() const { return index != -1; }
130
131 void Clear() {
132 index = -1;
133 monotonic_eof = aos::monotonic_clock::min_time;
134 }
135 };
136
Brian Silverman9dd793b2020-01-31 23:52:21 -0800137 // Attempts to dequeue a buffer (nonblocking). Returns the index of the new
Brian Silverman967e5df2020-02-09 16:43:34 -0800138 // buffer, or BufferInfo() if there wasn't a frame to dequeue.
139 BufferInfo DequeueBuffer();
Brian Silverman9dd793b2020-01-31 23:52:21 -0800140
Brian Silverman9dd793b2020-01-31 23:52:21 -0800141 // The mmaped V4L2 buffers.
142 std::array<Buffer, kNumberBuffers> buffers_;
143
144 // If this is non-negative, it's the buffer number we're currently holding
145 // onto.
Brian Silverman967e5df2020-02-09 16:43:34 -0800146 BufferInfo saved_buffer_;
Brian Silverman9dd793b2020-01-31 23:52:21 -0800147
Austin Schuh77d0bbd2022-12-26 14:00:51 -0800148 bool multiplanar_ = false;
149
150 int rows_ = 0;
151 int cols_ = 0;
Brian Silverman9dd793b2020-01-31 23:52:21 -0800152
153 aos::ScopedFD fd_;
Austin Schuh77d0bbd2022-12-26 14:00:51 -0800154
155 aos::EventLoop *event_loop_;
156 aos::Ftrace ftrace_;
milind-ufd08c432023-02-05 15:15:21 -0800157
158 std::string_view image_channel_;
Austin Schuh77d0bbd2022-12-26 14:00:51 -0800159};
160
161// Generic V4L2 reader for pi's and older.
162class V4L2Reader : public V4L2ReaderBase {
163 public:
milind-ufd08c432023-02-05 15:15:21 -0800164 V4L2Reader(aos::EventLoop *event_loop, std::string_view device_name,
165 std::string_view image_channel = "/camera");
Austin Schuh77d0bbd2022-12-26 14:00:51 -0800166};
167
168// Rockpi specific v4l2 reader. This assumes that the media device has been
169// properly configured before this class is constructed.
170class RockchipV4L2Reader : public V4L2ReaderBase {
171 public:
Ravago Jonesdc524752022-12-27 01:15:13 -0800172 RockchipV4L2Reader(aos::EventLoop *event_loop, aos::internal::EPoll *epoll,
milind-ufd08c432023-02-05 15:15:21 -0800173 std::string_view device_name,
174 std::string_view image_sensor_subdev,
175 std::string_view image_channel = "/camera");
Ravago Jones65469be2023-01-13 21:28:23 -0800176
milind-ufd08c432023-02-05 15:15:21 -0800177 virtual ~RockchipV4L2Reader();
Ravago Jonesfd8aa202023-01-16 14:21:45 -0800178
Ravago Jones65469be2023-01-13 21:28:23 -0800179 void SetExposure(size_t duration) override;
180
181 void SetGain(size_t gain);
Ravago Jonesa0a2e062023-01-03 21:45:18 -0800182 void SetGainExt(size_t gain);
183
Ravago Jonesda1b0082023-01-21 15:33:19 -0800184 void SetVerticalBlanking(size_t vblank);
Ravago Jonesdc524752022-12-27 01:15:13 -0800185
186 private:
187 void OnImageReady();
188
Ravago Jonesc6b919f2023-01-01 21:34:12 -0800189 void MarkBufferToBeEnqueued(int buffer) override;
190
Ravago Jones65469be2023-01-13 21:28:23 -0800191 int ImageSensorIoctl(unsigned long number, void *arg);
192
Ravago Jonesdc524752022-12-27 01:15:13 -0800193 aos::internal::EPoll *epoll_;
Ravago Jones65469be2023-01-13 21:28:23 -0800194
195 aos::ScopedFD image_sensor_fd_;
Ravago Jonesc6b919f2023-01-01 21:34:12 -0800196
Austin Schuh2cd5fe82023-02-04 16:21:19 -0800197 static constexpr int kEnqueueFifoPriority = 1;
198
Ravago Jonesc6b919f2023-01-01 21:34:12 -0800199 aos::util::ThreadedConsumer<int, kNumberBuffers> buffer_requeuer_;
Brian Silverman9dd793b2020-01-31 23:52:21 -0800200};
201
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -0800202} // namespace frc971::vision
Brian Silverman9dd793b2020-01-31 23:52:21 -0800203
Jim Ostrowski977850f2022-01-22 21:04:22 -0800204#endif // FRC971_VISION_V4L2_READER_H_