1 #include <stdlib.h>
2 #include <unistd.h>
3 #include <errno.h>
4 #include <string.h>
5 #include <fcntl.h>
6 #include <sys/mman.h>
7 #include <malloc.h>
8 #include <sys/stat.h>
9 #include <sys/ioctl.h>
10 #include <stdbool.h>
11 #include <linux/videodev2.h>
13 #define NBUF (3)
14 #define CAP_WIDTH 800
15 #define CAP_HEIGHT 600
19 /*
20 * V4L2 capture device structure declaration
21 */
22 class V4l2Obj {
23 public:
24 V4l2Obj();
25 V4l2Obj(const char * dev_name, int w, int h, int num_buf);
26 ~V4l2Obj();
27 int request_buf(int *fd);
28 int queue_buf(int fd);
29 int dequeue_buf();
30 private:
31 int m_fd;
32 enum v4l2_memory m_memory_mode;
33 unsigned int num_buffers;
34 int m_width;
35 int m_height;
36 char m_dev_name[256];
37 struct v4l2_buffer *m_v4l2buf;
38 struct v4l2_format m_fmt;
40 void default_parameters();
41 void device_init();
42 };
44 /*
45 * Initialize the app resources with default parameters
46 */
47 void V4l2Obj::default_parameters(void)
48 {
49 /* Main camera */
50 m_memory_mode = V4L2_MEMORY_DMABUF;
51 m_num_buffers = NBUF;
52 strcpy(m_dev_name,"/dev/video1");
53 m_buffers = NULL;
54 m_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
55 m_width = CAP_WIDTH;
56 m_height = CAP_HEIGHT;
58 return;
59 }
61 void V4l2Obj::device_init()
62 {
63 /* Open the capture device */
64 m_fd = open(m_dev_name, O_RDWR);
65 if (m_fd <= 0) {
66 printf("Cannot open %s device\n", m_dev_name);
67 return -1;
68 }
70 MSG("\n%s: Opened Channel\n", m_dev_name);
72 /* Check if the device is capable of streaming */
73 if (ioctl(m_fd, VIDIOC_QUERYCAP, &capability) < 0) {
74 perror("VIDIOC_QUERYCAP");
75 goto ERROR;
76 }
78 if (capability.capabilities & V4L2_CAP_STREAMING)
79 MSG("%s: Capable of streaming\n", m_dev_name);
80 else {
81 ERROR("%s: Not capable of streaming\n", m_dev_name);
82 goto ERROR;
83 }
85 streamparam.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
86 if (ioctl(m_fd, VIDIOC_G_PARM, &streamparam) < 0){
87 perror("VIDIOC_G_PARM");
88 goto ERROR;
89 }
91 m_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
92 ret = ioctl(m_fd, VIDIOC_G_FMT, &m_fmt);
93 if (ret < 0) {
94 ERROR("VIDIOC_G_FMT failed: %s (%d)", strerror(errno), ret);
95 goto ERROR;
96 }
98 m_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
99 m_fmt.fmt.pix.width = m_width;
100 m_fmt.fmt.pix.height = m_height;
102 ret = ioctl(m_fd, VIDIOC_S_FMT, &m_fmt);
103 if (ret < 0) {
104 perror("VIDIOC_S_FMT");
105 goto ERROR;
106 }
108 MSG("%s: Init done successfully\n", dev_name);
110 ERROR:
111 close(m_fd);
112 }
114 V4l2Obj::V4l2Obj()
115 {
116 int ret;
117 struct v4l2_capability capability;
118 struct v4l2_streamparm streamparam;
120 default_parameters();
121 v4l2_device_init();
122 }
124 V4l2Obj::V4l2Obj(const char * dev_name, int w, int h, int num_buf, int pix_fmt)
125 {
126 int ret;
127 struct v4l2_capability capability;
128 struct v4l2_streamparm streamparam;
130 default_parameters();
132 m_dev_name = dev_name;
133 m_width = w;
134 m_height = h;
135 m_num_buffers = num_buf;
136 m_fmt.fmt.pix.pixelformat = pix_fmt;
138 v4l2_device_init();
139 }
141 V4l2Obj::~V4l2Obj(struct v4l2_device_info *device)
142 {
144 free(m_v4l2buf);
145 close(m_fd);
147 return;
148 }
150 int V4l2Obj::request_buf(int *fd)
151 {
152 struct v4l2_requestbuffers reqbuf;
153 unsigned int i;
154 int ret;
156 if (m_v4l2buf) {
157 // maybe eventually need to support this?
158 ERROR("already reqbuf'd");
159 return -1;
160 }
162 reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
163 reqbuf.memory = m_memory_mode;
164 reqbuf.count = m_num_buffers;
166 ret = ioctl(m_fd, VIDIOC_REQBUFS, &reqbuf);
167 if (ret < 0) {
168 ERROR("VIDIOC_REQBUFS failed: %s (%d)", strerror(errno), ret);
169 return ret;
170 }
172 if ((reqbuf.count != device->num_buffers) ||
173 (reqbuf.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
174 (reqbuf.memory != V4L2_MEMORY_DMABUF)) {
175 ERROR("unsupported..");
176 return -1;
177 }
179 m_num_buffers = reqbuf.count;
180 m_v4l2buf = (struct v4l2_buffer *) calloc(m_num_buffers, \
181 sizeof(struct v4l2_buffer));
182 if (!m_v4l2buf) {
183 ERROR("allocation failed");
184 return -1;
185 }
187 for (i = 0; i < m_num_buffers; i++) {
188 m_v4l2buf[i].type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
189 m_v4l2buf[i].memory = V4L2_MEMORY_DMABUF;
190 m_v4l2buf[i].index = i;
192 ret = ioctl(m_fd, VIDIOC_QUERYBUF, &m_v4l2buf[i]);
193 m_v4l2buf[i].m.fd = fd[i];
195 if (ret) {
196 ERROR("VIDIOC_QUERYBUF failed: %s (%d)", strerror(errno), ret);
197 return ret;
198 }
199 }
201 return 0;
202 }
204 /*
205 * Queue V4L2 buffer
206 */
207 int V4l2Obj::queue_buf(int fd)
208 {
209 struct v4l2_buffer *v4l2buf = NULL;
210 int ret;
211 unsigned char i;
213 if(buf->nbo != 1){
214 ERROR("number of bufers not right\n");
215 return -1;
216 }
218 for (i = 0; i < device->num_buffers; i++) {
219 if (m_v4l2buf[i].m.fd == fd) {
220 v4l2buf = &m_v4l2buf[i];
221 }
222 }
224 if (!v4l2buf) {
225 ERROR("invalid buffer");
226 return -1;
227 }
228 ret = ioctl(m_fd, VIDIOC_QBUF, v4l2buf);
229 if (ret) {
230 ERROR("VIDIOC_QBUF failed: %s (%d)", strerror(errno), ret);
231 }
233 return ret;
234 }
236 /*
237 * DeQueue V4L2 buffer
238 */
239 int V4l2Obj::dequeue_buf()
240 {
241 struct dmabuf_buffer *buf;
242 struct v4l2_buffer v4l2buf;
243 int ret;
245 v4l2buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
246 v4l2buf.memory = V4L2_MEMORY_DMABUF;
247 ret = ioctl(m_fd, VIDIOC_DQBUF, &v4l2buf);
248 if (ret) {
249 ERROR("VIDIOC_DQBUF failed: %s (%d)\n", strerror(errno), ret);
250 return NULL;
251 }
253 m_v4l2buf[v4l2buf.index].timestamp = v4l2buf.timestamp;
255 return v4l2buf.index;
256 }
261 /*
262 * Enable streaming for V4L2 capture device
263 */
264 int V4l2Obj::stream_on()
265 {
266 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
267 int ret = 0;
269 ret = ioctl(m_fd, VIDIOC_STREAMON, &type);
271 if (ret) {
272 ERROR("VIDIOC_STREAMON failed: %s (%d)", strerror(errno), ret);
273 }
275 return ret;
276 }
278 /*
279 * Disable streaming for V4L2 capture device
280 */
281 int V4l2Obj::stream_off()
282 {
283 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
284 int ret = -1;
286 if (m_fd <= 0) {
287 return ret;
288 }
290 ret = ioctl(m_fd, VIDIOC_STREAMOFF, &type);
292 if (ret) {
293 ERROR("VIDIOC_STREAMOFF failed: %s (%d)", strerror(errno), ret);
294 }
296 return ret;
297 }