blob: 3c9d7958902852bb2d988840f0ea4386d49e82cd [file] [log] [blame]
Brian Silverman9dd793b2020-01-31 23:52:21 -08001#ifndef Y2020_VISION_V4L2_READER_H_
2#define Y2020_VISION_V4L2_READER_H_
3
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"
12#include "y2020/vision/vision_generated.h"
13
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
Brian Silverman9dd793b2020-01-31 23:52:21 -080046 private:
47 static constexpr int kNumberBuffers = 16;
48
49 struct Buffer {
Brian Silverman967e5df2020-02-09 16:43:34 -080050 void InitializeMessage(size_t max_image_size);
Brian Silverman9dd793b2020-01-31 23:52:21 -080051
Brian Silverman967e5df2020-02-09 16:43:34 -080052 void PrepareMessage(int rows, int cols, size_t image_size,
53 aos::monotonic_clock::time_point monotonic_eof);
54
55 void Send() {
56 builder.Send(message_offset);
57 message_offset = flatbuffers::Offset<CameraImage>();
Brian Silverman9dd793b2020-01-31 23:52:21 -080058 }
59
60 absl::Span<const char> DataSpan(size_t image_size) {
Brian Silverman967e5df2020-02-09 16:43:34 -080061 return absl::Span<const char>(
62 reinterpret_cast<char *>(CHECK_NOTNULL(data_pointer)), image_size);
Brian Silverman9dd793b2020-01-31 23:52:21 -080063 }
64
65 aos::Sender<CameraImage> sender;
66 aos::Sender<CameraImage>::Builder builder;
Brian Silverman967e5df2020-02-09 16:43:34 -080067 flatbuffers::Offset<CameraImage> message_offset;
Brian Silverman9dd793b2020-01-31 23:52:21 -080068
69 uint8_t *data_pointer = nullptr;
70 };
71
Brian Silverman967e5df2020-02-09 16:43:34 -080072 struct BufferInfo {
73 int index = -1;
74 aos::monotonic_clock::time_point monotonic_eof =
75 aos::monotonic_clock::min_time;
76
77 explicit operator bool() const { return index != -1; }
78
79 void Clear() {
80 index = -1;
81 monotonic_eof = aos::monotonic_clock::min_time;
82 }
83 };
84
Brian Silverman9dd793b2020-01-31 23:52:21 -080085 // TODO(Brian): This concept won't exist once we start using variable-size
86 // H.264 frames.
87 size_t ImageSize() const { return rows_ * cols_ * 2 /* bytes per pixel */; }
88
89 // Attempts to dequeue a buffer (nonblocking). Returns the index of the new
Brian Silverman967e5df2020-02-09 16:43:34 -080090 // buffer, or BufferInfo() if there wasn't a frame to dequeue.
91 BufferInfo DequeueBuffer();
Brian Silverman9dd793b2020-01-31 23:52:21 -080092
93 void EnqueueBuffer(int buffer);
94
95 int Ioctl(unsigned long number, void *arg);
96
Brian Silverman8f24adb2020-02-02 17:15:58 -080097 void StreamOff();
98
Brian Silverman9dd793b2020-01-31 23:52:21 -080099 // The mmaped V4L2 buffers.
100 std::array<Buffer, kNumberBuffers> buffers_;
101
102 // If this is non-negative, it's the buffer number we're currently holding
103 // onto.
Brian Silverman967e5df2020-02-09 16:43:34 -0800104 BufferInfo saved_buffer_;
Brian Silverman9dd793b2020-01-31 23:52:21 -0800105
106 const int rows_ = 480;
107 const int cols_ = 640;
108
109 aos::ScopedFD fd_;
110};
111
112} // namespace vision
113} // namespace frc971
114
115#endif // Y2020_VISION_V4L2_READER_H_