1 /*
2 * Copyright (C) 2013 Texas Instruments
3 * Author: Nikhil Devshatwar <nikhil.nd@ti.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program. If not, see <http://www.gnu.org/licenses/>.
16 */
19 /*
20 * This is a drm test app to capture and display frames from a v4l2 device
21 * It uses standard single planar V4L2 API to capture progressive frames
22 * Displays the buffers via drm in fullscreen
23 * Currently only YUYV format is allowed
24 * This can be used to test VIP (Video Input Port) on DRA7xx SoC
25 * For this, vpdma firmware should be copied in /lib/firmware on target
26 */
28 #include "util.h"
30 #include <linux/videodev2.h>
31 #include <sys/ioctl.h>
32 #include <sys/mman.h>
33 #include <unistd.h>
34 #include <stdio.h>
35 #include <stdint.h>
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <stdlib.h>
40 #define NBUF 6
42 int width = 640, height = 480;
44 void *buffer_addr[NBUF];
45 int size[NBUF];
47 static int xioctl(int fd, int request, void *arg)
48 {
49 int r;
51 do r = ioctl (fd, request, arg);
52 while (-1 == r && EINTR == errno);
54 return r;
55 }
57 int init_device(int fd)
58 {
59 char fourcc[5];
60 unsigned int i;
61 struct v4l2_format fmt;
62 struct v4l2_requestbuffers req;
63 struct v4l2_buffer buf;
64 struct v4l2_capability caps;
66 /* Check for capture device */
67 memset(&caps, 0, sizeof(caps));
69 if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &caps)) {
70 perror("Setting Pixel Format");
71 return 1;
72 }
73 MSG("Driver: %s\ncaps: %8x", caps.driver, caps.capabilities);
74 if(~caps.capabilities & V4L2_CAP_VIDEO_CAPTURE) {
75 MSG("Not a capture device");
76 return 1;
77 }
79 /* Set capture format to YUYV */
80 memset(&fmt, 0, sizeof(fmt));
81 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
82 fmt.fmt.pix.width = width;
83 fmt.fmt.pix.height = height;
84 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
85 fmt.fmt.pix.field = V4L2_FIELD_NONE;
87 if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt)) {
88 perror("Setting Pixel Format");
89 return 1;
90 }
92 strncpy(fourcc, (char *)&fmt.fmt.pix.pixelformat, 4);
93 MSG( "Selected Camera Mode:\n"
94 " Width: %d\n"
95 " Height: %d\n"
96 " PixFmt: %s\n"
97 " Field: %d",
98 fmt.fmt.pix.width,
99 fmt.fmt.pix.height,
100 fourcc,
101 fmt.fmt.pix.field);
103 /* Currently driver supports only mmap buffers
104 * Request memory mapped buffers */
105 memset(&req, 0, sizeof(req));
106 req.count = 6;
107 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
108 req.memory = V4L2_MEMORY_MMAP;
110 if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {
111 perror("Requesting Buffer");
112 return 1;
113 }
115 for (i = 0; i < req.count; i++) {
116 memset(&buf, 0, sizeof(buf));
117 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
118 buf.memory = V4L2_MEMORY_MMAP;
119 buf.index = i;
120 if(-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf)) {
121 perror("Querying Buffer");
122 return 1;
123 }
125 /* Memory map all the buffers and save the addresses */
126 buffer_addr[i] = mmap (NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
127 size[i] = buf.length;
128 MSG("Length: %d\nAddress: %p", buf.length, buffer_addr[i]);
129 MSG("Image Length: %d", buf.bytesused);
131 /* Queue the buffer for capture */
132 memset(&buf, 0, sizeof(buf));
133 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
134 buf.memory = V4L2_MEMORY_MMAP;
135 buf.index = i;
136 if(-1 == xioctl(fd, VIDIOC_QBUF, &buf)) {
137 perror("Queue Buffer");
138 return 1;
139 }
141 }
142 if(-1 == xioctl(fd, VIDIOC_STREAMON, &buf.type)) {
143 perror("Start Capture");
144 return 1;
145 }
146 return 0;
147 }
149 void release_device(int fd)
150 {
151 int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
152 xioctl(fd, VIDIOC_STREAMOFF, &type);
153 close(fd);
154 }
156 static void usage(char *name) {
157 MSG("Usage: %s [OPTION]...", name);
158 MSG("V4L2 capture display test");
159 MSG("");
160 MSG("v4l2capturedisplay options:");
161 MSG("\t-h, --help: Print this help and exit.");
162 MSG("\t-n:\t Number of frames to capture (0 for infinite)");
163 MSG("\t-d:\t Device node to be used as capture device");
164 MSG("");
165 disp_usage();
166 }
168 void copy_buf(struct buffer *buf, void *deqbuf)
169 {
170 int i, height = buf->height, stride = buf->pitches[0];
171 int capStride = 2 * width;
172 uint8_t *dst, *src;
174 dst = omap_bo_map(buf->bo[0]);
175 src = deqbuf;
177 /* Call this before you start accessing display buffers */
178 for (i = 0; i < buf->nbo; i++)
179 omap_bo_cpu_prep(buf->bo[i], OMAP_GEM_WRITE);
181 /* YUYV format - Only one bo expected
182 * TODO: Change this for all formats */
183 for(i=0; i<height; i++) {
184 dst += stride;
185 src += capStride;
186 memcpy(dst, src, capStride);
187 }
189 /* Call this after you are done with accessing display buffers */
190 for (i = 0; i < buf->nbo; i++)
191 omap_bo_cpu_fini(buf->bo[i], OMAP_GEM_WRITE);
193 }
195 int main(int argc, char **argv)
196 {
197 struct display *disp;
198 struct buffer **buffers;
199 int ret, i, idx, fd, count = 0;
200 char devnode[100] = "/dev/video1";
202 /* Parse command line arguments */
203 for (i = 1; i < argc; i++) {
204 if (!strcmp(argv[i], "-h")) {
205 argv[i++] = NULL;
206 if(sscanf(argv[i], "%d", &height) != 1) {
207 ERROR("invalid height: %s", argv[i]);
208 return 1;
209 }
210 argv[i] = NULL;
211 } else if (!strcmp(argv[i], "-w")) {
212 argv[i++] = NULL;
213 if(sscanf(argv[i], "%d", &width) != 1) {
214 ERROR("invalid width: %s", argv[i]);
215 return 1;
216 }
217 argv[i] = NULL;
218 } else if (!strcmp(argv[i], "-n")) {
219 argv[i++] = NULL;
220 if(sscanf(argv[i], "%d", &count) != 1) {
221 ERROR("invalid count: %s", argv[i]);
222 return 1;
223 }
224 argv[i] = NULL;
225 } else if (!strcmp(argv[i], "-d")) {
226 argv[i++] = NULL;
227 strncpy(devnode, argv[i],100);
228 argv[i] = NULL;
229 }
230 }
232 MSG("Opening Video device %s", devnode);
233 fd = open(devnode, O_RDWR);
234 if (fd == -1) {
235 perror("Opening video device");
236 return 1;
237 }
239 ret = init_device(fd);
240 if (0 != ret) {
241 MSG("Exiting");
242 return ret;
243 }
245 MSG("Opening Display..");
246 disp = disp_open(argc, argv);
247 if (NULL == disp) {
248 usage(argv[0]);
249 return 1;
250 }
252 if (check_args(argc, argv)) {
253 /* remaining args.. print usage msg */
254 usage(argv[0]);
255 return 1;
256 }
258 /* Request drm to allocate some buffers */
259 buffers = disp_get_vid_buffers(disp, NBUF, FOURCC_STR("YUYV"), width, height);
260 if (!buffers) {
261 return 1;
262 }
264 for (i = 1; i != count; i++) {
265 struct buffer *dispbuf = buffers[i % NBUF];
266 struct v4l2_buffer buf;
268 /* Dequeue one buffer */
269 memset(&buf, 0, sizeof(buf));
270 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
271 buf.memory = V4L2_MEMORY_MMAP;
272 if(-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {
273 perror("Queue Buffer");
274 return 1;
275 }
276 idx = buf.index;
278 /* Copy data from dequeued buffer into display buffer */
279 copy_buf(dispbuf, buffer_addr[idx]);
280 /* Give it to display */
281 ret = disp_post_vid_buffer(disp, dispbuf, 0, 0, width, height);
282 if (ret) {
283 return ret;
284 }
286 /* Queue it back for next capture */
287 memset(&buf, 0, sizeof(buf));
288 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
289 buf.memory = V4L2_MEMORY_MMAP;
290 buf.index = idx;
291 if(-1 == xioctl(fd, VIDIOC_QBUF, &buf)) {
292 perror("Queue Buffer");
293 return 1;
294 }
295 }
297 disp_free_buffers(disp, NBUF);
298 disp_close(disp);
299 release_device(fd);
301 return 0;
302 }