xref: /openbmc/obmc-ikvm/ikvm_video.cpp (revision 7dfac9ff2d1569aedf83175fb0427562c2188e63)
121b177e0SEddie James #include "ikvm_video.hpp"
221b177e0SEddie James 
390d49581SEddie James #include <err.h>
490d49581SEddie James #include <errno.h>
590d49581SEddie James #include <fcntl.h>
690d49581SEddie James #include <linux/videodev2.h>
790d49581SEddie James #include <poll.h>
890d49581SEddie James #include <sys/ioctl.h>
990d49581SEddie James #include <sys/mman.h>
1090d49581SEddie James #include <sys/select.h>
1190d49581SEddie James #include <sys/stat.h>
1290d49581SEddie James #include <sys/time.h>
1390d49581SEddie James #include <sys/types.h>
1490d49581SEddie James #include <unistd.h>
1590d49581SEddie James 
1690d49581SEddie James #include <phosphor-logging/elog-errors.hpp>
1790d49581SEddie James #include <phosphor-logging/elog.hpp>
1890d49581SEddie James #include <phosphor-logging/log.hpp>
1990d49581SEddie James #include <xyz/openbmc_project/Common/Device/error.hpp>
2090d49581SEddie James #include <xyz/openbmc_project/Common/File/error.hpp>
2190d49581SEddie James 
2221b177e0SEddie James namespace ikvm
2321b177e0SEddie James {
2421b177e0SEddie James 
2590d49581SEddie James const int Video::bitsPerSample(8);
2690d49581SEddie James const int Video::bytesPerPixel(4);
2790d49581SEddie James const int Video::samplesPerPixel(3);
2890d49581SEddie James 
2990d49581SEddie James using namespace phosphor::logging;
3090d49581SEddie James using namespace sdbusplus::xyz::openbmc_project::Common::File::Error;
3190d49581SEddie James using namespace sdbusplus::xyz::openbmc_project::Common::Device::Error;
3290d49581SEddie James 
3321b177e0SEddie James Video::Video(const std::string& p, Input& input, int fr) :
3490d49581SEddie 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 {
4190d49581SEddie James     stop();
4290d49581SEddie James }
4390d49581SEddie James 
4490d49581SEddie James char* Video::getData()
4590d49581SEddie James {
4690d49581SEddie James     if (lastFrameIndex >= 0)
4790d49581SEddie James     {
4890d49581SEddie James         return (char*)buffers[lastFrameIndex].data;
4990d49581SEddie James     }
5090d49581SEddie James 
5190d49581SEddie James     return nullptr;
5290d49581SEddie James }
5390d49581SEddie James 
5490d49581SEddie James void Video::getFrame()
5590d49581SEddie James {
5690d49581SEddie James     int rc(0);
5790d49581SEddie James     int fd_flags;
5890d49581SEddie James     v4l2_buffer buf;
5990d49581SEddie James     fd_set fds;
6090d49581SEddie James     timeval tv;
6190d49581SEddie James 
6290d49581SEddie James     if (fd < 0)
6390d49581SEddie James     {
6490d49581SEddie James         return;
6590d49581SEddie James     }
6690d49581SEddie James 
6790d49581SEddie James     FD_ZERO(&fds);
6890d49581SEddie James     FD_SET(fd, &fds);
6990d49581SEddie James 
7090d49581SEddie James     tv.tv_sec = 1;
7190d49581SEddie James     tv.tv_usec = 0;
7290d49581SEddie James 
7390d49581SEddie James     memset(&buf, 0, sizeof(v4l2_buffer));
7490d49581SEddie James     buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
7590d49581SEddie James     buf.memory = V4L2_MEMORY_MMAP;
7690d49581SEddie James 
7790d49581SEddie James     // Switch to non-blocking in order to safely dequeue all buffers; if the
7890d49581SEddie James     // video signal is lost while blocking to dequeue, the video driver may
7990d49581SEddie James     // wait forever if signal is not re-acquired
8090d49581SEddie James     fd_flags = fcntl(fd, F_GETFL);
8190d49581SEddie James     fcntl(fd, F_SETFL, fd_flags | O_NONBLOCK);
8290d49581SEddie James 
8390d49581SEddie James     rc = select(fd + 1, &fds, NULL, NULL, &tv);
8490d49581SEddie James     if (rc > 0)
8590d49581SEddie James     {
8690d49581SEddie James         do
8790d49581SEddie James         {
8890d49581SEddie James             rc = ioctl(fd, VIDIOC_DQBUF, &buf);
8990d49581SEddie James             if (rc >= 0)
9090d49581SEddie James             {
9190d49581SEddie James                 buffers[buf.index].queued = false;
9290d49581SEddie James 
9390d49581SEddie James                 if (!(buf.flags & V4L2_BUF_FLAG_ERROR))
9490d49581SEddie James                 {
9590d49581SEddie James                     lastFrameIndex = buf.index;
9690d49581SEddie James                     buffers[lastFrameIndex].payload = buf.bytesused;
9790d49581SEddie James                     break;
9890d49581SEddie James                 }
9990d49581SEddie James                 else
10090d49581SEddie James                 {
10190d49581SEddie James                     buffers[buf.index].payload = 0;
10290d49581SEddie James                 }
10390d49581SEddie James             }
10490d49581SEddie James         } while (rc >= 0);
10590d49581SEddie James     }
10690d49581SEddie James 
10790d49581SEddie James     fcntl(fd, F_SETFL, fd_flags);
10890d49581SEddie James 
10990d49581SEddie James     for (unsigned int i = 0; i < buffers.size(); ++i)
11090d49581SEddie James     {
11190d49581SEddie James         if (i == (unsigned int)lastFrameIndex)
11290d49581SEddie James         {
11390d49581SEddie James             continue;
11490d49581SEddie James         }
11590d49581SEddie James 
11690d49581SEddie James         if (!buffers[i].queued)
11790d49581SEddie James         {
11890d49581SEddie James             memset(&buf, 0, sizeof(v4l2_buffer));
11990d49581SEddie James             buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
12090d49581SEddie James             buf.memory = V4L2_MEMORY_MMAP;
12190d49581SEddie James             buf.index = i;
12290d49581SEddie James 
12390d49581SEddie James             rc = ioctl(fd, VIDIOC_QBUF, &buf);
12490d49581SEddie James             if (rc)
12590d49581SEddie James             {
12690d49581SEddie James                 log<level::ERR>("Failed to queue buffer",
12790d49581SEddie James                                 entry("ERROR=%s", strerror(errno)));
12890d49581SEddie James             }
12990d49581SEddie James             else
13090d49581SEddie James             {
13190d49581SEddie James                 buffers[i].queued = true;
13290d49581SEddie James             }
13390d49581SEddie James         }
13490d49581SEddie James     }
13590d49581SEddie James }
13690d49581SEddie James 
13790d49581SEddie James bool Video::needsResize()
13890d49581SEddie James {
13990d49581SEddie James     int rc;
14090d49581SEddie James     v4l2_dv_timings timings;
14190d49581SEddie James 
14290d49581SEddie James     if (fd < 0)
14390d49581SEddie James     {
14490d49581SEddie James         return false;
14590d49581SEddie James     }
14690d49581SEddie James 
14790d49581SEddie James     if (resizeAfterOpen)
14890d49581SEddie James     {
14990d49581SEddie James         return true;
15090d49581SEddie James     }
15190d49581SEddie James 
15290d49581SEddie James     memset(&timings, 0, sizeof(v4l2_dv_timings));
15390d49581SEddie James     rc = ioctl(fd, VIDIOC_QUERY_DV_TIMINGS, &timings);
15490d49581SEddie James     if (rc < 0)
15590d49581SEddie James     {
15690d49581SEddie James         log<level::ERR>("Failed to query timings",
15790d49581SEddie James                         entry("ERROR=%s", strerror(errno)));
15890d49581SEddie James         return false;
15990d49581SEddie James     }
16090d49581SEddie James 
16190d49581SEddie James     if (timings.bt.width != width || timings.bt.height != height)
16290d49581SEddie James     {
16390d49581SEddie James         width = timings.bt.width;
16490d49581SEddie James         height = timings.bt.height;
16590d49581SEddie James 
16690d49581SEddie James         if (!width || !height)
16790d49581SEddie James         {
16890d49581SEddie James             log<level::ERR>("Failed to get new resolution",
16990d49581SEddie James                             entry("WIDTH=%d", width),
17090d49581SEddie James                             entry("HEIGHT=%d", height));
17190d49581SEddie James             elog<Open>(
17290d49581SEddie James                 xyz::openbmc_project::Common::File::Open::ERRNO(-EPROTO),
17390d49581SEddie James                 xyz::openbmc_project::Common::File::Open::PATH(path.c_str()));
17490d49581SEddie James         }
17590d49581SEddie James 
17690d49581SEddie James         lastFrameIndex = -1;
17790d49581SEddie James         return true;
17890d49581SEddie James     }
17990d49581SEddie James 
18090d49581SEddie James     return false;
18190d49581SEddie James }
18290d49581SEddie James 
18390d49581SEddie James void Video::resize()
18490d49581SEddie James {
18590d49581SEddie James     int rc;
18690d49581SEddie James     unsigned int i;
18790d49581SEddie James     bool needsResizeCall(false);
18890d49581SEddie James     v4l2_buf_type type(V4L2_BUF_TYPE_VIDEO_CAPTURE);
18990d49581SEddie James     v4l2_requestbuffers req;
19090d49581SEddie James 
19190d49581SEddie James     if (fd < 0)
19290d49581SEddie James     {
19390d49581SEddie James         return;
19490d49581SEddie James     }
19590d49581SEddie James 
19690d49581SEddie James     if (resizeAfterOpen)
19790d49581SEddie James     {
19890d49581SEddie James         resizeAfterOpen = false;
19990d49581SEddie James         return;
20090d49581SEddie James     }
20190d49581SEddie James 
20290d49581SEddie James     for (i = 0; i < buffers.size(); ++i)
20390d49581SEddie James     {
20490d49581SEddie James         if (buffers[i].data)
20590d49581SEddie James         {
20690d49581SEddie James             needsResizeCall = true;
20790d49581SEddie James             break;
20890d49581SEddie James         }
20990d49581SEddie James     }
21090d49581SEddie James 
21190d49581SEddie James     if (needsResizeCall)
21290d49581SEddie James     {
21390d49581SEddie James         rc = ioctl(fd, VIDIOC_STREAMOFF, &type);
21490d49581SEddie James         if (rc)
21590d49581SEddie James         {
21690d49581SEddie James             log<level::ERR>("Failed to stop streaming",
21790d49581SEddie James                             entry("ERROR=%s", strerror(errno)));
21890d49581SEddie James             elog<ReadFailure>(
21990d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
22090d49581SEddie James                     CALLOUT_ERRNO(errno),
22190d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
22290d49581SEddie James                     CALLOUT_DEVICE_PATH(path.c_str()));
22390d49581SEddie James         }
22490d49581SEddie James     }
22590d49581SEddie James 
22690d49581SEddie James     for (i = 0; i < buffers.size(); ++i)
22790d49581SEddie James     {
22890d49581SEddie James         if (buffers[i].data)
22990d49581SEddie James         {
23090d49581SEddie James             munmap(buffers[i].data, buffers[i].size);
23190d49581SEddie James             buffers[i].data = nullptr;
23290d49581SEddie James             buffers[i].queued = false;
23390d49581SEddie James         }
23490d49581SEddie James     }
23590d49581SEddie James 
23690d49581SEddie James     if (needsResizeCall)
23790d49581SEddie James     {
23890d49581SEddie James         v4l2_dv_timings timings;
23990d49581SEddie James 
24090d49581SEddie James         memset(&req, 0, sizeof(v4l2_requestbuffers));
24190d49581SEddie James         req.count = 0;
24290d49581SEddie James         req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
24390d49581SEddie James         req.memory = V4L2_MEMORY_MMAP;
24490d49581SEddie James         rc = ioctl(fd, VIDIOC_REQBUFS, &req);
24590d49581SEddie James         if (rc < 0)
24690d49581SEddie James         {
24790d49581SEddie James             log<level::ERR>("Failed to zero streaming buffers",
24890d49581SEddie James                             entry("ERROR=%s", strerror(errno)));
24990d49581SEddie James             elog<ReadFailure>(
25090d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
25190d49581SEddie James                     CALLOUT_ERRNO(errno),
25290d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
25390d49581SEddie James                     CALLOUT_DEVICE_PATH(path.c_str()));
25490d49581SEddie James         }
25590d49581SEddie James 
25690d49581SEddie James         memset(&timings, 0, sizeof(v4l2_dv_timings));
25790d49581SEddie James         rc = ioctl(fd, VIDIOC_QUERY_DV_TIMINGS, &timings);
25890d49581SEddie James         if (rc < 0)
25990d49581SEddie James         {
26090d49581SEddie James             log<level::ERR>("Failed to query timings",
26190d49581SEddie James                             entry("ERROR=%s", strerror(errno)));
26290d49581SEddie James             elog<ReadFailure>(
26390d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
26490d49581SEddie James                     CALLOUT_ERRNO(errno),
26590d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
26690d49581SEddie James                     CALLOUT_DEVICE_PATH(path.c_str()));
26790d49581SEddie James         }
26890d49581SEddie James 
26990d49581SEddie James         rc = ioctl(fd, VIDIOC_S_DV_TIMINGS, &timings);
27090d49581SEddie James         if (rc < 0)
27190d49581SEddie James         {
27290d49581SEddie James             log<level::ERR>("Failed to set timings",
27390d49581SEddie James                             entry("ERROR=%s", strerror(errno)));
27490d49581SEddie James             elog<ReadFailure>(
27590d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
27690d49581SEddie James                     CALLOUT_ERRNO(errno),
27790d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
27890d49581SEddie James                     CALLOUT_DEVICE_PATH(path.c_str()));
27990d49581SEddie James         }
28090d49581SEddie James 
28190d49581SEddie James         buffers.clear();
28290d49581SEddie James     }
28390d49581SEddie James 
28490d49581SEddie James     memset(&req, 0, sizeof(v4l2_requestbuffers));
28590d49581SEddie James     req.count = 3;
28690d49581SEddie James     req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
28790d49581SEddie James     req.memory = V4L2_MEMORY_MMAP;
28890d49581SEddie James     rc = ioctl(fd, VIDIOC_REQBUFS, &req);
28990d49581SEddie James     if (rc < 0 || req.count < 2)
29090d49581SEddie James     {
29190d49581SEddie James         log<level::ERR>("Failed to request streaming buffers",
29290d49581SEddie James                         entry("ERROR=%s", strerror(errno)));
29390d49581SEddie James         elog<ReadFailure>(
29490d49581SEddie James             xyz::openbmc_project::Common::Device::ReadFailure::CALLOUT_ERRNO(
29590d49581SEddie James                 errno),
29690d49581SEddie James             xyz::openbmc_project::Common::Device::ReadFailure::
29790d49581SEddie James                 CALLOUT_DEVICE_PATH(path.c_str()));
29890d49581SEddie James     }
29990d49581SEddie James 
30090d49581SEddie James     buffers.resize(req.count);
30190d49581SEddie James 
30290d49581SEddie James     for (i = 0; i < buffers.size(); ++i)
30390d49581SEddie James     {
30490d49581SEddie James         v4l2_buffer buf;
30590d49581SEddie James 
30690d49581SEddie James         memset(&buf, 0, sizeof(v4l2_buffer));
30790d49581SEddie James         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
30890d49581SEddie James         buf.memory = V4L2_MEMORY_MMAP;
30990d49581SEddie James         buf.index = i;
31090d49581SEddie James 
31190d49581SEddie James         rc = ioctl(fd, VIDIOC_QUERYBUF, &buf);
31290d49581SEddie James         if (rc < 0)
31390d49581SEddie James         {
31490d49581SEddie James             log<level::ERR>("Failed to query buffer",
31590d49581SEddie James                             entry("ERROR=%s", strerror(errno)));
31690d49581SEddie James             elog<ReadFailure>(
31790d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
31890d49581SEddie James                     CALLOUT_ERRNO(errno),
31990d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
32090d49581SEddie James                     CALLOUT_DEVICE_PATH(path.c_str()));
32190d49581SEddie James         }
32290d49581SEddie James 
32390d49581SEddie James         buffers[i].data = mmap(NULL, buf.length, PROT_READ | PROT_WRITE,
32490d49581SEddie James                                MAP_SHARED, fd, buf.m.offset);
32590d49581SEddie James         if (buffers[i].data == MAP_FAILED)
32690d49581SEddie James         {
32790d49581SEddie James             log<level::ERR>("Failed to mmap buffer",
32890d49581SEddie James                             entry("ERROR=%s", strerror(errno)));
32990d49581SEddie James             elog<ReadFailure>(
33090d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
33190d49581SEddie James                     CALLOUT_ERRNO(errno),
33290d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
33390d49581SEddie James                     CALLOUT_DEVICE_PATH(path.c_str()));
33490d49581SEddie James         }
33590d49581SEddie James 
33690d49581SEddie James         buffers[i].size = buf.length;
33790d49581SEddie James 
33890d49581SEddie James         rc = ioctl(fd, VIDIOC_QBUF, &buf);
33990d49581SEddie James         if (rc < 0)
34090d49581SEddie James         {
34190d49581SEddie James             log<level::ERR>("Failed to queue buffer",
34290d49581SEddie James                             entry("ERROR=%s", strerror(errno)));
34390d49581SEddie James             elog<ReadFailure>(
34490d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
34590d49581SEddie James                     CALLOUT_ERRNO(errno),
34690d49581SEddie James                 xyz::openbmc_project::Common::Device::ReadFailure::
34790d49581SEddie James                     CALLOUT_DEVICE_PATH(path.c_str()));
34890d49581SEddie James         }
34990d49581SEddie James 
35090d49581SEddie James         buffers[i].queued = true;
35190d49581SEddie James     }
35290d49581SEddie James 
35390d49581SEddie James     rc = ioctl(fd, VIDIOC_STREAMON, &type);
35490d49581SEddie James     if (rc)
35590d49581SEddie James     {
35690d49581SEddie James         log<level::ERR>("Failed to start streaming",
35790d49581SEddie James                         entry("ERROR=%s", strerror(errno)));
35890d49581SEddie James         elog<ReadFailure>(
35990d49581SEddie James             xyz::openbmc_project::Common::Device::ReadFailure::CALLOUT_ERRNO(
36090d49581SEddie James                 errno),
36190d49581SEddie James             xyz::openbmc_project::Common::Device::ReadFailure::
36290d49581SEddie James                 CALLOUT_DEVICE_PATH(path.c_str()));
36390d49581SEddie James     }
36490d49581SEddie James }
36590d49581SEddie James 
36690d49581SEddie James void Video::start()
36790d49581SEddie James {
36890d49581SEddie James     int rc;
36990d49581SEddie James     size_t oldHeight = height;
37090d49581SEddie James     size_t oldWidth = width;
37190d49581SEddie James     v4l2_capability cap;
37290d49581SEddie James     v4l2_format fmt;
37390d49581SEddie James     v4l2_streamparm sparm;
37490d49581SEddie James 
37590d49581SEddie James     if (fd >= 0)
37690d49581SEddie James     {
37790d49581SEddie James         return;
37890d49581SEddie James     }
37990d49581SEddie James 
38090d49581SEddie James     fd = open(path.c_str(), O_RDWR);
38190d49581SEddie James     if (fd < 0)
38290d49581SEddie James     {
383*7dfac9ffSJae Hyun Yoo         input.sendWakeupPacket();
38490d49581SEddie James 
38590d49581SEddie James         fd = open(path.c_str(), O_RDWR);
38690d49581SEddie James         if (fd < 0)
38790d49581SEddie James         {
38890d49581SEddie James             log<level::ERR>("Failed to open video device",
38990d49581SEddie James                             entry("PATH=%s", path.c_str()),
39090d49581SEddie James                             entry("ERROR=%s", strerror(errno)));
39190d49581SEddie James             elog<Open>(
39290d49581SEddie James                 xyz::openbmc_project::Common::File::Open::ERRNO(errno),
39390d49581SEddie James                 xyz::openbmc_project::Common::File::Open::PATH(path.c_str()));
39490d49581SEddie James         }
39590d49581SEddie James     }
39690d49581SEddie James 
39790d49581SEddie James     memset(&cap, 0, sizeof(v4l2_capability));
39890d49581SEddie James     rc = ioctl(fd, VIDIOC_QUERYCAP, &cap);
39990d49581SEddie James     if (rc < 0)
40090d49581SEddie James     {
40190d49581SEddie James         log<level::ERR>("Failed to query video device capabilities",
40290d49581SEddie James                         entry("ERROR=%s", strerror(errno)));
40390d49581SEddie James         elog<ReadFailure>(
40490d49581SEddie James             xyz::openbmc_project::Common::Device::ReadFailure::CALLOUT_ERRNO(
40590d49581SEddie James                 errno),
40690d49581SEddie James             xyz::openbmc_project::Common::Device::ReadFailure::
40790d49581SEddie James                 CALLOUT_DEVICE_PATH(path.c_str()));
40890d49581SEddie James     }
40990d49581SEddie James 
41090d49581SEddie James     if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) ||
41190d49581SEddie James         !(cap.capabilities & V4L2_CAP_STREAMING))
41290d49581SEddie James     {
41390d49581SEddie James         log<level::ERR>("Video device doesn't support this application");
41490d49581SEddie James         elog<Open>(
41590d49581SEddie James             xyz::openbmc_project::Common::File::Open::ERRNO(errno),
41690d49581SEddie James             xyz::openbmc_project::Common::File::Open::PATH(path.c_str()));
41790d49581SEddie James     }
41890d49581SEddie James 
41990d49581SEddie James     memset(&fmt, 0, sizeof(v4l2_format));
42090d49581SEddie James     fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
42190d49581SEddie James     rc = ioctl(fd, VIDIOC_G_FMT, &fmt);
42290d49581SEddie James     if (rc < 0)
42390d49581SEddie James     {
42490d49581SEddie James         log<level::ERR>("Failed to query video device format",
42590d49581SEddie James                         entry("ERROR=%s", strerror(errno)));
42690d49581SEddie James         elog<ReadFailure>(
42790d49581SEddie James             xyz::openbmc_project::Common::Device::ReadFailure::CALLOUT_ERRNO(
42890d49581SEddie James                 errno),
42990d49581SEddie James             xyz::openbmc_project::Common::Device::ReadFailure::
43090d49581SEddie James                 CALLOUT_DEVICE_PATH(path.c_str()));
43190d49581SEddie James     }
43290d49581SEddie James 
43390d49581SEddie James     memset(&sparm, 0, sizeof(v4l2_streamparm));
43490d49581SEddie James     sparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
43590d49581SEddie James     sparm.parm.capture.timeperframe.numerator = 1;
43690d49581SEddie James     sparm.parm.capture.timeperframe.denominator = frameRate;
43790d49581SEddie James     rc = ioctl(fd, VIDIOC_S_PARM, &sparm);
43890d49581SEddie James     if (rc < 0)
43990d49581SEddie James     {
44090d49581SEddie James         log<level::WARNING>("Failed to set video device frame rate",
44190d49581SEddie James                             entry("ERROR=%s", strerror(errno)));
44290d49581SEddie James     }
44390d49581SEddie James 
44490d49581SEddie James     height = fmt.fmt.pix.height;
44590d49581SEddie James     width = fmt.fmt.pix.width;
44690d49581SEddie James 
44790d49581SEddie James     resize();
44890d49581SEddie James 
44990d49581SEddie James     if (oldHeight != height || oldWidth != width)
45090d49581SEddie James     {
45190d49581SEddie James         resizeAfterOpen = true;
45290d49581SEddie James     }
45390d49581SEddie James }
45490d49581SEddie James 
45590d49581SEddie James void Video::stop()
45690d49581SEddie James {
45790d49581SEddie James     int rc;
45890d49581SEddie James     unsigned int i;
45990d49581SEddie James     v4l2_buf_type type(V4L2_BUF_TYPE_VIDEO_CAPTURE);
46090d49581SEddie James 
46190d49581SEddie James     if (fd < 0)
46290d49581SEddie James     {
46390d49581SEddie James         return;
46490d49581SEddie James     }
46590d49581SEddie James 
46690d49581SEddie James     lastFrameIndex = -1;
46790d49581SEddie James 
46890d49581SEddie James     rc = ioctl(fd, VIDIOC_STREAMOFF, &type);
46990d49581SEddie James     if (rc)
47090d49581SEddie James     {
47190d49581SEddie James         log<level::ERR>("Failed to stop streaming",
47290d49581SEddie James                         entry("ERROR=%s", strerror(errno)));
47390d49581SEddie James     }
47490d49581SEddie James 
47590d49581SEddie James     for (i = 0; i < buffers.size(); ++i)
47690d49581SEddie James     {
47790d49581SEddie James         if (buffers[i].data)
47890d49581SEddie James         {
47990d49581SEddie James             munmap(buffers[i].data, buffers[i].size);
48090d49581SEddie James             buffers[i].data = nullptr;
48190d49581SEddie James             buffers[i].queued = false;
48290d49581SEddie James         }
48390d49581SEddie James     }
48490d49581SEddie James 
48590d49581SEddie James     close(fd);
48690d49581SEddie James     fd = -1;
48721b177e0SEddie James }
48821b177e0SEddie James 
48921b177e0SEddie James } // namespace ikvm
490