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