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