1 /******************************************************************************\
2 Copyright (c) 2005-2019, Intel Corporation
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6
7 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
8
9 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
10
11 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
12
13 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
15 This sample was distributed or derived from the Intel's Media Samples package.
16 The original version of this sample may be obtained from https://software.intel.com/en-us/intel-media-server-studio
17 or https://software.intel.com/en-us/media-client-solutions-support.
18 \**********************************************************************************/
19
20 #if defined (ENABLE_V4L2_SUPPORT)
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <assert.h>
25 #include <sys/ioctl.h>
26 #include <fcntl.h>
27 #include <pthread.h>
28 #include <poll.h>
29 #include <signal.h>
30 #include <assert.h>
31 #include <linux/videodev2.h>
32 #include "v4l2_util.h"
33
34 /* Global Declaration */
35 Buffer *buffers, *CurBuffers;
36 bool CtrlFlag = false;
37 int m_q[5], m_first = 0, m_last = 0, m_numInQ = 0;
38 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
39 pthread_mutex_t empty = PTHREAD_MUTEX_INITIALIZER;
40
v4l2Device(const char * devname,uint32_t width,uint32_t height,uint32_t num_buffers,enum AtomISPMode MipiMode,enum V4L2PixelFormat v4l2Format)41 v4l2Device::v4l2Device( const char *devname,
42 uint32_t width,
43 uint32_t height,
44 uint32_t num_buffers,
45 enum AtomISPMode MipiMode,
46 enum V4L2PixelFormat v4l2Format):
47 m_devname(devname),
48 m_height(height),
49 m_width(width),
50 m_num_buffers(num_buffers),
51 m_MipiPort(0),
52 m_MipiMode(MipiMode),
53 m_v4l2Format(v4l2Format),
54 m_fd(-1)
55 {
56 }
57
~v4l2Device()58 v4l2Device::~v4l2Device()
59 {
60 if (m_fd > -1)
61 {
62 BYE_ON(close(m_fd) < 0, "V4L2 device close failed: %s\n", ERRSTR);
63 }
64 }
65
blockIOCTL(int handle,int request,void * args)66 int v4l2Device::blockIOCTL(int handle, int request, void *args)
67 {
68 int ioctlStatus;
69 do
70 {
71 ioctlStatus = ioctl(handle, request, args);
72 } while (-1 == ioctlStatus && EINTR == errno);
73 return ioctlStatus;
74 }
75
GetAtomISPModes(enum AtomISPMode mode)76 int v4l2Device::GetAtomISPModes(enum AtomISPMode mode)
77 {
78 switch(mode)
79 {
80 case VIDEO: return _ISP_MODE_VIDEO;
81 case PREVIEW: return _ISP_MODE_PREVIEW;
82 case CONTINUOUS: return _ISP_MODE_CONTINUOUS;
83 case STILL: return _ISP_MODE_STILL;
84 case NONE:
85
86 default:
87 return _ISP_MODE_NONE;
88 }
89 }
90
ConvertToMFXFourCC(enum V4L2PixelFormat v4l2Format)91 int v4l2Device::ConvertToMFXFourCC(enum V4L2PixelFormat v4l2Format)
92 {
93 switch (v4l2Format)
94 {
95 case UYVY: return MFX_FOURCC_UYVY;
96 case YUY2: return MFX_FOURCC_YUY2;
97 case NO_FORMAT:
98
99 default:
100 assert( !"Unsupported mfx fourcc");
101 return 0;
102 }
103 }
104
ConvertToV4L2FourCC()105 int v4l2Device::ConvertToV4L2FourCC()
106 {
107 switch (m_v4l2Format)
108 {
109 case UYVY: return V4L2_PIX_FMT_UYVY;
110 case YUY2: return V4L2_PIX_FMT_YUYV;
111 case NO_FORMAT:
112
113 default:
114 assert( !"Unsupported v4l2 fourcc");
115 return 0;
116 }
117 }
118
Init(const char * devname,uint32_t width,uint32_t height,uint32_t num_buffers,enum V4L2PixelFormat v4l2Format,enum AtomISPMode MipiMode,int MipiPort)119 void v4l2Device::Init( const char *devname,
120 uint32_t width,
121 uint32_t height,
122 uint32_t num_buffers,
123 enum V4L2PixelFormat v4l2Format,
124 enum AtomISPMode MipiMode,
125 int MipiPort)
126 {
127
128 (devname != NULL)? m_devname = devname : m_devname;
129 (m_width != width )? m_width = width : m_width;
130 (m_height != height)? m_height = height : m_height;
131 (m_num_buffers != num_buffers)? m_num_buffers = num_buffers : m_num_buffers;
132 (m_v4l2Format != v4l2Format )? m_v4l2Format = v4l2Format : m_v4l2Format;
133 (m_MipiMode != MipiMode )? m_MipiMode = MipiMode : m_MipiMode;
134 (m_MipiPort != MipiPort )? m_MipiPort = MipiPort : m_MipiPort;
135
136 memset(&m_format, 0, sizeof m_format);
137 m_format.width = m_width;
138 m_format.height = m_height;
139 m_format.pixelformat = ConvertToV4L2FourCC();
140
141 V4L2Init();
142 }
143
V4L2Init()144 void v4l2Device::V4L2Init()
145 {
146 int ret;
147 struct v4l2_format fmt;
148 struct v4l2_capability caps;
149 struct v4l2_streamparm parm;
150 struct v4l2_requestbuffers rqbufs;
151 CLEAR(parm);
152
153 m_fd = open(m_devname, O_RDWR);
154 BYE_ON(m_fd < 0, "failed to open %s: %s\n", m_devname, ERRSTR);
155 CLEAR(caps);
156
157 /* Specifically for setting up mipi configuration. DMABUFF is
158 * also enable by default here.
159 */
160 if (m_MipiPort > -1 && m_MipiMode != NONE) {
161 parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
162 parm.parm.capture.capturemode = GetAtomISPModes(m_MipiMode);
163
164 ret = blockIOCTL(m_fd, VIDIOC_S_INPUT, &m_MipiPort);
165 BYE_ON(ret < 0, "VIDIOC_S_INPUT failed: %s\n", ERRSTR);
166
167 ret = blockIOCTL(m_fd, VIDIOC_S_PARM, &parm);
168 BYE_ON(ret < 0, "VIDIOC_S_PARAM failed: %s\n", ERRSTR);
169 }
170
171 ret = blockIOCTL(m_fd, VIDIOC_QUERYCAP, &caps);
172 msdk_printf( "Driver Caps:\n"
173 " Driver: \"%s\"\n"
174 " Card: \"%s\"\n"
175 " Bus: \"%s\"\n"
176 " Version: %d.%d\n"
177 " Capabilities: %08x\n",
178 caps.driver,
179 caps.card,
180 caps.bus_info,
181 (caps.version>>16)&&0xff,
182 (caps.version>>24)&&0xff,
183 caps.capabilities);
184
185 BYE_ON(ret, "VIDIOC_QUERYCAP failed: %s\n", ERRSTR);
186 BYE_ON(~caps.capabilities & V4L2_CAP_VIDEO_CAPTURE,
187 "video: singleplanar capture is not supported\n");
188
189 CLEAR(fmt);
190 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
191 ret = blockIOCTL(m_fd, VIDIOC_G_FMT, &fmt);
192
193 BYE_ON(ret < 0, "VIDIOC_G_FMT failed: %s\n", ERRSTR);
194
195 msdk_printf("G_FMT(start): width = %u, height = %u, 4cc = %.4s, BPP = %u sizeimage = %d field = %d\n",
196 fmt.fmt.pix.width, fmt.fmt.pix.height,
197 (char*)&fmt.fmt.pix.pixelformat,
198 fmt.fmt.pix.bytesperline,
199 fmt.fmt.pix.sizeimage,
200 fmt.fmt.pix.field);
201
202 fmt.fmt.pix = m_format;
203
204 msdk_printf("G_FMT(pre): width = %u, height = %u, 4cc = %.4s, BPP = %u sizeimage = %d field = %d\n",
205 fmt.fmt.pix.width, fmt.fmt.pix.height,
206 (char*)&fmt.fmt.pix.pixelformat,
207 fmt.fmt.pix.bytesperline,
208 fmt.fmt.pix.sizeimage,
209 fmt.fmt.pix.field);
210
211 ret = blockIOCTL(m_fd, VIDIOC_S_FMT, &fmt);
212 BYE_ON(ret < 0, "VIDIOC_S_FMT failed: %s\n", ERRSTR);
213
214 ret = blockIOCTL(m_fd, VIDIOC_G_FMT, &fmt);
215 BYE_ON(ret < 0, "VIDIOC_G_FMT failed: %s\n", ERRSTR);
216 msdk_printf("G_FMT(final): width = %u, height = %u, 4cc = %.4s, BPP = %u\n",
217 fmt.fmt.pix.width, fmt.fmt.pix.height,
218 (char*)&fmt.fmt.pix.pixelformat,
219 fmt.fmt.pix.bytesperline);
220
221 CLEAR(rqbufs);
222 rqbufs.count = m_num_buffers;
223 rqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
224 rqbufs.memory = V4L2_MEMORY_DMABUF;
225
226 ret = blockIOCTL(m_fd, VIDIOC_REQBUFS, &rqbufs);
227 BYE_ON(ret < 0, "VIDIOC_REQBUFS failed: %s\n", ERRSTR);
228 BYE_ON(rqbufs.count < m_num_buffers, "video node allocated only "
229 "%u of %u buffers\n", rqbufs.count, m_num_buffers);
230
231 m_format = fmt.fmt.pix;
232 }
233
V4L2Alloc()234 void v4l2Device::V4L2Alloc()
235 {
236 buffers = (Buffer *)malloc(sizeof(Buffer) * (int) m_num_buffers);
237 }
238
V4L2QueueBuffer(Buffer * buffer)239 void v4l2Device::V4L2QueueBuffer(Buffer *buffer)
240 {
241 struct v4l2_buffer buf;
242 int ret;
243
244 memset(&buf, 0, sizeof buf);
245 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
246 buf.memory = V4L2_MEMORY_DMABUF;
247 buf.index = buffer->index;
248 buf.m.fd = buffer->fd;
249
250 ret = blockIOCTL(m_fd, VIDIOC_QBUF, &buf);
251 BYE_ON(ret < 0, "VIDIOC_QBUF for buffer %d failed: %s (fd %u) (i %u)\n",
252 buf.index, ERRSTR, buffer->fd, buffer->index);
253 }
254
V4L2DeQueueBuffer(Buffer * buffer)255 Buffer *v4l2Device::V4L2DeQueueBuffer(Buffer *buffer)
256 {
257 struct v4l2_buffer buf;
258 int ret;
259
260 memset(&buf, 0, sizeof buf);
261
262 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
263 buf.memory = V4L2_MEMORY_DMABUF;
264
265 ret = blockIOCTL(m_fd, VIDIOC_DQBUF, &buf);
266 BYE_ON(ret, "VIDIOC_DQBUF failed: %s\n", ERRSTR);
267
268 return &buffer[buf.index];
269 }
270
V4L2StartCapture()271 void v4l2Device::V4L2StartCapture()
272 {
273 int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
274 int ret = 0;
275
276 ret = blockIOCTL(m_fd, VIDIOC_STREAMON, &type);
277 BYE_ON(ret < 0, "STREAMON failed: %s\n", ERRSTR);
278 }
279
V4L2StopCapture()280 void v4l2Device::V4L2StopCapture()
281 {
282 int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
283 int ret = 0;
284
285 ret = blockIOCTL(m_fd, VIDIOC_STREAMOFF, &type);
286 BYE_ON(ret < 0, "STREAMOFF failed: %s\n", ERRSTR);
287 }
288
PutOnQ(int x)289 void v4l2Device::PutOnQ(int x)
290 {
291 pthread_mutex_lock(&mutex);
292 m_q[m_first] = x;
293 m_first = (m_first+1) % 5;
294 m_numInQ++;
295 pthread_mutex_unlock(&mutex);
296 pthread_mutex_unlock(&empty);
297 }
298
GetOffQ()299 int v4l2Device::GetOffQ()
300 {
301 int thing;
302
303 /* wait if the queue is empty. */
304 while (m_numInQ == 0)
305 pthread_mutex_lock(&empty);
306
307 pthread_mutex_lock(&mutex);
308 thing = m_q[m_last];
309 m_last = (m_last+1) % 5;
310 m_numInQ--;
311 pthread_mutex_unlock(&mutex);
312
313 return thing;
314 }
315
GetV4L2TerminationSignal()316 int v4l2Device::GetV4L2TerminationSignal()
317 {
318 return (CtrlFlag && m_numInQ == 0)? 1 : 0;
319 }
320
CtrlCTerminationHandler(int s)321 static void CtrlCTerminationHandler(int s) { CtrlFlag = true; }
322
PollingThread(void * data)323 void *PollingThread(void *data)
324 {
325
326 v4l2Device *v4l2 = (v4l2Device *)data;
327
328 struct sigaction sigIntHandler;
329 sigIntHandler.sa_handler = CtrlCTerminationHandler;
330 sigemptyset(&sigIntHandler.sa_mask);
331 sigIntHandler.sa_flags = 0;
332 sigaction(SIGINT, &sigIntHandler, NULL);
333
334 struct pollfd fd;
335 fd.fd = v4l2->GetV4L2DisplayID();
336 fd.events = POLLIN;
337
338 while(1)
339 {
340 if (poll(&fd, 1, 5000) > 0)
341 {
342 if (fd.revents & POLLIN)
343 {
344 CurBuffers = v4l2->V4L2DeQueueBuffer(buffers);
345 v4l2->PutOnQ(CurBuffers->index);
346
347 if (CtrlFlag)
348 break;
349
350 if (CurBuffers)
351 v4l2->V4L2QueueBuffer(&buffers[CurBuffers->index]);
352 }
353 }
354 }
355 }
356
357 #endif // ifdef ENABLE_V4L2_SUPPORT
358