JeVois  1.6
JeVois Smart Embedded Machine Vision Toolkit
Share this page:
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 // ####################################################################################################
30 jevois::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  buf.type = type;
46  buf.memory = V4L2_MEMORY_MMAP;
47  buf.index = i;
48  try { XIOCTL(fd, VIDIOC_QUERYBUF, &buf); } catch (...) { FDLFATAL("Failed to request buffers"); }
49 
50  itsBuffers.push_back(std::make_shared<jevois::VideoBuf>(fd, buf.length, buf.m.offset));
51  FDLDEBUG("Added mmap'd buffer " << i << " of size " << buf.length);
52  }
53 }
54 
55 // ####################################################################################################
57 {
58  if (itsNqueued) FDLDEBUG(itsNqueued << " buffers are still queued...");
59 
60  // Free and unmap all our buffers:
61  for (auto & b : itsBuffers)
62  {
63  if (b.use_count() > 1) FDLDEBUG("Ref count non zero when attempting to free VideoBuf");
64 
65  b.reset(); // VideoBuf destructor will do the memory unmapping
66  }
67 
68  itsBuffers.clear();
69 
70  // Then free all buffers at the device level:
71  struct v4l2_requestbuffers req = { };
72  req.count = 0; // request 0 buffers to free all the previously requested ones
73  req.type = itsType;
74  req.memory = V4L2_MEMORY_MMAP;
75  try { XIOCTL_QUIET(itsFd, VIDIOC_REQBUFS, &req); }
76  catch (...) { FDLDEBUG("Error trying to free V4L2 buffers -- IGNORED"); }
77 }
78 
79 // ####################################################################################################
81 {
82  return itsBuffers.size();
83 }
84 
85 // ####################################################################################################
87 {
88  return itsNqueued;
89 }
90 
91 // ####################################################################################################
92 std::shared_ptr<jevois::VideoBuf> jevois::VideoBuffers::get(size_t const index) const
93 {
94  if (index >= itsBuffers.size()) FDLFATAL("Index " << index << " out of range [0.." << itsBuffers.size() << ']');
95 
96  return itsBuffers[index];
97 }
98 
99 // ####################################################################################################
100 void jevois::VideoBuffers::qbuf(size_t const index)
101 {
102  if (itsType == V4L2_BUF_TYPE_VIDEO_OUTPUT) FDLFATAL("Cannot enqueue output buffers by index");
103  if (itsNqueued == itsBuffers.size()) FDLFATAL("All buffers have already been queued");
104 
105  struct v4l2_buffer buf = { };
106 
107  buf.type = itsType;
108  buf.memory = V4L2_MEMORY_MMAP;
109  buf.index = index;
110 
111  XIOCTL(itsFd, VIDIOC_QBUF, &buf);
112 
113  ++itsNqueued;
114 }
115 
116 // ####################################################################################################
117 void jevois::VideoBuffers::qbuf(struct v4l2_buffer & buf)
118 {
119  if (itsNqueued == itsBuffers.size()) FDLFATAL("All buffers have already been queued");
120 
121  XIOCTL(itsFd, VIDIOC_QBUF, &buf);
122 
123  ++itsNqueued;
124 }
125 
126 // ####################################################################################################
128 {
129  for (unsigned int i = 0; i < itsBuffers.size(); ++i) qbuf(i);
130 }
131 
132 // ####################################################################################################
133 void jevois::VideoBuffers::dqbuf(struct v4l2_buffer & buf)
134 {
135  if (itsNqueued == 0) FDLFATAL("No buffer is currently queued");
136 
137  memset(&buf, 0, sizeof(struct v4l2_buffer));
138  buf.type = itsType;
139  buf.memory = V4L2_MEMORY_MMAP;
140 
141  XIOCTL(itsFd, VIDIOC_DQBUF, &buf);
142 
143  --itsNqueued;
144 }
145 
146 // ####################################################################################################
148 {
149  struct v4l2_buffer buf;
150  int retry = 100;
151 
152  // Loop until all are dequeued; we may need to sleep a bit if some buffers are still in use by the hardware:
153  while (itsNqueued && retry-- >= 0)
154  {
155  try { dqbuf(buf); } catch (...) { std::this_thread::sleep_for(std::chrono::milliseconds(5)); }
156  }
157 }
#define FDLDEBUG(msg)
Definition: VideoBuffers.C:24
void dqbuf(struct v4l2_buffer &buf)
Dequeue the next captured/displayed buffer, blocks until one is available.
Definition: VideoBuffers.C:133
#define XIOCTL_QUIET(dev, req, mem)
Helper macro to execute an ioctl, ignore interruptions, and, if error throw quietly.
VideoBuffers(char const *name, int const fd, v4l2_buf_type type, size_t const num=4)
Construct and allocate MMAP&#39;d video buffers.
Definition: VideoBuffers.C:30
void dqbufall()
Dequeue all buffers, typically used when stopping a stream, not that this may take some time...
Definition: VideoBuffers.C:147
size_t size() const
Get the number of buffers allocated.
Definition: VideoBuffers.C:80
#define FDLFATAL(msg)
Definition: VideoBuffers.C:27
#define XIOCTL(dev, req, mem)
Helper macro to execute an ioctl, ignore interruptions, and, if error, issue a fatal message and thro...
size_t nqueued() const
Get the number of buffers queued, this is always in [0 .. size()[.
Definition: VideoBuffers.C:86
std::shared_ptr< VideoBuf > get(size_t const index) const
Get one buffer, by index [0 .. size()[.
Definition: VideoBuffers.C:92
void qbuf(size_t const index)
Queue one buffer to V4L2, by index [0 .. size()[.
Definition: VideoBuffers.C:100
~VideoBuffers()
Free the MMAP&#39;d memory area.
Definition: VideoBuffers.C:56
void qbufall()
Queue all buffers, typically used when starting streaming on capture devices.
Definition: VideoBuffers.C:127