#include "DirectShowCapture.h"
#include <easy/profiler.h>
#include <Windows.h>
#include <chrono>
#include <cstring>
#ifdef WIN32
#undef GetObject
#endif
using namespace adtf::streaming;
using namespace adtf::ucom;
using namespace adtf::util;
constexpr tUInt DEFAULT_FRAMERATE = 20;
constexpr tUInt DEFAULT_TIMEOUT = 2000000;
constexpr tUInt DEFAULT_BITSPERPIXEL = 8;
constexpr tTimeStamp MICROSEC_PER_SEC = 1000000;
cDirectShowCaptureDevice::~cDirectShowCaptureDevice()
{
m_oDSInput.Release();
}
tResult cDirectShowCaptureDevice::DeviceOpen(const tChar* strReceiverName,
const tChar* strDeviceName,
tUInt32 nFrameRate,
const tInternalFormat& sFormat)
{
m_strReceiverName = strReceiverName;
_runtime->GetObject(m_pClock);
cDSInput::tDeviceConfig sDSDeviceConfig;
std::memset(&sDSDeviceConfig, 0, sizeof(sDSDeviceConfig));
sDSDeviceConfig.ui32Mask = cDSInput::DCM_FrameRate;
sDSDeviceConfig.nFrameRate = nFrameRate;
if (nFrameRate != 0)
{
m_tmFrameTime = MICROSEC_PER_SEC / nFrameRate;
}
else
{
m_tmFrameTime = MICROSEC_PER_SEC / DEFAULT_FRAMERATE;
}
m_pStreamType = make_object_ptr<cStreamType>(stream_meta_type_image());
set_stream_type_image_format(*m_pStreamType, sFormat);
sDSDeviceConfig.sBitmapFormat = sFormat;
HRESULT hr = S_OK;
if (!m_oDSInput.Open(strDeviceName, nullptr, this, &sDSDeviceConfig, 0, &hr))
{
if (hr != S_OK)
{
cString strError = cDSInput::GetDSError(hr);
RETURN_ERROR_DESC(ERR_INVALID_ARG, "DirectShow Error: %s", strError.GetPtr());
}
else
{
RETURN_ERROR_DESC(ERR_INVALID_ARG, "Can not open device (error unknown)");
}
}
const tInternalFormat* psCaptureFormat = m_oDSInput.GetBitmapFormat();
set_stream_type_image_format(*m_pStreamType, *psCaptureFormat);
RETURN_NOERROR;
}
tResult cDirectShowCaptureDevice::DeviceStart()
{
m_oDSInput.Play();
RETURN_IF_FAILED(Create(m_strReceiverName + "_t"));
RETURN_IF_FAILED(SetState(tLoopState::Running));
RETURN_NOERROR;
}
tResult cDirectShowCaptureDevice::DeviceStop()
{
m_oDSInput.Stop();
{
std::unique_lock<std::mutex> oLock(m_oSync);
m_pCurrentSample = nullptr;
m_bTypeChanged = tFalse;
SetState(tLoopState::Suspended, tFalse);
m_oReceiveEvent.notify_all();
}
SetState(tLoopState::Suspended, tTrue);
RETURN_NOERROR;
}
tResult cDirectShowCaptureDevice::DeviceClose()
{
SetState(tLoopState::Destroyed, tFalse);
m_oDSInput.Release();
RETURN_NOERROR;
}
tResult cDirectShowCaptureDevice::LoopFunc()
{
object_ptr<ISample> pSample;
{
std::unique_lock<std::mutex> oLock(m_oSync);
m_oReceiveEvent.wait_for(oLock, std::chrono::microseconds(m_tmFrameTime));
if (m_bTypeChanged)
{
set_stream_type_image_format(*m_pStreamType, m_sCurrentFormat);
object_ptr<const IStreamType> pNewType = m_pStreamType;
m_bTypeChanged = tFalse;
*m_pWriter << pNewType;
m_pWriter->ManualTrigger();
}
pSample = m_pCurrentSample;
}
if (pSample)
{
m_pWriter->Write(pSample);
m_pWriter->ManualTrigger();
}
RETURN_NOERROR;
}
void cDirectShowCaptureDevice::OnNewFrame(tTimeStamp nTime,
tUInt8* pData,
tInt nDataSize,
tInternalFormat* pBitmapFormat,
tColor* pPalette,
tBool bVFlip)
{
EASY_FUNCTION(m_strReceiverName);
tBool bTypeChanged = tFalse;
if (pBitmapFormat != nullptr)
{
if (*pBitmapFormat != m_sCurrentFormat)
{
m_sCurrentFormat = *pBitmapFormat;
bTypeChanged = tTrue;
}
}
object_ptr<ISample> pSample;
if (IS_FAILED(alloc_sample(pSample)))
{
*m_pWriter << ERR_MEMORY;
m_pWriter->ManualTrigger();
}
if (IS_FAILED(pSample->Set(m_pClock->GetStreamTime(), pData, nDataSize)))
{
*m_pWriter << ERR_MEMORY;
m_pWriter->ManualTrigger();
}
if (!bVFlip)
{
}
else
{
object_ptr_locked<ISampleBuffer> pBuffer;
pSample->WriteLock(pBuffer, nDataSize);
if (pBuffer)
{
tVoid* pCurrentBuffer = pBuffer->GetPtr();
if (m_sCurrentFormat.m_ui32Height > 0)
{
tSize nBytesPerLine = m_sCurrentFormat.m_szMaxByteSize / m_sCurrentFormat.m_ui32Height;
const tUInt8* pSrcLine = pData;
const tUInt8* pSrcLineEnd = pData + m_sCurrentFormat.m_szMaxByteSize;
tUInt8* pDestLine = static_cast<tUInt8*>(pCurrentBuffer) + ((m_sCurrentFormat.m_ui32Height - 1) * nBytesPerLine);
while (pSrcLine < pSrcLineEnd)
{
cMemoryBlock::MemCopy(pDestLine, pSrcLine, nBytesPerLine);
pSrcLine += nBytesPerLine;
pDestLine -= nBytesPerLine;
}
}
}
}
{
std::unique_lock<std::mutex> oLock(m_oSync);
if (bTypeChanged)
{
m_bTypeChanged = tTrue;
m_pCurrentSample = nullptr;
}
if (pSample)
{
m_pCurrentSample = pSample;
}
m_oReceiveEvent.notify_all();
}
}
void cDirectShowCaptureDevice::OnStreamEvent(tInt lEventCode,
tInt lParam1,
tInt lParam2)
{
}