2,新增“Apps”; 3,新增“Common”; 4,新增“FileList”; 5,新增“MediaX”; 6,新增“OpenSource”; 7,新增“Samples”; 8,新增“SoftwareBusinessLines”.
628 lines
12 KiB
C++
628 lines
12 KiB
C++
#include "DeckLinkManager.h"
|
|
|
|
#pragma comment(lib, "ole32") // Windows
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
CDeckLinkInputDelegate::CDeckLinkInputDelegate(void* pOwner)
|
|
{
|
|
m_pOwner = pOwner;
|
|
m_RefCount = 1;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CDeckLinkInputDelegate::QueryInterface(REFIID iid, LPVOID *ppv)
|
|
{
|
|
HRESULT result = E_NOINTERFACE;
|
|
|
|
// Initialise the return result
|
|
*ppv = NULL;
|
|
|
|
// Obtain the IUnknown interface and compare it the provided REFIID
|
|
if (iid == IID_IUnknown)
|
|
{
|
|
*ppv = this;
|
|
AddRef();
|
|
result = S_OK;
|
|
}
|
|
else if (iid == IID_IDeckLinkInputCallback)
|
|
{
|
|
*ppv = (IDeckLinkInputCallback*)this;
|
|
AddRef();
|
|
result = S_OK;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
ULONG STDMETHODCALLTYPE CDeckLinkInputDelegate::AddRef(void)
|
|
{
|
|
return InterlockedIncrement((LONG*)&m_RefCount);
|
|
}
|
|
|
|
ULONG STDMETHODCALLTYPE CDeckLinkInputDelegate::Release(void)
|
|
{
|
|
int newRefValue;
|
|
|
|
newRefValue = InterlockedDecrement((LONG*)&m_RefCount);
|
|
if (newRefValue == 0)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
return newRefValue;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CDeckLinkInputDelegate::VideoInputFormatChanged(BMDVideoInputFormatChangedEvents notificationEvents, IDeckLinkDisplayMode* newDisplayMode, BMDDetectedVideoInputFormatFlags detectedSignalFlags)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CDeckLinkInputDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame* pArrivedFrame, IDeckLinkAudioInputPacket*)
|
|
{
|
|
CDeckLinkManager* pDeckLinkManager = reinterpret_cast<CDeckLinkManager*>(m_pOwner);
|
|
|
|
if(nullptr == pDeckLinkManager)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
if (pDeckLinkManager->m_bRunning)
|
|
{
|
|
pDeckLinkManager->CaptureVideoFrame(pArrivedFrame);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
CVideoInput::CVideoInput(const char* lpszCardName, void* pOwner)
|
|
{
|
|
m_strCardName = lpszCardName;
|
|
m_pOwner = pOwner;
|
|
m_pInputCard = nullptr;
|
|
|
|
m_bOpen = false;
|
|
}
|
|
|
|
CVideoInput::~CVideoInput()
|
|
{
|
|
Stop();
|
|
|
|
if(nullptr != m_pInputCard)
|
|
{
|
|
m_pInputCard->Release();
|
|
m_pInputCard = nullptr;
|
|
}
|
|
}
|
|
|
|
bool CVideoInput::Init(int nChannel, CDeckLinkInputDelegate *pDelegate, BMDDisplayMode dmDisplayMode )
|
|
{
|
|
BSTR bstrCardName;
|
|
QString strCardName;
|
|
bool bInit = false;
|
|
|
|
CDeckLinkManager* pDeckLinkManager = reinterpret_cast<CDeckLinkManager*>(m_pOwner);
|
|
|
|
if(nullptr == pDeckLinkManager)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (int i = 0; i < pDeckLinkManager->m_nDeckLinkCount; i++)
|
|
{
|
|
pDeckLinkManager->m_pDeckLink[i]->GetModelName(&bstrCardName);
|
|
strCardName = QString::fromWCharArray(bstrCardName);
|
|
|
|
if (strCardName == "Intensity Pro")
|
|
{
|
|
if(1 == nChannel)
|
|
{
|
|
strCardName = strCardName + "1";
|
|
}
|
|
else
|
|
{
|
|
strCardName = strCardName + "2";
|
|
}
|
|
}
|
|
else if (strCardName == "DeckLink Duo 2")
|
|
{
|
|
if(!m_strCardName.contains("DeckLink Duo") )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if(nChannel != i+1)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
m_strCardName = strCardName;
|
|
}
|
|
else
|
|
{
|
|
// to do
|
|
}
|
|
|
|
if (strCardName == m_strCardName)
|
|
{
|
|
pDeckLinkManager->m_pDeckLink[i]->QueryInterface(IID_IDeckLinkInput, (void**)&m_pInputCard);
|
|
m_pInputCard->SetCallback(pDelegate);
|
|
|
|
bInit = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
m_dmDisplayMode = dmDisplayMode;
|
|
|
|
return bInit;
|
|
}
|
|
|
|
bool CVideoInput::Start()
|
|
{
|
|
if(nullptr == m_pInputCard)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Stop();
|
|
|
|
HRESULT hr = S_FALSE;
|
|
|
|
//
|
|
hr = m_pInputCard->EnableVideoInput(m_dmDisplayMode, bmdFormat8BitYUV, 0);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//
|
|
hr = m_pInputCard->StartStreams();
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
m_bOpen = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CVideoInput::Stop()
|
|
{
|
|
if(nullptr == m_pInputCard)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if(!m_bOpen)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
m_bOpen = false;
|
|
|
|
HRESULT hr = S_FALSE;
|
|
|
|
hr = m_pInputCard->StopStreams();;
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
hr = m_pInputCard->DisableVideoInput();
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
CVideoOutput::CVideoOutput(const char* lpszCardName, void* pOwner)
|
|
{
|
|
m_strCardName = lpszCardName;
|
|
m_pOwner = pOwner;
|
|
m_pOutputCard = nullptr;
|
|
m_pVideoFrame = nullptr;
|
|
|
|
m_nFrameWidth = 0;
|
|
m_nFrameHeight = 0;
|
|
|
|
m_bOpen = false;
|
|
}
|
|
|
|
CVideoOutput::~CVideoOutput()
|
|
{
|
|
Stop();
|
|
|
|
if(nullptr != m_pOutputCard)
|
|
{
|
|
m_pOutputCard->Release();
|
|
m_pOutputCard = nullptr;
|
|
}
|
|
}
|
|
|
|
bool CVideoOutput::Init(int nChannel, BMDDisplayMode dmDisplayMode, int nFrameWidth, int nFrameHeight)
|
|
{
|
|
BSTR bstrCardName;
|
|
QString strCardName;
|
|
bool bInit = false;
|
|
|
|
CDeckLinkManager* pDeckLinkManager = reinterpret_cast<CDeckLinkManager*>(m_pOwner);
|
|
|
|
if(nullptr == pDeckLinkManager)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (int i = 0; i < pDeckLinkManager->m_nDeckLinkCount; i++)
|
|
{
|
|
pDeckLinkManager->m_pDeckLink[i]->GetModelName(&bstrCardName);
|
|
strCardName = QString::fromWCharArray(bstrCardName);
|
|
|
|
if (strCardName == "Intensity Pro")
|
|
{
|
|
if(1 == nChannel)
|
|
{
|
|
strCardName = strCardName + "1";
|
|
}
|
|
else
|
|
{
|
|
strCardName = strCardName + "2";
|
|
}
|
|
}
|
|
else if (strCardName == "DeckLink Duo 2")
|
|
{
|
|
if(!m_strCardName.contains("DeckLink Duo") )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if(nChannel != i+1)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
m_strCardName = strCardName;
|
|
}
|
|
else
|
|
{
|
|
// to do
|
|
}
|
|
|
|
if (strCardName == m_strCardName)
|
|
{
|
|
pDeckLinkManager->m_pDeckLink[i]->QueryInterface(IID_IDeckLinkOutput, (void**)&m_pOutputCard);
|
|
|
|
m_dmDisplayMode = dmDisplayMode;
|
|
m_nFrameWidth = nFrameWidth;
|
|
m_nFrameHeight = nFrameHeight;
|
|
|
|
m_pOutputCard->CreateVideoFrame(nFrameWidth, nFrameHeight, nFrameWidth*2, bmdFormat8BitYUV, bmdFrameFlagDefault, &m_pVideoFrame);
|
|
|
|
bInit = true;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return bInit;
|
|
}
|
|
|
|
bool CVideoOutput::Start()
|
|
{
|
|
if(nullptr == m_pOutputCard)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Stop();
|
|
|
|
HRESULT hr = S_FALSE;
|
|
|
|
//
|
|
hr = m_pOutputCard->EnableVideoOutput(m_dmDisplayMode, bmdVideoOutputFlagDefault);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
m_bOpen = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
// 停止视频输入
|
|
bool CVideoOutput::Stop()
|
|
{
|
|
if(nullptr == m_pOutputCard)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if(!m_bOpen)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
m_bOpen = false;
|
|
|
|
HRESULT hr = S_FALSE;
|
|
|
|
hr = m_pOutputCard->DisableVideoOutput();
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CVideoOutput::OutputData(byte* pFrameData)
|
|
{
|
|
if(nullptr == m_pOutputCard)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
BYTE *pBuffer = NULL;
|
|
m_pVideoFrame->GetBytes((void**)&pBuffer);
|
|
|
|
memcpy(pBuffer, pFrameData, m_nFrameWidth * m_nFrameHeight * 2);
|
|
|
|
m_pOutputCard->DisplayVideoFrameSync(m_pVideoFrame);
|
|
|
|
return true;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
IDeckLink* CDeckLinkManager::m_pDeckLink[MAX_DECKLINK] = {0};
|
|
int CDeckLinkManager::m_nDeckLinkCount = 0;
|
|
std::map<QString, int> CDeckLinkManager::m_mapDeckLinkCards;
|
|
|
|
CDeckLinkManager::CDeckLinkManager()
|
|
{
|
|
m_pInput = nullptr;
|
|
m_pDelegate = nullptr;
|
|
m_bRunning = false;
|
|
m_nFrameWidth = 0;
|
|
m_nFrameHeight = 0;
|
|
m_nFrameSize = 0;
|
|
m_nTimeScale = 0;
|
|
m_eDisplayMode = bmdModeHD1080p25;
|
|
m_nChannel = 0;
|
|
|
|
m_pFrameData = nullptr;
|
|
m_pOwner = nullptr;
|
|
|
|
m_bVideoInput = true;
|
|
}
|
|
|
|
CDeckLinkManager::~CDeckLinkManager(void)
|
|
{
|
|
if (m_bRunning)
|
|
{
|
|
StopStreams();
|
|
}
|
|
|
|
if (m_pInput != NULL)
|
|
{
|
|
delete m_pInput;
|
|
m_pInput = NULL;
|
|
}
|
|
|
|
if (m_pDelegate != NULL)
|
|
{
|
|
delete m_pDelegate;
|
|
m_pDelegate = NULL;
|
|
}
|
|
|
|
if(NULL != m_pFrameData)
|
|
{
|
|
delete [] m_pFrameData;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 查找DeckLink卡,并返回卡数量
|
|
*/
|
|
int CDeckLinkManager::SearchDeckLinkCard()
|
|
{
|
|
int i = 0;
|
|
IDeckLinkIterator* pIterator = nullptr;
|
|
|
|
BSTR bstrCardName;
|
|
QString strCardName = "";
|
|
|
|
//
|
|
m_mapDeckLinkCards.clear();
|
|
|
|
if (CoCreateInstance(CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**)&pIterator) == S_OK && pIterator != NULL)
|
|
{
|
|
for (; i < MAX_DECKLINK; i++)
|
|
{
|
|
if (pIterator->Next(&m_pDeckLink[i]) != S_OK)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
m_pDeckLink[i]->GetModelName(&bstrCardName);
|
|
strCardName = QString::fromWCharArray(bstrCardName);
|
|
|
|
m_mapDeckLinkCards[strCardName] += 1;
|
|
}
|
|
}
|
|
|
|
m_nDeckLinkCount = i;
|
|
|
|
if(nullptr != pIterator)
|
|
{
|
|
pIterator->Release();
|
|
pIterator = nullptr;
|
|
}
|
|
|
|
return m_nDeckLinkCount;
|
|
}
|
|
|
|
/*
|
|
* 初始化VideoManager(初始化输入)
|
|
*/
|
|
bool CDeckLinkManager::InitVideoInput(const char* lpszCardName, int nChannel, int nFrameWidth, int nFrameHeight, BMDDisplayMode eDisplayMode, pCallBack_DataCapture pCallBack_DataCapture, void* pOwner)
|
|
{
|
|
if (nullptr == lpszCardName)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
m_pDelegate = new CDeckLinkInputDelegate(this);
|
|
m_pInput = new CVideoInput(lpszCardName, this);
|
|
|
|
m_bVideoInput = true; // 视频输入(采集)
|
|
|
|
m_eDisplayMode = eDisplayMode;
|
|
|
|
m_nFrameWidth = nFrameWidth;
|
|
m_nFrameHeight = nFrameHeight;
|
|
m_nTimeScale = 600;
|
|
m_nChannel = nChannel;
|
|
|
|
if(!m_pInput->Init(m_nChannel, m_pDelegate, m_eDisplayMode) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
m_nFrameSize = m_nFrameWidth * m_nFrameHeight * 2;
|
|
|
|
m_pCB_DataCapture = pCallBack_DataCapture;
|
|
|
|
m_pFrameData = new BYTE[m_nFrameSize*2];
|
|
|
|
m_pOwner = pOwner;
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* 初始化VideoManager(初始化输出)
|
|
*/
|
|
bool CDeckLinkManager::InitVideoOutput(const char* lpszCardName, int nChannel, int nFrameWidth, int nFrameHeight, BMDDisplayMode eDisplayMode)
|
|
{
|
|
if (nullptr == lpszCardName)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
m_pOutput = new CVideoOutput(lpszCardName, this);
|
|
|
|
m_bVideoInput = false; // 视频输出
|
|
|
|
m_eDisplayMode = eDisplayMode;
|
|
|
|
m_nFrameWidth = nFrameWidth;
|
|
m_nFrameHeight = nFrameHeight;
|
|
m_nChannel = nChannel;
|
|
|
|
if(!m_pOutput->Init(m_nChannel, m_eDisplayMode, m_nFrameWidth, m_nFrameHeight) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
m_nFrameSize = m_nFrameWidth * m_nFrameHeight * 2;
|
|
|
|
m_pFrameData = new BYTE[m_nFrameSize*2];
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CDeckLinkManager::StartStreams()
|
|
{
|
|
if (m_bRunning)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if(m_bVideoInput)
|
|
{
|
|
if (!m_pInput->Start())
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!m_pOutput->Start())
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
m_bRunning = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CDeckLinkManager::StopStreams()
|
|
{
|
|
if (!m_bRunning)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
m_bRunning = false;
|
|
|
|
if(m_bVideoInput)
|
|
{
|
|
m_pInput->Stop();
|
|
}
|
|
else
|
|
{
|
|
m_pOutput->Stop();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CDeckLinkManager::OutputData(byte* pFrameData)
|
|
{
|
|
if(!m_pOutput)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return m_pOutput->OutputData(pFrameData);
|
|
}
|
|
|
|
/*
|
|
* 采集到达的视频帧
|
|
*/
|
|
void CDeckLinkManager::CaptureVideoFrame(IDeckLinkVideoInputFrame* pArrivedFrame)
|
|
{
|
|
// 获取时间戳
|
|
BMDTimeValue tvFrameTime, tvFrameDuration;
|
|
pArrivedFrame->GetStreamTime(&tvFrameTime, &tvFrameDuration, m_nTimeScale);
|
|
|
|
// 获取数据
|
|
BYTE *pBuffer = NULL;
|
|
pArrivedFrame->GetBytes((void**)&pBuffer);
|
|
|
|
memset(m_pFrameData, 0, m_nFrameSize);
|
|
memcpy_s(m_pFrameData, m_nFrameSize, pBuffer, m_nFrameSize);
|
|
|
|
m_pCB_DataCapture(m_pFrameData, m_nFrameSize, m_pOwner);
|
|
}
|