blob: 669c1576cc12f4ce3eabd8db997419aa36e0fa98 [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"
Ravago Jonesdc524752022-12-27 01:15:13 -08008#include "aos/events/epoll.h"
Brian Silverman9dd793b2020-01-31 23:52:21 -08009#include "aos/events/event_loop.h"
Austin Schuhe4acc1e2022-12-26 14:01:34 -080010#include "aos/ftrace.h"
Brian Silverman9dd793b2020-01-31 23:52:21 -080011#include "aos/scoped/scoped_fd.h"
Jim Ostrowski977850f2022-01-22 21:04:22 -080012#include "frc971/vision/vision_generated.h"
Austin Schuh77d0bbd2022-12-26 14:00:51 -080013#include "glog/logging.h"
Brian Silverman9dd793b2020-01-31 23:52:21 -080014
15namespace frc971 {
16namespace vision {
17
18// Reads images from a V4L2 capture device (aka camera).
Austin Schuh77d0bbd2022-12-26 14:00:51 -080019class V4L2ReaderBase {
Brian Silverman9dd793b2020-01-31 23:52:21 -080020 public:
21 // device_name is the name of the device file (like "/dev/video0").
Austin Schuh77d0bbd2022-12-26 14:00:51 -080022 V4L2ReaderBase(aos::EventLoop *event_loop, const std::string &device_name);
Brian Silverman9dd793b2020-01-31 23:52:21 -080023
Austin Schuh77d0bbd2022-12-26 14:00:51 -080024 V4L2ReaderBase(const V4L2ReaderBase &) = delete;
25 V4L2ReaderBase &operator=(const V4L2ReaderBase &) = delete;
Brian Silverman9dd793b2020-01-31 23:52:21 -080026
27 // Reads the latest image.
28 //
Brian Silverman967e5df2020-02-09 16:43:34 -080029 // Returns false if no image was available since the last image was read.
30 // Call LatestImage() to get a reference to the data, which will be valid
31 // until this method is called again.
32 bool ReadLatestImage();
Brian Silverman9dd793b2020-01-31 23:52:21 -080033
Ravago Jones65469be2023-01-13 21:28:23 -080034 void MaybeEnqueue();
35
Brian Silverman9dd793b2020-01-31 23:52:21 -080036 // Sends the latest image.
37 //
38 // ReadLatestImage() must have returned a non-empty span the last time it was
39 // called. After calling this, the data which was returned from
40 // ReadLatestImage() will no longer be valid.
41 void SendLatestImage();
42
Brian Silverman967e5df2020-02-09 16:43:34 -080043 const CameraImage &LatestImage() {
44 Buffer *const buffer = &buffers_[saved_buffer_.index];
45 return *flatbuffers::GetTemporaryPointer(*buffer->builder.fbb(),
46 buffer->message_offset);
47 }
48
milind-udaebe9b2022-01-09 18:25:24 -080049 // Sets the exposure duration of the camera. duration is the number of 100
50 // microsecond units.
Ravago Jones65469be2023-01-13 21:28:23 -080051 virtual void SetExposure(size_t duration);
milind-udaebe9b2022-01-09 18:25:24 -080052
53 // Switches from manual to auto exposure.
54 void UseAutoExposure();
55
Austin Schuh77d0bbd2022-12-26 14:00:51 -080056 protected:
57 void StreamOff();
58 void StreamOn();
59
60 int Ioctl(unsigned long number, void *arg);
61
62 bool multiplanar() const { return multiplanar_; }
63
64 // TODO(Brian): This concept won't exist once we start using variable-size
65 // H.264 frames.
milind-u6b094092023-01-09 19:26:12 -080066 size_t ImageSize() const { return ImageSize(rows_, cols_); }
67 static size_t ImageSize(int rows, int cols) {
68 return rows * cols * 2 /* bytes per pixel */;
69 }
Austin Schuh77d0bbd2022-12-26 14:00:51 -080070
Ravago Jonesdc524752022-12-27 01:15:13 -080071 const aos::ScopedFD &fd() { return fd_; };
72
Brian Silverman9dd793b2020-01-31 23:52:21 -080073 private:
Austin Schuh77d0bbd2022-12-26 14:00:51 -080074 static constexpr int kNumberBuffers = 4;
Brian Silverman9dd793b2020-01-31 23:52:21 -080075
76 struct Buffer {
Brian Silverman967e5df2020-02-09 16:43:34 -080077 void InitializeMessage(size_t max_image_size);
Brian Silverman9dd793b2020-01-31 23:52:21 -080078
Brian Silverman967e5df2020-02-09 16:43:34 -080079 void PrepareMessage(int rows, int cols, size_t image_size,
80 aos::monotonic_clock::time_point monotonic_eof);
81
82 void Send() {
Ravago Jonesda1b0082023-01-21 15:33:19 -080083 builder.CheckOk(builder.Send(message_offset));
Brian Silverman967e5df2020-02-09 16:43:34 -080084 message_offset = flatbuffers::Offset<CameraImage>();
Brian Silverman9dd793b2020-01-31 23:52:21 -080085 }
86
87 absl::Span<const char> DataSpan(size_t image_size) {
Brian Silverman967e5df2020-02-09 16:43:34 -080088 return absl::Span<const char>(
89 reinterpret_cast<char *>(CHECK_NOTNULL(data_pointer)), image_size);
Brian Silverman9dd793b2020-01-31 23:52:21 -080090 }
91
92 aos::Sender<CameraImage> sender;
93 aos::Sender<CameraImage>::Builder builder;
Brian Silverman967e5df2020-02-09 16:43:34 -080094 flatbuffers::Offset<CameraImage> message_offset;
Brian Silverman9dd793b2020-01-31 23:52:21 -080095
96 uint8_t *data_pointer = nullptr;
97 };
98
Brian Silverman967e5df2020-02-09 16:43:34 -080099 struct BufferInfo {
100 int index = -1;
101 aos::monotonic_clock::time_point monotonic_eof =
102 aos::monotonic_clock::min_time;
103
104 explicit operator bool() const { return index != -1; }
105
106 void Clear() {
107 index = -1;
108 monotonic_eof = aos::monotonic_clock::min_time;
109 }
110 };
111
Brian Silverman9dd793b2020-01-31 23:52:21 -0800112 // Attempts to dequeue a buffer (nonblocking). Returns the index of the new
Brian Silverman967e5df2020-02-09 16:43:34 -0800113 // buffer, or BufferInfo() if there wasn't a frame to dequeue.
114 BufferInfo DequeueBuffer();
Brian Silverman9dd793b2020-01-31 23:52:21 -0800115
116 void EnqueueBuffer(int buffer);
117
Brian Silverman9dd793b2020-01-31 23:52:21 -0800118 // The mmaped V4L2 buffers.
119 std::array<Buffer, kNumberBuffers> buffers_;
120
121 // If this is non-negative, it's the buffer number we're currently holding
122 // onto.
Brian Silverman967e5df2020-02-09 16:43:34 -0800123 BufferInfo saved_buffer_;
Brian Silverman9dd793b2020-01-31 23:52:21 -0800124
Austin Schuh77d0bbd2022-12-26 14:00:51 -0800125 bool multiplanar_ = false;
126
127 int rows_ = 0;
128 int cols_ = 0;
Brian Silverman9dd793b2020-01-31 23:52:21 -0800129
130 aos::ScopedFD fd_;
Austin Schuh77d0bbd2022-12-26 14:00:51 -0800131
132 aos::EventLoop *event_loop_;
133 aos::Ftrace ftrace_;
134};
135
136// Generic V4L2 reader for pi's and older.
137class V4L2Reader : public V4L2ReaderBase {
138 public:
139 V4L2Reader(aos::EventLoop *event_loop, const std::string &device_name);
Austin Schuh77d0bbd2022-12-26 14:00:51 -0800140};
141
142// Rockpi specific v4l2 reader. This assumes that the media device has been
143// properly configured before this class is constructed.
144class RockchipV4L2Reader : public V4L2ReaderBase {
145 public:
Ravago Jonesdc524752022-12-27 01:15:13 -0800146 RockchipV4L2Reader(aos::EventLoop *event_loop, aos::internal::EPoll *epoll,
Ravago Jones65469be2023-01-13 21:28:23 -0800147 const std::string &device_name,
148 const std::string &image_sensor_subdev);
149
Ravago Jonesfd8aa202023-01-16 14:21:45 -0800150 ~RockchipV4L2Reader();
151
Ravago Jones65469be2023-01-13 21:28:23 -0800152 void SetExposure(size_t duration) override;
153
154 void SetGain(size_t gain);
Ravago Jonesa0a2e062023-01-03 21:45:18 -0800155 void SetGainExt(size_t gain);
156
Ravago Jonesda1b0082023-01-21 15:33:19 -0800157 void SetVerticalBlanking(size_t vblank);
Ravago Jonesdc524752022-12-27 01:15:13 -0800158
159 private:
160 void OnImageReady();
161
Ravago Jones65469be2023-01-13 21:28:23 -0800162 int ImageSensorIoctl(unsigned long number, void *arg);
163
Ravago Jonesdc524752022-12-27 01:15:13 -0800164 aos::internal::EPoll *epoll_;
Ravago Jones65469be2023-01-13 21:28:23 -0800165
166 aos::ScopedFD image_sensor_fd_;
Brian Silverman9dd793b2020-01-31 23:52:21 -0800167};
168
169} // namespace vision
170} // namespace frc971
171
Jim Ostrowski977850f2022-01-22 21:04:22 -0800172#endif // FRC971_VISION_V4L2_READER_H_