HRESULT hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, riid, (void**)&this->CaptureInterface);
HR_GUARD_RET(hr, TEXT("CoCreateInstance"));
this->WindowName = FString::Printf(TEXT("LtmmCaptureWindow%X"), this);
this->Window = CreateCaptureWindow(*this->WindowName, 32, 32, CaptureWindowProc);
if (!this->Window)
{
UE_LOG(LtmmLog, Error, TEXT("CreateCaptureWindow failed"));
break;
}
SetWindowLongPtr((HWND)this->Window, DWLP_USER, (LONG_PTR)this);
this->CaptureInterface->SetNotifyWindow((long)(UINT64)this->Window, WM_CAPTURENOTIFY);
this->CaptureInterface->put_VideoWindowFrame(0);
this->CaptureInterface->put_PreferredVideoRenderer(ltmmVideoRenderer_NULL);
this->VideoTexture = new UVideoTexture();
this->UserCallback = new LMVUserCallbackImpl(this);
// Setup Video Processors
HRESULT hr = RemoveVideoProcessors(this->CaptureInterface);
HR_GUARD_BREAK(hr, TEXT("RemoveVideoProcessors"));
long ProcessorId = 0;
// LEAD Video RGB Converter
#if 1
{
ScopedComPtr<IltmmProcessor> Processor;
hr = FindVideoProcessor(this->CaptureInterface,
L"@device:sw:{E526D606-22E7-494C-B81E-AC0A94BFE603}\\{E2B7DB22-38C5-11D5-91F6-00104BDB8FF9}",
&Processor);
HR_GUARD_BREAK(hr, TEXT("FindVideoProcessor"));
hr = AddVideoProcessor(this->CaptureInterface, Processor, ProcessorId);
HR_GUARD_BREAK(hr, TEXT("AddVideoProcessor"));
ScopedComPtr<IUnknown> ProcessorObject;
hr = GetSelectedVideoProcessor(this->CaptureInterface, ProcessorId, &ProcessorObject);
HR_GUARD_BREAK(hr, TEXT("GetSelectedVideoProcessor"));
ScopedComPtr<ILMVConvRGB> ProcessorInterface;
hr = ProcessorObject->QueryInterface(IID_ILMVConvRGB, (void**)&ProcessorInterface);
HR_GUARD_BREAK(hr, TEXT("QueryInterface IID_ILMVConvRGB"));
hr = ProcessorInterface->SetOutputType(LM_MEDIATYPE_RGB32, false);
HR_GUARD_BREAK(hr, TEXT("SetOutputType"));
hr = ProcessorInterface->SetRGBOrder(false);
HR_GUARD_BREAK(hr, TEXT("SetRGBOrder"));
++ProcessorId;
}
#endif
// LEAD Video Callback Filter (2.0)
{
ScopedComPtr<IltmmProcessor> Processor;
hr = FindVideoProcessor(this->CaptureInterface,
L"@device:sw:{E526D606-22E7-494C-B81E-AC0A94BFE603}\\{E2B7DDB0-38C5-11D5-91F6-00104BDB8FF9}",
&Processor);
HR_GUARD_BREAK(hr, TEXT("FindVideoProcessor"));
hr = AddVideoProcessor(this->CaptureInterface, Processor, ProcessorId);
HR_GUARD_BREAK(hr, TEXT("AddVideoProcessor"));
ScopedComPtr<IUnknown> ProcessorObject;
hr = GetSelectedVideoProcessor(this->CaptureInterface, ProcessorId, &ProcessorObject);
HR_GUARD_BREAK(hr, TEXT("GetSelectedVideoProcessor"));
hr = ProcessorObject->QueryInterface(IID_ILMVCallback2, (void**)&this->VideoCallback);
HR_GUARD_BREAK(hr, TEXT("QueryInterface IID_ILMVCallback2"));
this->VideoCallback->put_CallInSameThread(VARIANT_FALSE);
this->VideoCallback->put_ReceiveProcObj(this->UserCallback);
++ProcessorId;
}
HRESULT hr = this->CaptureInterface->StartCapture(ltmmCapture_Mode_Video);
HR_GUARD_RET(hr, TEXT("IltmmCapture::StartCapture"));
// SUCCESS
struct LMVUserCallbackImpl : public ILMVUserCallback2
{
IVideoFrameHandler* Context = nullptr;
double LastFrameTime = 0;
LMVUserCallbackImpl(IVideoFrameHandler* ContextPtr) : Context(ContextPtr) { }
STDMETHODIMP QueryInterface(REFIID riid, void** ppv)
{
if (!ppv) return E_POINTER;
if (riid == IID_ILMVUserCallback2)
{
*ppv = (ILMVUserCallback2*)this;
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) AddRef() { return S_OK; }
STDMETHODIMP_(ULONG) Release() { return S_OK; }
STDMETHODIMP ReceiveProc(LONGLONG pData, LONG lWidth, LONG lHeight, LONG lBitCount, LONG lSize, LONG bTopDown)
{
#if 1
const double ticks = FPlatformTime::Seconds();
if (this->LastFrameTime > 0)
{
double delta = ticks - this->LastFrameTime;
if (delta > (1 / 10.0)) // at least 10 FPS
{
UE_LOG(LtmmLog, LTMM_LOG_LEVEL, TEXT("LAG: ILMVUserCallback %.5f ms"), delta * 1000);
}
}
this->LastFrameTime = ticks;
#endif
if (Context)
{
// disabled for lag test
//Context->OnVideoFrame((void*)pData, (size_t)lSize, (int)lWidth, (int)lHeight, (int)lBitCount, (int)bTopDown);
}
return S_OK;
}
};