// Copyright (c) 2012-2017 VideoStitch SAS // Copyright (c) 2018 stitchEm #include "magewellReader.hpp" #include "magewell_helpers.hpp" #include "libvideostitch/logging.hpp" #include "libvideostitch/parse.hpp" namespace VideoStitch { namespace Input { // ------------------------ Lifecycle -------------------------------- MagewellReader::MagewellReader(readerid_t id, const int64_t width, const int64_t height, HCHANNEL channel, int64_t frameSize, FrameRate fps, PixelFormat pixelFormat, int bytesPerPixel, const std::string& name) : Reader(id), VideoReader(width, height, frameSize, pixelFormat, Host, fps, 0, NO_LAST_FRAME, false /* not a procedural reader */, nullptr), channel(channel), name(name), bytesPerPixel(bytesPerPixel) { notifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); captureEvent = CreateEvent(NULL, FALSE, FALSE, NULL); } MagewellReader::~MagewellReader() { MWStopVideoCapture(channel); CloseHandle(notifyEvent); CloseHandle(captureEvent); MWCloseChannel(channel); } // -------------------------- Plugin implementation ---------------------------------- MagewellReader* MagewellReader::create(readerid_t id, const Ptv::Value* config, const int64_t width, const int64_t height) { MWRefreshDevice(); std::string name; if (Parse::populateString("Magewell reader", *config, "name", name, true) != VideoStitch::Parse::PopulateResult_Ok) { Logger::get(Logger::Error) << "Magewell : camera name (\"name\") couldn't be retrieved. Please, give a name to your input. Aborting." << std::endl; return nullptr; } //------------------------ Video FrameRate frameRate; if (!config->has("frame_rate")) { Logger::get(Logger::Error) << "Magewell : frame rate (\"frame_rate\") couldn't be retrieved. Aborting." << std::endl; return nullptr; } else { const Ptv::Value* fpsConf = config->has("frame_rate"); if ((Parse::populateInt("Magewell reader", *fpsConf, "num", frameRate.num, false) != VideoStitch::Parse::PopulateResult_Ok) || (Parse::populateInt("Magewell reader", *fpsConf, "den", frameRate.den, false) != VideoStitch::Parse::PopulateResult_Ok)) { Logger::get(Logger::Error) << "Magewell : frame rate (\"frame_rate\") couldn't be retrieved. Aborting." << std::endl; return nullptr; } } std::string pixelFormatString; if (Parse::populateString("Magewell reader", *config, "pixel_format", pixelFormatString, false) != VideoStitch::Parse::PopulateResult_Ok) { Logger::get(Logger::Error) << "Magewell : pixel format (\"pixel_format\") couldn't be retrieved. Aborting." << std::endl; return nullptr; } PixelFormat pixelFormat = PixelFormat::Unknown; int bytesPerPixel = 0; if (pixelFormatString == "RGBA") { pixelFormat = PixelFormat::RGBA; bytesPerPixel = 4; } else if (pixelFormatString == "RGB") { pixelFormat = PixelFormat::RGB; bytesPerPixel = 3; } else if (pixelFormatString == "BGR") { pixelFormat = PixelFormat::BGR; bytesPerPixel = 3; } else if (pixelFormatString == "BGRU") { pixelFormat = PixelFormat::BGRU; bytesPerPixel = 4; } else if (pixelFormatString == "UYVY") { pixelFormat = PixelFormat::UYVY; bytesPerPixel = 2; } else if (pixelFormatString == "YUY2") { pixelFormat = PixelFormat::YUY2; bytesPerPixel = 2; } //------------------------------- Runtime objects MWCAP_CHANNEL_INFO videoInfo = {0}; if (MW_SUCCEEDED != MWGetChannelInfoByIndex(std::stoi(name), &videoInfo)) { Logger::get(Logger::Error) << "Magewell : Can't get channel info" << std::endl; return nullptr; } HCHANNEL channel = MWOpenChannel(videoInfo.byBoardIndex, videoInfo.byChannelIndex); if (channel == nullptr) { Logger::get(Logger::Error) << "Magewell : Open channel error" << std::endl; return nullptr; } Logger::get(Logger::Info) << "Magewell : Open channel - BoardIndex = " << (int)videoInfo.byBoardIndex << ", ChannelIndex = " << (int)videoInfo.byChannelIndex << std::endl; Logger::get(Logger::Info) << "Magewell : Product Name: " << videoInfo.szProductName << std::endl; Logger::get(Logger::Info) << "Magewell : Board SerialNo: " << videoInfo.szBoardSerialNo << std::endl; MagewellReader* reader = new MagewellReader(id, width, height, channel, width * height * bytesPerPixel, frameRate, pixelFormat, bytesPerPixel, name); if (reader->init() == true) { return reader; } else { return nullptr; } } bool MagewellReader::init() { format = VideoStitch::Magewell::xiColorFormat(getSpec().format); if (MWStartVideoCapture(channel, captureEvent)) { Logger::get(Logger::Error) << "Magewell : Open Video Capture error" << std::endl; return false; } MWGetVideoBufferInfo(channel, &videoBufferInfo); MWGetVideoFrameInfo(channel, videoBufferInfo.iNewestBufferedFullFrame, &videoFrameInfo); MWGetVideoSignalStatus(channel, &videoSignalStatus); switch (videoSignalStatus.state) { case MWCAP_VIDEO_SIGNAL_NONE: Logger::get(Logger::Info) << "Magewell : Input signal status: NONE" << std::endl; break; case MWCAP_VIDEO_SIGNAL_UNSUPPORTED: Logger::get(Logger::Info) << "Magewell : Input signal status: Unsupported" << std::endl; break; case MWCAP_VIDEO_SIGNAL_LOCKING: Logger::get(Logger::Info) << "Magewell : Input signal status: Locking" << std::endl; break; case MWCAP_VIDEO_SIGNAL_LOCKED: Logger::get(Logger::Info) << "Magewell : Input signal status: Locked" << std::endl; Logger::get(Logger::Info) << "Magewell : Input signal resolution: " << videoSignalStatus.cx << " x " << videoSignalStatus.cy << std::endl; double fps = (double)10000000LL / videoSignalStatus.dwFrameDuration; Logger::get(Logger::Info) << "Magewell : Input signal fps: " << fps << std::endl; Logger::get(Logger::Info) << "Magewell : Input signal interlaced: " << (videoSignalStatus.bInterlaced ? "true" : "false") << std::endl; Logger::get(Logger::Info) << "Magewell : Input signal colorspace: "; switch (videoSignalStatus.colorFormat) { case MWCAP_VIDEO_COLOR_FORMAT_UNKNOWN: Logger::get(Logger::Info) << "unknown"; break; case MWCAP_VIDEO_COLOR_FORMAT_RGB: Logger::get(Logger::Info) << "RGB"; break; case MWCAP_VIDEO_COLOR_FORMAT_YUV601: Logger::get(Logger::Info) << "YUV601"; break; case MWCAP_VIDEO_COLOR_FORMAT_YUV709: Logger::get(Logger::Info) << "YUV709"; break; case MWCAP_VIDEO_COLOR_FORMAT_YUV2020: Logger::get(Logger::Info) << "YUV2020"; break; case MWCAP_VIDEO_COLOR_FORMAT_YUV2020C: Logger::get(Logger::Info) << "YUV2020C"; break; } Logger::get(Logger::Info) << std::endl; break; } HNOTIFY notify = MWRegisterNotify(channel, notifyEvent, MWCAP_NOTIFY_VIDEO_FRAME_BUFFERED); if (notify == nullptr) { Logger::get(Logger::Error) << "Magewell : Register Notify error" << std::endl; return false; } return true; } // --------------------------------- Reader implementation ------------------------ ReadStatus MagewellReader::readFrame(mtime_t& date, unsigned char* video) { if (WaitForSingleObject(notifyEvent, 2000) == WAIT_TIMEOUT) { date = 0; return ReadStatus::OK(); } MWGetVideoBufferInfo(channel, &videoBufferInfo); MWGetVideoFrameInfo(channel, videoBufferInfo.iNewestBufferedFullFrame, &videoFrameInfo); MWCaptureVideoFrameToVirtualAddress( channel, videoBufferInfo.iNewestBufferedFullFrame, (LPBYTE)video, (DWORD)(VideoReader::getSpec().width * VideoReader::getSpec().height * bytesPerPixel), (DWORD)(VideoReader::getSpec().width * bytesPerPixel), false, nullptr, format, (int)VideoReader::getSpec().width, (int)getSpec().height); WaitForSingleObject(captureEvent, INFINITE); date = (mtime_t)(videoFrameInfo.allFieldStartTimes[0] / 10); // time unit is 100 ns Logger::get(Logger::Verbose) << "Magewell : Captured frame " << (int)((videoFrameInfo.allFieldStartTimes[0] * getSpec().frameRate.num) / (10000000.0 * getSpec().frameRate.den)) << std::endl; // time unit is 100 ns return ReadStatus::OK(); } Status MagewellReader::seekFrame(frameid_t) { return Status::OK(); } } // namespace Input } // namespace VideoStitch