This source file includes following definitions.
- getInstance
- isStarted
- closeGrabber
- initGrabber
- _GrabFrameAsync
- CopyOutput
- listDevicesTask
- listDevices
#include "cap_winrt_video.hpp"
#include <ppl.h>
#include <ppltasks.h>
#include <concrt.h>
#include <agile.h>
#include <atomic>
#include <future>
#include <vector>
using namespace ::concurrency;
using namespace ::Windows::Foundation;
using namespace ::std;
using namespace Microsoft::WRL;
using namespace Windows::Media::Devices;
using namespace Windows::Media::MediaProperties;
using namespace Windows::Media::Capture;
using namespace Windows::UI::Xaml::Media::Imaging;
using namespace Windows::Devices::Enumeration;
#include "cap_winrt/CaptureFrameGrabber.hpp"
#pragma comment(lib, "mfplat")
#pragma comment(lib, "mf")
#pragma comment(lib, "mfuuid")
#if (WINAPI_FAMILY!=WINAPI_FAMILY_PHONE_APP) && !defined(_M_ARM)
#pragma comment(lib, "Shlwapi")
#endif
#include "cap_winrt_bridge.hpp"
Video::Video() {}
Video &Video::getInstance() {
static Video v;
return v;
}
bool Video::isStarted() {
return bGrabberInited.load();
}
void Video::closeGrabber() {
m_frameGrabber = nullptr;
bGrabberInited = false;
bGrabberInitInProgress = false;
}
bool Video::initGrabber(int device, int w, int h) {
if (bGrabberInited || bGrabberInitInProgress) return false;
width = w;
height = h;
bGrabberInited = false;
bGrabberInitInProgress = true;
m_deviceID = device;
create_task(DeviceInformation::FindAllAsync(DeviceClass::VideoCapture))
.then([this](task<DeviceInformationCollection^> findTask)
{
m_devices = findTask.get();
if ((unsigned)m_deviceID >= m_devices.Get()->Size)
{
OutputDebugStringA("Video::initGrabber - no video device found\n");
return false;
}
auto devInfo = m_devices.Get()->GetAt(m_deviceID);
auto settings = ref new MediaCaptureInitializationSettings();
settings->StreamingCaptureMode = StreamingCaptureMode::Video;
settings->VideoDeviceId = devInfo->Id;
auto location = devInfo->EnclosureLocation;
bFlipImageX = true;
if (location != nullptr && location->Panel == Windows::Devices::Enumeration::Panel::Back)
{
bFlipImageX = false;
}
m_capture = ref new MediaCapture();
create_task(m_capture->InitializeAsync(settings)).then([this](){
auto props = safe_cast<VideoEncodingProperties^>(m_capture->VideoDeviceController->GetMediaStreamProperties(MediaStreamType::VideoPreview));
props->Subtype = MediaEncodingSubtypes::Rgb24; bytesPerPixel = 3;
props->Width = width;
props->Height = height;
return ::Media::CaptureFrameGrabber::CreateAsync(m_capture.Get(), props);
}).then([this](::Media::CaptureFrameGrabber^ frameGrabber)
{
m_frameGrabber = frameGrabber;
bGrabberInited = true;
bGrabberInitInProgress = false;
_GrabFrameAsync(frameGrabber);
});
return true;
});
return true;
}
void Video::_GrabFrameAsync(::Media::CaptureFrameGrabber^ frameGrabber) {
create_task(frameGrabber->GetFrameAsync()).then([this, frameGrabber](const ComPtr<IMF2DBuffer2>& buffer)
{
BYTE *pbScanline;
LONG plPitch;
unsigned int colBytes = width * bytesPerPixel;
CHK(buffer->Lock2D(&pbScanline, &plPitch));
if (bFlipImageX)
{
std::lock_guard<std::mutex> lock(VideoioBridge::getInstance().inputBufferMutex);
auto buf = VideoioBridge::getInstance().backInputPtr;
for (unsigned int row = 0; row < height; row++)
{
unsigned int i = 0;
unsigned int j = colBytes - 1;
while (i < colBytes)
{
buf[j--] = pbScanline[i++];
buf[j--] = pbScanline[i++];
buf[j--] = pbScanline[i++];
}
pbScanline += plPitch;
buf += colBytes;
}
VideoioBridge::getInstance().bIsFrameNew = true;
} else
{
std::lock_guard<std::mutex> lock(VideoioBridge::getInstance().inputBufferMutex);
auto buf = VideoioBridge::getInstance().backInputPtr;
for (unsigned int row = 0; row < height; row++)
{
for (unsigned int i = 0; i < colBytes; i += bytesPerPixel)
{
buf[i] = pbScanline[i + 2];
buf[i + 1] = pbScanline[i + 1];
buf[i + 2] = pbScanline[i];
}
pbScanline += plPitch;
buf += colBytes;
}
VideoioBridge::getInstance().bIsFrameNew = true;
}
CHK(buffer->Unlock2D());
VideoioBridge::getInstance().frameCounter++;
if (bGrabberInited)
{
_GrabFrameAsync(frameGrabber);
}
}, task_continuation_context::use_current());
}
void Video::CopyOutput() {
{
std::lock_guard<std::mutex> lock(VideoioBridge::getInstance().outputBufferMutex);
auto inAr = VideoioBridge::getInstance().frontInputPtr;
auto outAr = GetData(VideoioBridge::getInstance().frontOutputBuffer->PixelBuffer);
const unsigned int bytesPerPixel = 3;
auto pbScanline = inAr;
auto plPitch = width * bytesPerPixel;
auto buf = outAr;
unsigned int colBytes = width * 4;
for (unsigned int row = 0; row < height; row++)
{
for (unsigned int i = 0, j = 0; i < plPitch; i += bytesPerPixel, j += 4)
{
buf[j] = pbScanline[i + 2];
buf[j + 1] = pbScanline[i + 1];
buf[j + 2] = pbScanline[i];
buf[j + 3] = 0xff;
}
pbScanline += plPitch;
buf += colBytes;
}
VideoioBridge::getInstance().frontOutputBuffer->PixelBuffer->Length = width * height * 4;
}
}
bool Video::listDevicesTask() {
std::atomic<bool> ready(false);
auto settings = ref new MediaCaptureInitializationSettings();
create_task(DeviceInformation::FindAllAsync(DeviceClass::VideoCapture))
.then([this, &ready](task<DeviceInformationCollection^> findTask)
{
m_devices = findTask.get();
ready = true;
});
int count = 0;
while (!ready)
{
count++;
}
return true;
}
bool Video::listDevices() {
std::future<bool> result = std::async(std::launch::async, &Video::listDevicesTask, this);
return result.get();
}