xref: /openbmc/obmc-ikvm/ikvm_video.cpp (revision 90d4958163cc6ae1e1bf2cf50b6b5b4bfb6fb845)
121b177e0SEddie James #include "ikvm_video.hpp"
221b177e0SEddie James 
3*90d49581SEddie James #include <err.h>
4*90d49581SEddie James #include <errno.h>
5*90d49581SEddie James #include <fcntl.h>
6*90d49581SEddie James #include <linux/videodev2.h>
7*90d49581SEddie James #include <poll.h>
8*90d49581SEddie James #include <sys/ioctl.h>
9*90d49581SEddie James #include <sys/mman.h>
10*90d49581SEddie James #include <sys/select.h>
11*90d49581SEddie James #include <sys/stat.h>
12*90d49581SEddie James #include <sys/time.h>
13*90d49581SEddie James #include <sys/types.h>
14*90d49581SEddie James #include <unistd.h>
15*90d49581SEddie James 
16*90d49581SEddie James #include <phosphor-logging/elog-errors.hpp>
17*90d49581SEddie James #include <phosphor-logging/elog.hpp>
18*90d49581SEddie James #include <phosphor-logging/log.hpp>
19*90d49581SEddie James #include <xyz/openbmc_project/Common/Device/error.hpp>
20*90d49581SEddie James #include <xyz/openbmc_project/Common/File/error.hpp>
21*90d49581SEddie James 
2221b177e0SEddie James namespace ikvm
2321b177e0SEddie James {
2421b177e0SEddie James 
25*90d49581SEddie James const int Video::bitsPerSample(8);
26*90d49581SEddie James const int Video::bytesPerPixel(4);
27*90d49581SEddie James const int Video::samplesPerPixel(3);
28*90d49581SEddie James 
29*90d49581SEddie James using namespace phosphor::logging;
30*90d49581SEddie James using namespace sdbusplus::xyz::openbmc_project::Common::File::Error;
31*90d49581SEddie James using namespace sdbusplus::xyz::openbmc_project::Common::Device::Error;
32*90d49581SEddie James 
3321b177e0SEddie James Video::Video(const std::string& p, Input& input, int fr) :
34*90d49581SEddie James     resizeAfterOpen(false), fd(-1), frameRate(fr), lastFrameIndex(-1),
3521b177e0SEddie James     height(600), width(800), input(input), path(p)
3621b177e0SEddie James {
3721b177e0SEddie James }
3821b177e0SEddie James 
3921b177e0SEddie James Video::~Video()
4021b177e0SEddie James {
41*90d49581SEddie James     stop();
42*90d49581SEddie James }
43*90d49581SEddie James 
44*90d49581SEddie James char* Video::getData()
45*90d49581SEddie James {
46*90d49581SEddie James     if (lastFrameIndex >= 0)
47*90d49581SEddie James     {
48*90d49581SEddie James         return (char*)buffers[lastFrameIndex].data;
49*90d49581SEddie James     }
50*90d49581SEddie James 
51*90d49581SEddie James     return nullptr;
52*90d49581SEddie James }
53*90d49581SEddie James 
54*90d49581SEddie James void Video::getFrame()
55*90d49581SEddie James {
56*90d49581SEddie James     int rc(0);
57*90d49581SEddie James     int fd_flags;
58*90d49581SEddie James     v4l2_buffer buf;
59*90d49581SEddie James     fd_set fds;
60*90d49581SEddie James     timeval tv;
61*90d49581SEddie James 
62*90d49581SEddie James     if (fd < 0)
63*90d49581SEddie James     {
64*90d49581SEddie James         return;
65*90d49581SEddie James     }
66*90d49581SEddie James 
67*90d49581SEddie James     FD_ZERO(&fds);
68*90d49581SEddie James     FD_SET(fd, &fds);
69*90d49581SEddie James 
70*90d49581SEddie James     tv.tv_sec = 1;
71*90d49581SEddie James     tv.tv_usec = 0;
72*90d49581SEddie James 
73*90d49581SEddie James     memset(&buf, 0, sizeof(v4l2_buffer));
74*90d49581SEddie James     buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
75*90d49581SEddie James     buf.memory = V4L2_MEMORY_MMAP;
76*90d49581SEddie James 
77*90d49581SEddie James     // Switch to non-blocking in order to safely dequeue all buffers; if the
78*90d49581SEddie James     // video signal is lost while blocking to dequeue, the video driver may
79*90d49581SEddie James     // wait forever if signal is not re-acquired
80*90d49581SEddie James     fd_flags = fcntl(fd, F_GETFL);
81*90d49581SEddie James     fcntl(fd, F_SETFL, fd_flags | O_NONBLOCK);
82*90d49581SEddie James 
83*90d49581SEddie James     rc = select(fd + 1, &fds, NULL, NULL, &tv);
84*90d49581SEddie James     if (rc > 0)
85*90d49581SEddie James     {
86*90d49581SEddie James         do
87*90d49581SEddie James         {
88*90d49581SEddie James             rc = ioctl(fd, VIDIOC_DQBUF, &buf);
89*90d49581SEddie James             if (rc >= 0)
90*90d49581SEddie James             {
91*90d49581SEddie James                 buffers[buf.index].queued = false;
92*90d49581SEddie James 
93*90d49581SEddie James                 if (!(buf.flags & V4L2_BUF_FLAG_ERROR))
94*90d49581SEddie James                 {
95*90d49581SEddie James                     lastFrameIndex = buf.index;
96*90d49581SEddie James                     buffers[lastFrameIndex].payload = buf.bytesused;
97*90d49581SEddie James                     break;
98*90d49581SEddie James                 }
99*90d49581SEddie James                 else
100*90d49581SEddie James                 {
101*90d49581SEddie James                     buffers[buf.index].payload = 0;
102*90d49581SEddie James                 }
103*90d49581SEddie James             }
104*90d49581SEddie James         } while (rc >= 0);
105*90d49581SEddie James     }
106*90d49581SEddie James 
107*90d49581SEddie James     fcntl(fd, F_SETFL, fd_flags);
108*90d49581SEddie James 
109*90d49581SEddie James     for (unsigned int i = 0; i < buffers.size(); ++i)
110*90d49581SEddie James     {
111*90d49581SEddie James         if (i == (unsigned int)lastFrameIndex)
112*90d49581SEddie James         {
113*90d49581SEddie James             continue;
114*90d49581SEddie James         }
115*90d49581SEddie James 
116*90d49581SEddie James         if (!buffers[i].queued)
117*90d49581SEddie James         {
118*90d49581SEddie James             memset(&buf, 0, sizeof(v4l2_buffer));
119*90d49581SEddie James             buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
120*90d49581SEddie James             buf.memory = V4L2_MEMORY_MMAP;
121*90d49581SEddie James             buf.index = i;
122*90d49581SEddie James 
123*90d49581SEddie James             rc = ioctl(fd, VIDIOC_QBUF, &buf);
124*90d49581SEddie James             if (rc)
125*90d49581SEddie James             {
126*90d49581SEddie James                 log<level::ERR>("Failed to queue buffer",
127*90d49581SEddie James                                 entry("ERROR=%s", strerror(errno)));
128*90d49581SEddie James             }
129*90d49581SEddie James             else
130*90d49581SEddie James             {
131*90d49581SEddie James                 buffers[i].queued = true;
132*90d49581SEddie James             }
133*90d49581SEddie James         }
134*90d49581SEddie James     }
135*90d49581SEddie James }
136*90d49581SEddie James 
137*90d49581SEddie James bool Video::needsResize()
138*90d49581SEddie James {
139*90d49581SEddie James     int rc;
140*90d49581SEddie James     v4l2_dv_timings timings;
141*90d49581SEddie James 
142*90d49581SEddie James     if (fd < 0)
143*90d49581SEddie James     {
144*90d49581SEddie James         return false;
145*90d49581SEddie James     }
146*90d49581SEddie James 
147*90d49581SEddie James     if (resizeAfterOpen)
148*90d49581SEddie James     {
149*90d49581SEddie James         return true;
150*90d49581SEddie James     }
151*90d49581SEddie James 
152*90d49581SEddie James     memset(&timings, 0, sizeof(v4l2_dv_timings));
153*90d49581SEddie James     rc = ioctl(fd, VIDIOC_QUERY_DV_TIMINGS, &timings);
154*90d49581SEddie James     if (rc < 0)
155*90d49581SEddie James     {
156*90d49581SEddie James         log<level::ERR>("Failed to query timings",
157*90d49581SEddie James                         entry("ERROR=%s", strerror(errno)));
158*90d49581SEddie James         return false;
159*90d49581SEddie James     }
160*90d49581SEddie James 
161*90d49581SEddie James     if (timings.bt.width != width || timings.bt.height != height)
162*90d49581SEddie James     {
163*90d49581SEddie James         width = timings.bt.width;
164*90d49581SEddie James         height = timings.bt.height;
165*90d49581SEddie James 
166*90d49581SEddie James         if (!width || !height)
167*90d49581SEddie James         {
168*90d49581SEddie James             log<level::ERR>("Failed to get new resolution",
169*90d49581SEddie James                             entry("WIDTH=%d", width),
170*90d49581SEddie James                             entry("HEIGHT=%d", height));
171*90d49581SEddie James             elog<Open>(
172*90d49581SEddie James                 xyz::openbmc_project::Common::File::Open::ERRNO(-EPROTO),
173*90d49581SEddie James                 xyz::openbmc_project::Common::File::Open::PATH(path.c_str()));
174*90d49581SEddie James         }
175*90d49581SEddie James 
176*90d49581SEddie James         lastFrameIndex = -1;
177*90d49581SEddie James         return true;
178*90d49581SEddie James     }
179*90d49581SEddie James 
180*90d49581SEddie James     return false;
181*90d49581SEddie James }
182*90d49581SEddie James 
183*90d49581SEddie James void Video::resize()
184*90d49581SEddie James {
185*90d49581SEddie James     int rc;
186*90d49581SEddie James     unsigned int i;
187*90d49581SEddie James     bool needsResizeCall(false);
188*90d49581SEddie James     v4l2_buf_type type(V4L2_BUF_TYPE_VIDEO_CAPTURE);
189*90d49581SEddie James     v4l2_requestbuffers req;
190*90d49581SEddie James 
191*90d49581SEddie James     if (fd < 0)
192*90d49581SEddie James     {
193*90d49581SEddie James         return;
194*90d49581SEddie James     }
195*90d49581SEddie James 
196*90d49581SEddie James     if (resizeAfterOpen)
197*90d49581SEddie James     {
198*90d49581SEddie James         resizeAfterOpen = false;
199*90d49581SEddie James         return;
200*90d49581SEddie James     }
201*90d49581SEddie James 
202*90d49581SEddie James     for (i = 0; i < buffers.size(); ++i)
203*90d49581SEddie James     {
204*90d49581SEddie James         if (buffers[i].data)
205*90d49581SEddie James         {
206*90d49581SEddie James             needsResizeCall = true;
207*90d49581SEddie James             break;
208*90d49581SEddie James         }
209*90d49581SEddie James     }
210*90d49581SEddie James 
211*90d49581SEddie James     if (needsResizeCall)
212*90d49581SEddie James     {
213*90d49581SEddie James         rc = ioctl(fd, VIDIOC_STREAMOFF, &type);
214*90d49581SEddie James         if (rc)
215*90d49581SEddie James         {
216*90d49581SEddie James             log<level::ERR>("Failed to stop streaming",
217*90d49581SEddie James                             entry("ERROR=%s", strerror(errno)));
218*90d49581SEddie James             elog<ReadFailure>(
219*90d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
220*90d49581SEddie James                     CALLOUT_ERRNO(errno),
221*90d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
222*90d49581SEddie James                     CALLOUT_DEVICE_PATH(path.c_str()));
223*90d49581SEddie James         }
224*90d49581SEddie James     }
225*90d49581SEddie James 
226*90d49581SEddie James     for (i = 0; i < buffers.size(); ++i)
227*90d49581SEddie James     {
228*90d49581SEddie James         if (buffers[i].data)
229*90d49581SEddie James         {
230*90d49581SEddie James             munmap(buffers[i].data, buffers[i].size);
231*90d49581SEddie James             buffers[i].data = nullptr;
232*90d49581SEddie James             buffers[i].queued = false;
233*90d49581SEddie James         }
234*90d49581SEddie James     }
235*90d49581SEddie James 
236*90d49581SEddie James     if (needsResizeCall)
237*90d49581SEddie James     {
238*90d49581SEddie James         v4l2_dv_timings timings;
239*90d49581SEddie James 
240*90d49581SEddie James         memset(&req, 0, sizeof(v4l2_requestbuffers));
241*90d49581SEddie James         req.count = 0;
242*90d49581SEddie James         req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
243*90d49581SEddie James         req.memory = V4L2_MEMORY_MMAP;
244*90d49581SEddie James         rc = ioctl(fd, VIDIOC_REQBUFS, &req);
245*90d49581SEddie James         if (rc < 0)
246*90d49581SEddie James         {
247*90d49581SEddie James             log<level::ERR>("Failed to zero streaming buffers",
248*90d49581SEddie James                             entry("ERROR=%s", strerror(errno)));
249*90d49581SEddie James             elog<ReadFailure>(
250*90d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
251*90d49581SEddie James                     CALLOUT_ERRNO(errno),
252*90d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
253*90d49581SEddie James                     CALLOUT_DEVICE_PATH(path.c_str()));
254*90d49581SEddie James         }
255*90d49581SEddie James 
256*90d49581SEddie James         memset(&timings, 0, sizeof(v4l2_dv_timings));
257*90d49581SEddie James         rc = ioctl(fd, VIDIOC_QUERY_DV_TIMINGS, &timings);
258*90d49581SEddie James         if (rc < 0)
259*90d49581SEddie James         {
260*90d49581SEddie James             log<level::ERR>("Failed to query timings",
261*90d49581SEddie James                             entry("ERROR=%s", strerror(errno)));
262*90d49581SEddie James             elog<ReadFailure>(
263*90d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
264*90d49581SEddie James                     CALLOUT_ERRNO(errno),
265*90d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
266*90d49581SEddie James                     CALLOUT_DEVICE_PATH(path.c_str()));
267*90d49581SEddie James         }
268*90d49581SEddie James 
269*90d49581SEddie James         rc = ioctl(fd, VIDIOC_S_DV_TIMINGS, &timings);
270*90d49581SEddie James         if (rc < 0)
271*90d49581SEddie James         {
272*90d49581SEddie James             log<level::ERR>("Failed to set timings",
273*90d49581SEddie James                             entry("ERROR=%s", strerror(errno)));
274*90d49581SEddie James             elog<ReadFailure>(
275*90d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
276*90d49581SEddie James                     CALLOUT_ERRNO(errno),
277*90d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
278*90d49581SEddie James                     CALLOUT_DEVICE_PATH(path.c_str()));
279*90d49581SEddie James         }
280*90d49581SEddie James 
281*90d49581SEddie James         buffers.clear();
282*90d49581SEddie James     }
283*90d49581SEddie James 
284*90d49581SEddie James     memset(&req, 0, sizeof(v4l2_requestbuffers));
285*90d49581SEddie James     req.count = 3;
286*90d49581SEddie James     req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
287*90d49581SEddie James     req.memory = V4L2_MEMORY_MMAP;
288*90d49581SEddie James     rc = ioctl(fd, VIDIOC_REQBUFS, &req);
289*90d49581SEddie James     if (rc < 0 || req.count < 2)
290*90d49581SEddie James     {
291*90d49581SEddie James         log<level::ERR>("Failed to request streaming buffers",
292*90d49581SEddie James                         entry("ERROR=%s", strerror(errno)));
293*90d49581SEddie James         elog<ReadFailure>(
294*90d49581SEddie James             xyz::openbmc_project::Common::Device::ReadFailure::CALLOUT_ERRNO(
295*90d49581SEddie James                 errno),
296*90d49581SEddie James             xyz::openbmc_project::Common::Device::ReadFailure::
297*90d49581SEddie James                 CALLOUT_DEVICE_PATH(path.c_str()));
298*90d49581SEddie James     }
299*90d49581SEddie James 
300*90d49581SEddie James     buffers.resize(req.count);
301*90d49581SEddie James 
302*90d49581SEddie James     for (i = 0; i < buffers.size(); ++i)
303*90d49581SEddie James     {
304*90d49581SEddie James         v4l2_buffer buf;
305*90d49581SEddie James 
306*90d49581SEddie James         memset(&buf, 0, sizeof(v4l2_buffer));
307*90d49581SEddie James         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
308*90d49581SEddie James         buf.memory = V4L2_MEMORY_MMAP;
309*90d49581SEddie James         buf.index = i;
310*90d49581SEddie James 
311*90d49581SEddie James         rc = ioctl(fd, VIDIOC_QUERYBUF, &buf);
312*90d49581SEddie James         if (rc < 0)
313*90d49581SEddie James         {
314*90d49581SEddie James             log<level::ERR>("Failed to query buffer",
315*90d49581SEddie James                             entry("ERROR=%s", strerror(errno)));
316*90d49581SEddie James             elog<ReadFailure>(
317*90d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
318*90d49581SEddie James                     CALLOUT_ERRNO(errno),
319*90d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
320*90d49581SEddie James                     CALLOUT_DEVICE_PATH(path.c_str()));
321*90d49581SEddie James         }
322*90d49581SEddie James 
323*90d49581SEddie James         buffers[i].data = mmap(NULL, buf.length, PROT_READ | PROT_WRITE,
324*90d49581SEddie James                                MAP_SHARED, fd, buf.m.offset);
325*90d49581SEddie James         if (buffers[i].data == MAP_FAILED)
326*90d49581SEddie James         {
327*90d49581SEddie James             log<level::ERR>("Failed to mmap buffer",
328*90d49581SEddie James                             entry("ERROR=%s", strerror(errno)));
329*90d49581SEddie James             elog<ReadFailure>(
330*90d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
331*90d49581SEddie James                     CALLOUT_ERRNO(errno),
332*90d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
333*90d49581SEddie James                     CALLOUT_DEVICE_PATH(path.c_str()));
334*90d49581SEddie James         }
335*90d49581SEddie James 
336*90d49581SEddie James         buffers[i].size = buf.length;
337*90d49581SEddie James 
338*90d49581SEddie James         rc = ioctl(fd, VIDIOC_QBUF, &buf);
339*90d49581SEddie James         if (rc < 0)
340*90d49581SEddie James         {
341*90d49581SEddie James             log<level::ERR>("Failed to queue buffer",
342*90d49581SEddie James                             entry("ERROR=%s", strerror(errno)));
343*90d49581SEddie James             elog<ReadFailure>(
344*90d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
345*90d49581SEddie James                     CALLOUT_ERRNO(errno),
346*90d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
347*90d49581SEddie James                     CALLOUT_DEVICE_PATH(path.c_str()));
348*90d49581SEddie James         }
349*90d49581SEddie James 
350*90d49581SEddie James         buffers[i].queued = true;
351*90d49581SEddie James     }
352*90d49581SEddie James 
353*90d49581SEddie James     rc = ioctl(fd, VIDIOC_STREAMON, &type);
354*90d49581SEddie James     if (rc)
355*90d49581SEddie James     {
356*90d49581SEddie James         log<level::ERR>("Failed to start streaming",
357*90d49581SEddie James                         entry("ERROR=%s", strerror(errno)));
358*90d49581SEddie James         elog<ReadFailure>(
359*90d49581SEddie James             xyz::openbmc_project::Common::Device::ReadFailure::CALLOUT_ERRNO(
360*90d49581SEddie James                 errno),
361*90d49581SEddie James             xyz::openbmc_project::Common::Device::ReadFailure::
362*90d49581SEddie James                 CALLOUT_DEVICE_PATH(path.c_str()));
363*90d49581SEddie James     }
364*90d49581SEddie James }
365*90d49581SEddie James 
366*90d49581SEddie James void Video::start()
367*90d49581SEddie James {
368*90d49581SEddie James     int rc;
369*90d49581SEddie James     size_t oldHeight = height;
370*90d49581SEddie James     size_t oldWidth = width;
371*90d49581SEddie James     v4l2_capability cap;
372*90d49581SEddie James     v4l2_format fmt;
373*90d49581SEddie James     v4l2_streamparm sparm;
374*90d49581SEddie James 
375*90d49581SEddie James     if (fd >= 0)
376*90d49581SEddie James     {
377*90d49581SEddie James         return;
378*90d49581SEddie James     }
379*90d49581SEddie James 
380*90d49581SEddie James     fd = open(path.c_str(), O_RDWR);
381*90d49581SEddie James     if (fd < 0)
382*90d49581SEddie James     {
383*90d49581SEddie James         unsigned short xx = SHRT_MAX;
384*90d49581SEddie James         char wakeupReport[6] = {0};
385*90d49581SEddie James 
386*90d49581SEddie James         wakeupReport[0] = 2;
387*90d49581SEddie James         memcpy(&wakeupReport[2], &xx, 2);
388*90d49581SEddie James 
389*90d49581SEddie James         input.sendRaw(wakeupReport, 6);
390*90d49581SEddie James 
391*90d49581SEddie James         fd = open(path.c_str(), O_RDWR);
392*90d49581SEddie James         if (fd < 0)
393*90d49581SEddie James         {
394*90d49581SEddie James             log<level::ERR>("Failed to open video device",
395*90d49581SEddie James                             entry("PATH=%s", path.c_str()),
396*90d49581SEddie James                             entry("ERROR=%s", strerror(errno)));
397*90d49581SEddie James             elog<Open>(
398*90d49581SEddie James                 xyz::openbmc_project::Common::File::Open::ERRNO(errno),
399*90d49581SEddie James                 xyz::openbmc_project::Common::File::Open::PATH(path.c_str()));
400*90d49581SEddie James         }
401*90d49581SEddie James     }
402*90d49581SEddie James 
403*90d49581SEddie James     memset(&cap, 0, sizeof(v4l2_capability));
404*90d49581SEddie James     rc = ioctl(fd, VIDIOC_QUERYCAP, &cap);
405*90d49581SEddie James     if (rc < 0)
406*90d49581SEddie James     {
407*90d49581SEddie James         log<level::ERR>("Failed to query video device capabilities",
408*90d49581SEddie James                         entry("ERROR=%s", strerror(errno)));
409*90d49581SEddie James         elog<ReadFailure>(
410*90d49581SEddie James             xyz::openbmc_project::Common::Device::ReadFailure::CALLOUT_ERRNO(
411*90d49581SEddie James                 errno),
412*90d49581SEddie James             xyz::openbmc_project::Common::Device::ReadFailure::
413*90d49581SEddie James                 CALLOUT_DEVICE_PATH(path.c_str()));
414*90d49581SEddie James     }
415*90d49581SEddie James 
416*90d49581SEddie James     if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) ||
417*90d49581SEddie James         !(cap.capabilities & V4L2_CAP_STREAMING))
418*90d49581SEddie James     {
419*90d49581SEddie James         log<level::ERR>("Video device doesn't support this application");
420*90d49581SEddie James         elog<Open>(
421*90d49581SEddie James             xyz::openbmc_project::Common::File::Open::ERRNO(errno),
422*90d49581SEddie James             xyz::openbmc_project::Common::File::Open::PATH(path.c_str()));
423*90d49581SEddie James     }
424*90d49581SEddie James 
425*90d49581SEddie James     memset(&fmt, 0, sizeof(v4l2_format));
426*90d49581SEddie James     fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
427*90d49581SEddie James     rc = ioctl(fd, VIDIOC_G_FMT, &fmt);
428*90d49581SEddie James     if (rc < 0)
429*90d49581SEddie James     {
430*90d49581SEddie James         log<level::ERR>("Failed to query video device format",
431*90d49581SEddie James                         entry("ERROR=%s", strerror(errno)));
432*90d49581SEddie James         elog<ReadFailure>(
433*90d49581SEddie James             xyz::openbmc_project::Common::Device::ReadFailure::CALLOUT_ERRNO(
434*90d49581SEddie James                 errno),
435*90d49581SEddie James             xyz::openbmc_project::Common::Device::ReadFailure::
436*90d49581SEddie James                 CALLOUT_DEVICE_PATH(path.c_str()));
437*90d49581SEddie James     }
438*90d49581SEddie James 
439*90d49581SEddie James     memset(&sparm, 0, sizeof(v4l2_streamparm));
440*90d49581SEddie James     sparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
441*90d49581SEddie James     sparm.parm.capture.timeperframe.numerator = 1;
442*90d49581SEddie James     sparm.parm.capture.timeperframe.denominator = frameRate;
443*90d49581SEddie James     rc = ioctl(fd, VIDIOC_S_PARM, &sparm);
444*90d49581SEddie James     if (rc < 0)
445*90d49581SEddie James     {
446*90d49581SEddie James         log<level::WARNING>("Failed to set video device frame rate",
447*90d49581SEddie James                             entry("ERROR=%s", strerror(errno)));
448*90d49581SEddie James     }
449*90d49581SEddie James 
450*90d49581SEddie James     height = fmt.fmt.pix.height;
451*90d49581SEddie James     width = fmt.fmt.pix.width;
452*90d49581SEddie James 
453*90d49581SEddie James     resize();
454*90d49581SEddie James 
455*90d49581SEddie James     if (oldHeight != height || oldWidth != width)
456*90d49581SEddie James     {
457*90d49581SEddie James         resizeAfterOpen = true;
458*90d49581SEddie James     }
459*90d49581SEddie James }
460*90d49581SEddie James 
461*90d49581SEddie James void Video::stop()
462*90d49581SEddie James {
463*90d49581SEddie James     int rc;
464*90d49581SEddie James     unsigned int i;
465*90d49581SEddie James     v4l2_buf_type type(V4L2_BUF_TYPE_VIDEO_CAPTURE);
466*90d49581SEddie James 
467*90d49581SEddie James     if (fd < 0)
468*90d49581SEddie James     {
469*90d49581SEddie James         return;
470*90d49581SEddie James     }
471*90d49581SEddie James 
472*90d49581SEddie James     lastFrameIndex = -1;
473*90d49581SEddie James 
474*90d49581SEddie James     rc = ioctl(fd, VIDIOC_STREAMOFF, &type);
475*90d49581SEddie James     if (rc)
476*90d49581SEddie James     {
477*90d49581SEddie James         log<level::ERR>("Failed to stop streaming",
478*90d49581SEddie James                         entry("ERROR=%s", strerror(errno)));
479*90d49581SEddie James     }
480*90d49581SEddie James 
481*90d49581SEddie James     for (i = 0; i < buffers.size(); ++i)
482*90d49581SEddie James     {
483*90d49581SEddie James         if (buffers[i].data)
484*90d49581SEddie James         {
485*90d49581SEddie James             munmap(buffers[i].data, buffers[i].size);
486*90d49581SEddie James             buffers[i].data = nullptr;
487*90d49581SEddie James             buffers[i].queued = false;
488*90d49581SEddie James         }
489*90d49581SEddie James     }
490*90d49581SEddie James 
491*90d49581SEddie James     close(fd);
492*90d49581SEddie James     fd = -1;
49321b177e0SEddie James }
49421b177e0SEddie James 
49521b177e0SEddie James } // namespace ikvm
496