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 33a4f63b38SJammy Huang Video::Video(const std::string& p, Input& input, int fr, int sub) : 3423135dd9SEddie James resizeAfterOpen(false), timingsError(false), fd(-1), frameRate(fr), 35*f79f6f54SGeorge Liu lastFrameIndex(-1), height(600), width(800), subSampling(sub), input(input), 36*f79f6f54SGeorge Liu path(p) 37*f79f6f54SGeorge Liu {} 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 { 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 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 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; 449*f79f6f54SGeorge Liu ctrl.value = subSampling ? V4L2_JPEG_CHROMA_SUBSAMPLING_420 450*f79f6f54SGeorge 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; 46090d49581SEddie James 46190d49581SEddie James resize(); 46290d49581SEddie James 46390d49581SEddie James if (oldHeight != height || oldWidth != width) 46490d49581SEddie James { 46590d49581SEddie James resizeAfterOpen = true; 46690d49581SEddie James } 46790d49581SEddie James } 46890d49581SEddie James 46990d49581SEddie James void Video::stop() 47090d49581SEddie James { 47190d49581SEddie James int rc; 47290d49581SEddie James unsigned int i; 47390d49581SEddie James v4l2_buf_type type(V4L2_BUF_TYPE_VIDEO_CAPTURE); 47490d49581SEddie James 47590d49581SEddie James if (fd < 0) 47690d49581SEddie James { 47790d49581SEddie James return; 47890d49581SEddie James } 47990d49581SEddie James 48090d49581SEddie James lastFrameIndex = -1; 48190d49581SEddie James 48290d49581SEddie James rc = ioctl(fd, VIDIOC_STREAMOFF, &type); 48390d49581SEddie James if (rc) 48490d49581SEddie James { 48590d49581SEddie James log<level::ERR>("Failed to stop streaming", 48690d49581SEddie James entry("ERROR=%s", strerror(errno))); 48790d49581SEddie James } 48890d49581SEddie James 48990d49581SEddie James for (i = 0; i < buffers.size(); ++i) 49090d49581SEddie James { 49190d49581SEddie James if (buffers[i].data) 49290d49581SEddie James { 49390d49581SEddie James munmap(buffers[i].data, buffers[i].size); 49490d49581SEddie James buffers[i].data = nullptr; 49590d49581SEddie James buffers[i].queued = false; 49690d49581SEddie James } 49790d49581SEddie James } 49890d49581SEddie James 49990d49581SEddie James close(fd); 50090d49581SEddie James fd = -1; 50121b177e0SEddie James } 50221b177e0SEddie James 50321b177e0SEddie James } // namespace ikvm 504