blob: a2b4c25f9ba2ad1a015aefb9f776df95af54ffde [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"
Brian Silverman9dd793b2020-01-31 23:52:21 -08008#include "aos/events/event_loop.h"
Austin Schuhe4acc1e2022-12-26 14:01:34 -08009#include "aos/ftrace.h"
Brian Silverman9dd793b2020-01-31 23:52:21 -080010#include "aos/scoped/scoped_fd.h"
Jim Ostrowski977850f2022-01-22 21:04:22 -080011#include "frc971/vision/vision_generated.h"
Austin Schuh77d0bbd2022-12-26 14:00:51 -080012#include "glog/logging.h"
Brian Silverman9dd793b2020-01-31 23:52:21 -080013
14namespace frc971 {
15namespace vision {
16
17// Reads images from a V4L2 capture device (aka camera).
Austin Schuh77d0bbd2022-12-26 14:00:51 -080018class V4L2ReaderBase {
Brian Silverman9dd793b2020-01-31 23:52:21 -080019 public:
20 // device_name is the name of the device file (like "/dev/video0").
Austin Schuh77d0bbd2022-12-26 14:00:51 -080021 V4L2ReaderBase(aos::EventLoop *event_loop, const std::string &device_name);
Brian Silverman9dd793b2020-01-31 23:52:21 -080022
Austin Schuh77d0bbd2022-12-26 14:00:51 -080023 V4L2ReaderBase(const V4L2ReaderBase &) = delete;
24 V4L2ReaderBase &operator=(const V4L2ReaderBase &) = delete;
Brian Silverman9dd793b2020-01-31 23:52:21 -080025
26 // Reads the latest image.
27 //
Brian Silverman967e5df2020-02-09 16:43:34 -080028 // Returns false if no image was available since the last image was read.
29 // Call LatestImage() to get a reference to the data, which will be valid
30 // until this method is called again.
31 bool ReadLatestImage();
Brian Silverman9dd793b2020-01-31 23:52:21 -080032
33 // Sends the latest image.
34 //
35 // ReadLatestImage() must have returned a non-empty span the last time it was
36 // called. After calling this, the data which was returned from
37 // ReadLatestImage() will no longer be valid.
38 void SendLatestImage();
39
Brian Silverman967e5df2020-02-09 16:43:34 -080040 const CameraImage &LatestImage() {
41 Buffer *const buffer = &buffers_[saved_buffer_.index];
42 return *flatbuffers::GetTemporaryPointer(*buffer->builder.fbb(),
43 buffer->message_offset);
44 }
45
milind-udaebe9b2022-01-09 18:25:24 -080046 // Sets the exposure duration of the camera. duration is the number of 100
47 // microsecond units.
48 void SetExposure(size_t duration);
49
50 // Switches from manual to auto exposure.
51 void UseAutoExposure();
52
Austin Schuh77d0bbd2022-12-26 14:00:51 -080053 protected:
54 void StreamOff();
55 void StreamOn();
56
57 int Ioctl(unsigned long number, void *arg);
58
59 bool multiplanar() const { return multiplanar_; }
60
61 // TODO(Brian): This concept won't exist once we start using variable-size
62 // H.264 frames.
63 size_t ImageSize() const { return rows_ * cols_ * 2 /* bytes per pixel */; }
64
Brian Silverman9dd793b2020-01-31 23:52:21 -080065 private:
Austin Schuh77d0bbd2022-12-26 14:00:51 -080066 static constexpr int kNumberBuffers = 4;
Brian Silverman9dd793b2020-01-31 23:52:21 -080067
68 struct Buffer {
Brian Silverman967e5df2020-02-09 16:43:34 -080069 void InitializeMessage(size_t max_image_size);
Brian Silverman9dd793b2020-01-31 23:52:21 -080070
Brian Silverman967e5df2020-02-09 16:43:34 -080071 void PrepareMessage(int rows, int cols, size_t image_size,
72 aos::monotonic_clock::time_point monotonic_eof);
73
74 void Send() {
milind1f1dca32021-07-03 13:50:07 -070075 (void)builder.Send(message_offset);
Brian Silverman967e5df2020-02-09 16:43:34 -080076 message_offset = flatbuffers::Offset<CameraImage>();
Brian Silverman9dd793b2020-01-31 23:52:21 -080077 }
78
79 absl::Span<const char> DataSpan(size_t image_size) {
Brian Silverman967e5df2020-02-09 16:43:34 -080080 return absl::Span<const char>(
81 reinterpret_cast<char *>(CHECK_NOTNULL(data_pointer)), image_size);
Brian Silverman9dd793b2020-01-31 23:52:21 -080082 }
83
84 aos::Sender<CameraImage> sender;
85 aos::Sender<CameraImage>::Builder builder;
Brian Silverman967e5df2020-02-09 16:43:34 -080086 flatbuffers::Offset<CameraImage> message_offset;
Brian Silverman9dd793b2020-01-31 23:52:21 -080087
88 uint8_t *data_pointer = nullptr;
89 };
90
Brian Silverman967e5df2020-02-09 16:43:34 -080091 struct BufferInfo {
92 int index = -1;
93 aos::monotonic_clock::time_point monotonic_eof =
94 aos::monotonic_clock::min_time;
95
96 explicit operator bool() const { return index != -1; }
97
98 void Clear() {
99 index = -1;
100 monotonic_eof = aos::monotonic_clock::min_time;
101 }
102 };
103
Brian Silverman9dd793b2020-01-31 23:52:21 -0800104 // Attempts to dequeue a buffer (nonblocking). Returns the index of the new
Brian Silverman967e5df2020-02-09 16:43:34 -0800105 // buffer, or BufferInfo() if there wasn't a frame to dequeue.
106 BufferInfo DequeueBuffer();
Brian Silverman9dd793b2020-01-31 23:52:21 -0800107
108 void EnqueueBuffer(int buffer);
109
Brian Silverman9dd793b2020-01-31 23:52:21 -0800110 // The mmaped V4L2 buffers.
111 std::array<Buffer, kNumberBuffers> buffers_;
112
113 // If this is non-negative, it's the buffer number we're currently holding
114 // onto.
Brian Silverman967e5df2020-02-09 16:43:34 -0800115 BufferInfo saved_buffer_;
Brian Silverman9dd793b2020-01-31 23:52:21 -0800116
Austin Schuh77d0bbd2022-12-26 14:00:51 -0800117 bool multiplanar_ = false;
118
119 int rows_ = 0;
120 int cols_ = 0;
Brian Silverman9dd793b2020-01-31 23:52:21 -0800121
122 aos::ScopedFD fd_;
Austin Schuh77d0bbd2022-12-26 14:00:51 -0800123
124 aos::EventLoop *event_loop_;
125 aos::Ftrace ftrace_;
126};
127
128// Generic V4L2 reader for pi's and older.
129class V4L2Reader : public V4L2ReaderBase {
130 public:
131 V4L2Reader(aos::EventLoop *event_loop, const std::string &device_name);
132
133 private:
134 const int rows_ = 480;
135 const int cols_ = 640;
136};
137
138// Rockpi specific v4l2 reader. This assumes that the media device has been
139// properly configured before this class is constructed.
140class RockchipV4L2Reader : public V4L2ReaderBase {
141 public:
142 RockchipV4L2Reader(aos::EventLoop *event_loop, const std::string &device_name);
Brian Silverman9dd793b2020-01-31 23:52:21 -0800143};
144
145} // namespace vision
146} // namespace frc971
147
Jim Ostrowski977850f2022-01-22 21:04:22 -0800148#endif // FRC971_VISION_V4L2_READER_H_