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
Video(const std::string & p,Input & input,int fr,int sub)33a4f63b38SJammy Huang Video::Video(const std::string& p, Input& input, int fr, int sub) :
3423135dd9SEddie James resizeAfterOpen(false), timingsError(false), fd(-1), frameRate(fr),
35f79f6f54SGeorge Liu lastFrameIndex(-1), height(600), width(800), subSampling(sub), input(input),
36*8e909b75SCharles Kearney path(p), pixelformat(V4L2_PIX_FMT_JPEG)
37f79f6f54SGeorge Liu {}
3821b177e0SEddie James
~Video()3921b177e0SEddie James Video::~Video()
4021b177e0SEddie James {
4190d49581SEddie James stop();
4290d49581SEddie James }
4390d49581SEddie James
getData()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
getFrame()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
needsResize()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 {
15623135dd9SEddie James if (!timingsError)
15723135dd9SEddie James {
15890d49581SEddie James log<level::ERR>("Failed to query timings",
15990d49581SEddie James entry("ERROR=%s", strerror(errno)));
16023135dd9SEddie James timingsError = true;
16123135dd9SEddie James }
16223135dd9SEddie James
163f6ed0e75SJae Hyun Yoo restart();
16490d49581SEddie James return false;
16590d49581SEddie James }
1667a89cd23SJae Hyun Yoo else
16723135dd9SEddie James {
16823135dd9SEddie James timingsError = false;
16923135dd9SEddie James }
17090d49581SEddie James
17190d49581SEddie James if (timings.bt.width != width || timings.bt.height != height)
17290d49581SEddie James {
17390d49581SEddie James width = timings.bt.width;
17490d49581SEddie James height = timings.bt.height;
17590d49581SEddie James
17690d49581SEddie James if (!width || !height)
17790d49581SEddie James {
17890d49581SEddie James log<level::ERR>("Failed to get new resolution",
17990d49581SEddie James entry("WIDTH=%d", width),
18090d49581SEddie James entry("HEIGHT=%d", height));
18190d49581SEddie James elog<Open>(
18290d49581SEddie James xyz::openbmc_project::Common::File::Open::ERRNO(-EPROTO),
18390d49581SEddie James xyz::openbmc_project::Common::File::Open::PATH(path.c_str()));
18490d49581SEddie James }
18590d49581SEddie James
18690d49581SEddie James lastFrameIndex = -1;
18790d49581SEddie James return true;
18890d49581SEddie James }
18990d49581SEddie James
19090d49581SEddie James return false;
19190d49581SEddie James }
19290d49581SEddie James
resize()19390d49581SEddie James void Video::resize()
19490d49581SEddie James {
19590d49581SEddie James int rc;
19690d49581SEddie James unsigned int i;
19790d49581SEddie James bool needsResizeCall(false);
19890d49581SEddie James v4l2_buf_type type(V4L2_BUF_TYPE_VIDEO_CAPTURE);
19990d49581SEddie James v4l2_requestbuffers req;
20090d49581SEddie James
20190d49581SEddie James if (fd < 0)
20290d49581SEddie James {
20390d49581SEddie James return;
20490d49581SEddie James }
20590d49581SEddie James
20690d49581SEddie James if (resizeAfterOpen)
20790d49581SEddie James {
20890d49581SEddie James resizeAfterOpen = false;
20990d49581SEddie James return;
21090d49581SEddie James }
21190d49581SEddie James
21290d49581SEddie James for (i = 0; i < buffers.size(); ++i)
21390d49581SEddie James {
21490d49581SEddie James if (buffers[i].data)
21590d49581SEddie James {
21690d49581SEddie James needsResizeCall = true;
21790d49581SEddie James break;
21890d49581SEddie James }
21990d49581SEddie James }
22090d49581SEddie James
22190d49581SEddie James if (needsResizeCall)
22290d49581SEddie James {
22390d49581SEddie James rc = ioctl(fd, VIDIOC_STREAMOFF, &type);
22490d49581SEddie James if (rc)
22590d49581SEddie James {
22690d49581SEddie James log<level::ERR>("Failed to stop streaming",
22790d49581SEddie James entry("ERROR=%s", strerror(errno)));
22890d49581SEddie James elog<ReadFailure>(
22990d49581SEddie James xyz::openbmc_project::Common::Device::ReadFailure::
23090d49581SEddie James CALLOUT_ERRNO(errno),
23190d49581SEddie James xyz::openbmc_project::Common::Device::ReadFailure::
23290d49581SEddie James CALLOUT_DEVICE_PATH(path.c_str()));
23390d49581SEddie James }
23490d49581SEddie James }
23590d49581SEddie James
23690d49581SEddie James for (i = 0; i < buffers.size(); ++i)
23790d49581SEddie James {
23890d49581SEddie James if (buffers[i].data)
23990d49581SEddie James {
24090d49581SEddie James munmap(buffers[i].data, buffers[i].size);
24190d49581SEddie James buffers[i].data = nullptr;
24290d49581SEddie James buffers[i].queued = false;
24390d49581SEddie James }
24490d49581SEddie James }
24590d49581SEddie James
24690d49581SEddie James if (needsResizeCall)
24790d49581SEddie James {
24890d49581SEddie James v4l2_dv_timings timings;
24990d49581SEddie James
25090d49581SEddie James memset(&req, 0, sizeof(v4l2_requestbuffers));
25190d49581SEddie James req.count = 0;
25290d49581SEddie James req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
25390d49581SEddie James req.memory = V4L2_MEMORY_MMAP;
25490d49581SEddie James rc = ioctl(fd, VIDIOC_REQBUFS, &req);
25590d49581SEddie James if (rc < 0)
25690d49581SEddie James {
25790d49581SEddie James log<level::ERR>("Failed to zero streaming buffers",
25890d49581SEddie James entry("ERROR=%s", strerror(errno)));
25990d49581SEddie James elog<ReadFailure>(
26090d49581SEddie James xyz::openbmc_project::Common::Device::ReadFailure::
26190d49581SEddie James CALLOUT_ERRNO(errno),
26290d49581SEddie James xyz::openbmc_project::Common::Device::ReadFailure::
26390d49581SEddie James CALLOUT_DEVICE_PATH(path.c_str()));
26490d49581SEddie James }
26590d49581SEddie James
26690d49581SEddie James memset(&timings, 0, sizeof(v4l2_dv_timings));
26790d49581SEddie James rc = ioctl(fd, VIDIOC_QUERY_DV_TIMINGS, &timings);
26890d49581SEddie James if (rc < 0)
26990d49581SEddie James {
270ee09e303SJammy Huang log<level::ERR>("Failed to query timings, restart",
27190d49581SEddie James entry("ERROR=%s", strerror(errno)));
272ee09e303SJammy Huang restart();
273ee09e303SJammy Huang return;
27490d49581SEddie James }
27590d49581SEddie James
27690d49581SEddie James rc = ioctl(fd, VIDIOC_S_DV_TIMINGS, &timings);
27790d49581SEddie James if (rc < 0)
27890d49581SEddie James {
27990d49581SEddie James log<level::ERR>("Failed to set timings",
28090d49581SEddie James entry("ERROR=%s", strerror(errno)));
28190d49581SEddie James elog<ReadFailure>(
28290d49581SEddie James xyz::openbmc_project::Common::Device::ReadFailure::
28390d49581SEddie James CALLOUT_ERRNO(errno),
28490d49581SEddie James xyz::openbmc_project::Common::Device::ReadFailure::
28590d49581SEddie James CALLOUT_DEVICE_PATH(path.c_str()));
28690d49581SEddie James }
28790d49581SEddie James
28890d49581SEddie James buffers.clear();
28990d49581SEddie James }
29090d49581SEddie James
29190d49581SEddie James memset(&req, 0, sizeof(v4l2_requestbuffers));
29290d49581SEddie James req.count = 3;
29390d49581SEddie James req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
29490d49581SEddie James req.memory = V4L2_MEMORY_MMAP;
29590d49581SEddie James rc = ioctl(fd, VIDIOC_REQBUFS, &req);
29690d49581SEddie James if (rc < 0 || req.count < 2)
29790d49581SEddie James {
29890d49581SEddie James log<level::ERR>("Failed to request streaming buffers",
29990d49581SEddie James entry("ERROR=%s", strerror(errno)));
30090d49581SEddie James elog<ReadFailure>(
30190d49581SEddie James xyz::openbmc_project::Common::Device::ReadFailure::CALLOUT_ERRNO(
30290d49581SEddie James errno),
30390d49581SEddie James xyz::openbmc_project::Common::Device::ReadFailure::
30490d49581SEddie James CALLOUT_DEVICE_PATH(path.c_str()));
30590d49581SEddie James }
30690d49581SEddie James
30790d49581SEddie James buffers.resize(req.count);
30890d49581SEddie James
30990d49581SEddie James for (i = 0; i < buffers.size(); ++i)
31090d49581SEddie James {
31190d49581SEddie James v4l2_buffer buf;
31290d49581SEddie James
31390d49581SEddie James memset(&buf, 0, sizeof(v4l2_buffer));
31490d49581SEddie James buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
31590d49581SEddie James buf.memory = V4L2_MEMORY_MMAP;
31690d49581SEddie James buf.index = i;
31790d49581SEddie James
31890d49581SEddie James rc = ioctl(fd, VIDIOC_QUERYBUF, &buf);
31990d49581SEddie James if (rc < 0)
32090d49581SEddie James {
32190d49581SEddie James log<level::ERR>("Failed to query buffer",
32290d49581SEddie James entry("ERROR=%s", strerror(errno)));
32390d49581SEddie James elog<ReadFailure>(
32490d49581SEddie James xyz::openbmc_project::Common::Device::ReadFailure::
32590d49581SEddie James CALLOUT_ERRNO(errno),
32690d49581SEddie James xyz::openbmc_project::Common::Device::ReadFailure::
32790d49581SEddie James CALLOUT_DEVICE_PATH(path.c_str()));
32890d49581SEddie James }
32990d49581SEddie James
33090d49581SEddie James buffers[i].data = mmap(NULL, buf.length, PROT_READ | PROT_WRITE,
33190d49581SEddie James MAP_SHARED, fd, buf.m.offset);
33290d49581SEddie James if (buffers[i].data == MAP_FAILED)
33390d49581SEddie James {
33490d49581SEddie James log<level::ERR>("Failed to mmap buffer",
33590d49581SEddie James entry("ERROR=%s", strerror(errno)));
33690d49581SEddie James elog<ReadFailure>(
33790d49581SEddie James xyz::openbmc_project::Common::Device::ReadFailure::
33890d49581SEddie James CALLOUT_ERRNO(errno),
33990d49581SEddie James xyz::openbmc_project::Common::Device::ReadFailure::
34090d49581SEddie James CALLOUT_DEVICE_PATH(path.c_str()));
34190d49581SEddie James }
34290d49581SEddie James
34390d49581SEddie James buffers[i].size = buf.length;
34490d49581SEddie James
34590d49581SEddie James rc = ioctl(fd, VIDIOC_QBUF, &buf);
34690d49581SEddie James if (rc < 0)
34790d49581SEddie James {
34890d49581SEddie James log<level::ERR>("Failed to queue buffer",
34990d49581SEddie James entry("ERROR=%s", strerror(errno)));
35090d49581SEddie James elog<ReadFailure>(
35190d49581SEddie James xyz::openbmc_project::Common::Device::ReadFailure::
35290d49581SEddie James CALLOUT_ERRNO(errno),
35390d49581SEddie James xyz::openbmc_project::Common::Device::ReadFailure::
35490d49581SEddie James CALLOUT_DEVICE_PATH(path.c_str()));
35590d49581SEddie James }
35690d49581SEddie James
35790d49581SEddie James buffers[i].queued = true;
35890d49581SEddie James }
35990d49581SEddie James
36090d49581SEddie James rc = ioctl(fd, VIDIOC_STREAMON, &type);
36190d49581SEddie James if (rc)
36290d49581SEddie James {
36390d49581SEddie James log<level::ERR>("Failed to start streaming",
36490d49581SEddie James entry("ERROR=%s", strerror(errno)));
36590d49581SEddie James elog<ReadFailure>(
36690d49581SEddie James xyz::openbmc_project::Common::Device::ReadFailure::CALLOUT_ERRNO(
36790d49581SEddie James errno),
36890d49581SEddie James xyz::openbmc_project::Common::Device::ReadFailure::
36990d49581SEddie James CALLOUT_DEVICE_PATH(path.c_str()));
37090d49581SEddie James }
37190d49581SEddie James }
37290d49581SEddie James
start()37390d49581SEddie James void Video::start()
37490d49581SEddie James {
37590d49581SEddie James int rc;
37690d49581SEddie James size_t oldHeight = height;
37790d49581SEddie James size_t oldWidth = width;
37890d49581SEddie James v4l2_capability cap;
37990d49581SEddie James v4l2_format fmt;
38090d49581SEddie James v4l2_streamparm sparm;
381a4f63b38SJammy Huang v4l2_control ctrl;
38290d49581SEddie James
38390d49581SEddie James if (fd >= 0)
38490d49581SEddie James {
38590d49581SEddie James return;
38690d49581SEddie James }
38790d49581SEddie James
3887dfac9ffSJae Hyun Yoo input.sendWakeupPacket();
38990d49581SEddie James
39090d49581SEddie James fd = open(path.c_str(), O_RDWR);
39190d49581SEddie James if (fd < 0)
39290d49581SEddie James {
39390d49581SEddie James log<level::ERR>("Failed to open video device",
39490d49581SEddie James entry("PATH=%s", path.c_str()),
39590d49581SEddie James entry("ERROR=%s", strerror(errno)));
39690d49581SEddie James elog<Open>(
39790d49581SEddie James xyz::openbmc_project::Common::File::Open::ERRNO(errno),
39890d49581SEddie James xyz::openbmc_project::Common::File::Open::PATH(path.c_str()));
39990d49581SEddie James }
40090d49581SEddie James
40190d49581SEddie James memset(&cap, 0, sizeof(v4l2_capability));
40290d49581SEddie James rc = ioctl(fd, VIDIOC_QUERYCAP, &cap);
40390d49581SEddie James if (rc < 0)
40490d49581SEddie James {
40590d49581SEddie James log<level::ERR>("Failed to query video device capabilities",
40690d49581SEddie James entry("ERROR=%s", strerror(errno)));
40790d49581SEddie James elog<ReadFailure>(
40890d49581SEddie James xyz::openbmc_project::Common::Device::ReadFailure::CALLOUT_ERRNO(
40990d49581SEddie James errno),
41090d49581SEddie James xyz::openbmc_project::Common::Device::ReadFailure::
41190d49581SEddie James CALLOUT_DEVICE_PATH(path.c_str()));
41290d49581SEddie James }
41390d49581SEddie James
41490d49581SEddie James if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) ||
41590d49581SEddie James !(cap.capabilities & V4L2_CAP_STREAMING))
41690d49581SEddie James {
41790d49581SEddie James log<level::ERR>("Video device doesn't support this application");
41890d49581SEddie James elog<Open>(
41990d49581SEddie James xyz::openbmc_project::Common::File::Open::ERRNO(errno),
42090d49581SEddie James xyz::openbmc_project::Common::File::Open::PATH(path.c_str()));
42190d49581SEddie James }
42290d49581SEddie James
42390d49581SEddie James memset(&fmt, 0, sizeof(v4l2_format));
42490d49581SEddie James fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
42590d49581SEddie James rc = ioctl(fd, VIDIOC_G_FMT, &fmt);
42690d49581SEddie James if (rc < 0)
42790d49581SEddie James {
42890d49581SEddie James log<level::ERR>("Failed to query video device format",
42990d49581SEddie James entry("ERROR=%s", strerror(errno)));
43090d49581SEddie James elog<ReadFailure>(
43190d49581SEddie James xyz::openbmc_project::Common::Device::ReadFailure::CALLOUT_ERRNO(
43290d49581SEddie James errno),
43390d49581SEddie James xyz::openbmc_project::Common::Device::ReadFailure::
43490d49581SEddie James CALLOUT_DEVICE_PATH(path.c_str()));
43590d49581SEddie James }
43690d49581SEddie James
43790d49581SEddie James memset(&sparm, 0, sizeof(v4l2_streamparm));
43890d49581SEddie James sparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
43990d49581SEddie James sparm.parm.capture.timeperframe.numerator = 1;
44090d49581SEddie James sparm.parm.capture.timeperframe.denominator = frameRate;
44190d49581SEddie James rc = ioctl(fd, VIDIOC_S_PARM, &sparm);
44290d49581SEddie James if (rc < 0)
44390d49581SEddie James {
44490d49581SEddie James log<level::WARNING>("Failed to set video device frame rate",
44590d49581SEddie James entry("ERROR=%s", strerror(errno)));
44690d49581SEddie James }
44790d49581SEddie James
448a4f63b38SJammy Huang ctrl.id = V4L2_CID_JPEG_CHROMA_SUBSAMPLING;
449f79f6f54SGeorge Liu ctrl.value = subSampling ? V4L2_JPEG_CHROMA_SUBSAMPLING_420
450f79f6f54SGeorge Liu : V4L2_JPEG_CHROMA_SUBSAMPLING_444;
451a4f63b38SJammy Huang rc = ioctl(fd, VIDIOC_S_CTRL, &ctrl);
452a4f63b38SJammy Huang if (rc < 0)
453a4f63b38SJammy Huang {
454a4f63b38SJammy Huang log<level::WARNING>("Failed to set video jpeg subsampling",
455a4f63b38SJammy Huang entry("ERROR=%s", strerror(errno)));
456a4f63b38SJammy Huang }
457a4f63b38SJammy Huang
45890d49581SEddie James height = fmt.fmt.pix.height;
45990d49581SEddie James width = fmt.fmt.pix.width;
460*8e909b75SCharles Kearney pixelformat = fmt.fmt.pix.pixelformat;
461*8e909b75SCharles Kearney
462*8e909b75SCharles Kearney if (pixelformat != V4L2_PIX_FMT_RGB24 && pixelformat != V4L2_PIX_FMT_JPEG)
463*8e909b75SCharles Kearney {
464*8e909b75SCharles Kearney log<level::ERR>("Pixel Format not supported",
465*8e909b75SCharles Kearney entry("PIXELFORMAT=%d", pixelformat));
466*8e909b75SCharles Kearney }
46790d49581SEddie James
46890d49581SEddie James resize();
46990d49581SEddie James
47090d49581SEddie James if (oldHeight != height || oldWidth != width)
47190d49581SEddie James {
47290d49581SEddie James resizeAfterOpen = true;
47390d49581SEddie James }
47490d49581SEddie James }
47590d49581SEddie James
stop()47690d49581SEddie James void Video::stop()
47790d49581SEddie James {
47890d49581SEddie James int rc;
47990d49581SEddie James unsigned int i;
48090d49581SEddie James v4l2_buf_type type(V4L2_BUF_TYPE_VIDEO_CAPTURE);
48190d49581SEddie James
48290d49581SEddie James if (fd < 0)
48390d49581SEddie James {
48490d49581SEddie James return;
48590d49581SEddie James }
48690d49581SEddie James
48790d49581SEddie James lastFrameIndex = -1;
48890d49581SEddie James
48990d49581SEddie James rc = ioctl(fd, VIDIOC_STREAMOFF, &type);
49090d49581SEddie James if (rc)
49190d49581SEddie James {
49290d49581SEddie James log<level::ERR>("Failed to stop streaming",
49390d49581SEddie James entry("ERROR=%s", strerror(errno)));
49490d49581SEddie James }
49590d49581SEddie James
49690d49581SEddie James for (i = 0; i < buffers.size(); ++i)
49790d49581SEddie James {
49890d49581SEddie James if (buffers[i].data)
49990d49581SEddie James {
50090d49581SEddie James munmap(buffers[i].data, buffers[i].size);
50190d49581SEddie James buffers[i].data = nullptr;
50290d49581SEddie James buffers[i].queued = false;
50390d49581SEddie James }
50490d49581SEddie James }
50590d49581SEddie James
50690d49581SEddie James close(fd);
50790d49581SEddie James fd = -1;
50821b177e0SEddie James }
50921b177e0SEddie James
51021b177e0SEddie James } // namespace ikvm
511