Files
CodeRepository/Apps/App_GeneralDataInjectionApp/Common/IO/DeviceStream/SDI/DeckLinkManager.cpp
chenzhen 222dda1e43 1,新增“App_ThermalImageSystem”;
2,新增“Apps”;
3,新增“Common”;
4,新增“FileList”;
5,新增“MediaX”;
6,新增“OpenSource”;
7,新增“Samples”;
8,新增“SoftwareBusinessLines”.
2026-02-14 23:03:23 +08:00

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);
}