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