JeVois  1.21
JeVois Smart Embedded Machine Vision Toolkit
Share this page:
Loading...
Searching...
No Matches
VideoBuffers.C
Go to the documentation of this file.
1// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2//
3// JeVois Smart Embedded Machine Vision Toolkit - Copyright (C) 2016 by Laurent Itti, the University of Southern
4// California (USC), and iLab at USC. See http://iLab.usc.edu and http://jevois.org for information about this project.
5//
6// This file is part of the JeVois Smart Embedded Machine Vision Toolkit. This program is free software; you can
7// redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software
8// Foundation, version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
10// License for more details. You should have received a copy of the GNU General Public License along with this program;
11// if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
12//
13// Contact information: Laurent Itti - 3641 Watt Way, HNB-07A - Los Angeles, CA 90089-2520 - USA.
14// Tel: +1 213 740 3527 - itti@pollux.usc.edu - http://iLab.usc.edu - http://jevois.org
15// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
16/*! \file */
17
19#include <jevois/Util/Utils.H>
20#include <jevois/Debug/Log.H>
21#include <sys/ioctl.h>
22#include <thread>
23
24#define FDLDEBUG(msg) LDEBUG('[' << itsFd << ':' << itsName << "] " << msg)
25#define FDLINFO(msg) LINFO('[' << itsFd << ':' << itsName << "] " << msg)
26#define FDLERROR(msg) LERROR('[' << itsFd << ':' << itsName << "] " << msg)
27#define FDLFATAL(msg) LFATAL('[' << itsFd << ':' << itsName << "] " << msg)
28
29// ####################################################################################################
30jevois::VideoBuffers::VideoBuffers(char const * name, int const fd, v4l2_buf_type const type, size_t const num) :
31 itsFd(fd), itsName(name), itsType(type), itsNqueued(0)
32{
33 // First, request the buffers:
34 struct v4l2_requestbuffers req = { };
35 req.count = num;
36 req.type = type;
37 req.memory = V4L2_MEMORY_MMAP;
38 XIOCTL(fd, VIDIOC_REQBUFS, &req);
39 FDLDEBUG("Reqbufs for " << num << " buffers returned " << req.count << " buffers");
40
41 // Allocate VideoBuf and MMAP the buffers:
42 for (unsigned int i = 0; i < req.count; ++i)
43 {
44 struct v4l2_buffer buf = { };
45 struct v4l2_plane plane = { };
46 buf.type = type;
47 buf.memory = V4L2_MEMORY_MMAP;
48 buf.index = i;
49 // Note: guvcview adds: buf.flags=V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC
50 if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
51 {
52 // In multi-plane mode, allocate a struct for the planes:
53 buf.length = 1; // FIXME only 1 plane supported
54 buf.m.planes = &plane;
55
56 try { XIOCTL(fd, VIDIOC_QUERYBUF, &buf); } catch (...) { FDLFATAL("Failed to request buffers"); }
57 if (buf.length != 1) LFATAL("Only one V4L2 plane is supported for now, i.e., only packed video formats.");
58 }
59 else
60 {
61 // Standard single-plane mode:
62 try { XIOCTL(fd, VIDIOC_QUERYBUF, &buf); } catch (...) { FDLFATAL("Failed to request buffers"); }
63 }
64
65 int dmafd = -1;
66
67#ifdef JEVOIS_PRO
68 // Try to get a dma_buf fd, if kernel driver supports it:
69 struct v4l2_exportbuffer ex_buf = { };
70 ex_buf.type = type;
71 ex_buf.index = i;
72 ex_buf.plane = 0; // FIXME only 1 plane supported
73 ex_buf.flags = 0;
74 ex_buf.fd = -1;
75
76 try { XIOCTL(fd, VIDIOC_EXPBUF, &ex_buf); } catch (...) { FDLDEBUG("Could not get dma_buf fd for buffer " << i); }
77 dmafd = ex_buf.fd;
78#endif
79
80 if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
81 itsBuffers.push_back(std::make_shared<jevois::VideoBuf>(fd, buf.m.planes[0].length,
82 buf.m.planes[0].m.mem_offset, dmafd));
83 else
84 itsBuffers.push_back(std::make_shared<jevois::VideoBuf>(fd, buf.length, buf.m.offset, dmafd));
85
86 FDLDEBUG("Added mmap'd buffer " << i << " of size " << buf.length);
87 }
88}
89
90// ####################################################################################################
92{
93 if (itsNqueued) FDLDEBUG(itsNqueued << " buffers are still queued...");
94
95 // Free and unmap all our buffers:
96 for (auto & b : itsBuffers)
97 {
98 if (b.use_count() > 1) FDLDEBUG("Ref count non zero when attempting to free VideoBuf");
99
100 b.reset(); // VideoBuf destructor will do the memory unmapping
101 }
102
103 itsBuffers.clear();
104
105 // Then free all buffers at the device level:
106 struct v4l2_requestbuffers req = { };
107 req.count = 0; // request 0 buffers to free all the previously requested ones
108 req.type = itsType;
109 req.memory = V4L2_MEMORY_MMAP;
110 try { XIOCTL_QUIET(itsFd, VIDIOC_REQBUFS, &req); }
111 catch (...) { FDLDEBUG("Error trying to free V4L2 buffers -- IGNORED"); }
112}
113
114// ####################################################################################################
116{
117 return itsBuffers.size();
118}
119
120// ####################################################################################################
122{
123 return itsNqueued;
124}
125
126// ####################################################################################################
127std::shared_ptr<jevois::VideoBuf> jevois::VideoBuffers::get(size_t const index) const
128{
129 if (index >= itsBuffers.size()) FDLFATAL("Index " << index << " out of range [0.." << itsBuffers.size() << ']');
130
131 return itsBuffers[index];
132}
133
134// ####################################################################################################
135void jevois::VideoBuffers::qbuf(size_t const index)
136{
137 if (itsType == V4L2_BUF_TYPE_VIDEO_OUTPUT) FDLFATAL("Cannot enqueue output buffers by index");
138 if (itsNqueued == itsBuffers.size())
139 throw std::runtime_error('[' + std::to_string(itsFd) + ':' + itsName + "] All buffers have already been queued");
140
141 struct v4l2_buffer buf = { };
142 buf.type = itsType;
143 buf.memory = V4L2_MEMORY_MMAP;
144 buf.index = index;
145
146 if (itsType == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
147 {
148 struct v4l2_plane plane = { };
149 buf.length = 1; // FIXME only one plane supported.
150 buf.m.planes = &plane;
151 }
152
153 XIOCTL_QUIET(itsFd, VIDIOC_QBUF, &buf);
154
155 ++itsNqueued;
156}
157
158// ####################################################################################################
159void jevois::VideoBuffers::qbuf(struct v4l2_buffer & buf)
160{
161 if (itsNqueued == itsBuffers.size())
162 throw std::runtime_error('[' + std::to_string(itsFd) + ':' + itsName + "] All buffers have already been queued");
163
164 XIOCTL_QUIET(itsFd, VIDIOC_QBUF, &buf);
165
166 ++itsNqueued;
167}
168
169// ####################################################################################################
171{
172 for (unsigned int i = 0; i < itsBuffers.size(); ++i) qbuf(i);
173}
174
175// ####################################################################################################
177{
178 for (unsigned int i = 0; i < itsBuffers.size(); ++i)
179 if (i != index) try { qbuf(i); } catch (...) { }
180}
181
182// ####################################################################################################
183void jevois::VideoBuffers::dqbuf(struct v4l2_buffer & buf)
184{
185 if (itsNqueued == 0) FDLFATAL("No buffer is currently queued");
186
187 memset(&buf, 0, sizeof(struct v4l2_buffer));
188 buf.type = itsType;
189 buf.memory = V4L2_MEMORY_MMAP;
190
191 if (itsType == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
192 {
193 struct v4l2_plane plane = { };
194 buf.length = 1; // FIXME only one plane supported.
195 buf.m.planes = &plane;
196
197 XIOCTL_QUIET_ONCE(itsFd, VIDIOC_DQBUF, &buf);
198 }
199 else
200 {
201 XIOCTL_QUIET_ONCE(itsFd, VIDIOC_DQBUF, &buf);
202 }
203
204 --itsNqueued;
205}
206
207// ####################################################################################################
209{
210 struct v4l2_buffer buf;
211 int retry = 100;
212
213 // Loop until all are dequeued; we may need to sleep a bit if some buffers are still in use by the hardware:
214 while (itsNqueued && retry-- >= 0)
215 {
216 try { dqbuf(buf); } catch (...) { std::this_thread::sleep_for(std::chrono::milliseconds(5)); }
217 }
218}
#define FDLFATAL(msg)
#define FDLDEBUG(msg)
std::shared_ptr< VideoBuf > get(size_t const index) const
Get one buffer, by index [0 .. size()[.
void dqbufall()
Dequeue all buffers, typically used when stopping a stream, not that this may take some time.
void qbufall()
Queue all buffers, typically used when starting streaming on capture devices.
size_t nqueued() const
Get the number of buffers queued, this is always in [0 .. size()[.
size_t size() const
Get the number of buffers allocated.
void qbufallbutone(size_t const index)
Queue all buffers that are not already queued except one specified.
void qbuf(size_t const index)
Queue one buffer to V4L2, by index [0 .. size()[.
~VideoBuffers()
Free the MMAP'd memory area.
VideoBuffers(char const *name, int const fd, v4l2_buf_type type, size_t const num=4)
Construct and allocate MMAP'd video buffers.
void dqbuf(struct v4l2_buffer &buf)
Dequeue the next captured/displayed buffer, blocks until one is available.
#define LFATAL(msg)
Convenience macro for users to print out console or syslog messages, FATAL level.
Definition Log.H:230
#define XIOCTL_QUIET_ONCE(dev, req, mem)
Helper macro to execute an ioctl, ignore interruptions, and, if error throw quietly.
Definition Utils.H:228
#define XIOCTL_QUIET(dev, req, mem)
Helper macro to execute an ioctl, ignore interruptions, and, if error throw quietly.
Definition Utils.H:216
#define XIOCTL(dev, req, mem)
Helper macro to execute an ioctl, ignore interruptions, and, if error, issue a fatal message and thro...
Definition Utils.H:205