blob: 6f90cecc0105db5becc5a6646370d6c92c405336 [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"
8#include "glog/logging.h"
9
10#include "aos/events/event_loop.h"
11#include "aos/scoped/scoped_fd.h"
Jim Ostrowski977850f2022-01-22 21:04:22 -080012#include "frc971/vision/vision_generated.h"
Brian Silverman9dd793b2020-01-31 23:52:21 -080013
14namespace frc971 {
15namespace vision {
16
17// Reads images from a V4L2 capture device (aka camera).
18class V4L2Reader {
19 public:
20 // device_name is the name of the device file (like "/dev/video0").
21 V4L2Reader(aos::EventLoop *event_loop, const std::string &device_name);
22
23 V4L2Reader(const V4L2Reader &) = delete;
24 V4L2Reader &operator=(const V4L2Reader &) = delete;
25
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
Brian Silverman9dd793b2020-01-31 23:52:21 -080053 private:
54 static constexpr int kNumberBuffers = 16;
55
56 struct Buffer {
Brian Silverman967e5df2020-02-09 16:43:34 -080057 void InitializeMessage(size_t max_image_size);
Brian Silverman9dd793b2020-01-31 23:52:21 -080058
Brian Silverman967e5df2020-02-09 16:43:34 -080059 void PrepareMessage(int rows, int cols, size_t image_size,
60 aos::monotonic_clock::time_point monotonic_eof);
61
62 void Send() {
milind1f1dca32021-07-03 13:50:07 -070063 (void)builder.Send(message_offset);
Brian Silverman967e5df2020-02-09 16:43:34 -080064 message_offset = flatbuffers::Offset<CameraImage>();
Brian Silverman9dd793b2020-01-31 23:52:21 -080065 }
66
67 absl::Span<const char> DataSpan(size_t image_size) {
Brian Silverman967e5df2020-02-09 16:43:34 -080068 return absl::Span<const char>(
69 reinterpret_cast<char *>(CHECK_NOTNULL(data_pointer)), image_size);
Brian Silverman9dd793b2020-01-31 23:52:21 -080070 }
71
72 aos::Sender<CameraImage> sender;
73 aos::Sender<CameraImage>::Builder builder;
Brian Silverman967e5df2020-02-09 16:43:34 -080074 flatbuffers::Offset<CameraImage> message_offset;
Brian Silverman9dd793b2020-01-31 23:52:21 -080075
76 uint8_t *data_pointer = nullptr;
77 };
78
Brian Silverman967e5df2020-02-09 16:43:34 -080079 struct BufferInfo {
80 int index = -1;
81 aos::monotonic_clock::time_point monotonic_eof =
82 aos::monotonic_clock::min_time;
83
84 explicit operator bool() const { return index != -1; }
85
86 void Clear() {
87 index = -1;
88 monotonic_eof = aos::monotonic_clock::min_time;
89 }
90 };
91
Brian Silverman9dd793b2020-01-31 23:52:21 -080092 // TODO(Brian): This concept won't exist once we start using variable-size
93 // H.264 frames.
94 size_t ImageSize() const { return rows_ * cols_ * 2 /* bytes per pixel */; }
95
96 // Attempts to dequeue a buffer (nonblocking). Returns the index of the new
Brian Silverman967e5df2020-02-09 16:43:34 -080097 // buffer, or BufferInfo() if there wasn't a frame to dequeue.
98 BufferInfo DequeueBuffer();
Brian Silverman9dd793b2020-01-31 23:52:21 -080099
100 void EnqueueBuffer(int buffer);
101
102 int Ioctl(unsigned long number, void *arg);
103
Brian Silverman8f24adb2020-02-02 17:15:58 -0800104 void StreamOff();
105
Brian Silverman9dd793b2020-01-31 23:52:21 -0800106 // The mmaped V4L2 buffers.
107 std::array<Buffer, kNumberBuffers> buffers_;
108
109 // If this is non-negative, it's the buffer number we're currently holding
110 // onto.
Brian Silverman967e5df2020-02-09 16:43:34 -0800111 BufferInfo saved_buffer_;
Brian Silverman9dd793b2020-01-31 23:52:21 -0800112
113 const int rows_ = 480;
114 const int cols_ = 640;
115
116 aos::ScopedFD fd_;
117};
118
119} // namespace vision
120} // namespace frc971
121
Jim Ostrowski977850f2022-01-22 21:04:22 -0800122#endif // FRC971_VISION_V4L2_READER_H_