2019-07-27 12:47:10 +00:00
|
|
|
|
#include <sstream>
|
2016-02-23 23:16:51 +00:00
|
|
|
|
|
|
|
|
|
#include "decklink-device.hpp"
|
|
|
|
|
|
|
|
|
|
#include <util/threading.h>
|
|
|
|
|
|
|
|
|
|
DeckLinkDevice::DeckLinkDevice(IDeckLink *device_) : device(device_)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DeckLinkDevice::~DeckLinkDevice(void)
|
|
|
|
|
{
|
2019-07-27 12:47:10 +00:00
|
|
|
|
for (DeckLinkDeviceMode *mode : inputModes)
|
|
|
|
|
delete mode;
|
|
|
|
|
|
|
|
|
|
for (DeckLinkDeviceMode *mode : outputModes)
|
2016-02-23 23:16:51 +00:00
|
|
|
|
delete mode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ULONG DeckLinkDevice::AddRef()
|
|
|
|
|
{
|
|
|
|
|
return os_atomic_inc_long(&refCount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ULONG DeckLinkDevice::Release()
|
|
|
|
|
{
|
|
|
|
|
long ret = os_atomic_dec_long(&refCount);
|
|
|
|
|
if (ret == 0)
|
|
|
|
|
delete this;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DeckLinkDevice::Init()
|
|
|
|
|
{
|
2018-02-19 19:54:37 +00:00
|
|
|
|
ComPtr<IDeckLinkAttributes> attributes;
|
|
|
|
|
const HRESULT result = device->QueryInterface(IID_IDeckLinkAttributes,
|
|
|
|
|
(void **)&attributes);
|
|
|
|
|
|
|
|
|
|
if (result == S_OK) {
|
|
|
|
|
decklink_bool_t detectable = false;
|
|
|
|
|
if (attributes->GetFlag(BMDDeckLinkSupportsInputFormatDetection,
|
|
|
|
|
&detectable) == S_OK && !!detectable) {
|
2019-07-27 12:47:10 +00:00
|
|
|
|
DeckLinkDeviceMode *mode = new DeckLinkDeviceMode(
|
|
|
|
|
"Auto",
|
|
|
|
|
MODE_ID_AUTO);
|
|
|
|
|
inputModes.push_back(mode);
|
|
|
|
|
inputModeIdMap[MODE_ID_AUTO] = mode;
|
2018-02-19 19:54:37 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-27 12:47:10 +00:00
|
|
|
|
// Find input modes
|
2016-02-23 23:16:51 +00:00
|
|
|
|
ComPtr<IDeckLinkInput> input;
|
2019-07-27 12:47:10 +00:00
|
|
|
|
if (device->QueryInterface(IID_IDeckLinkInput, (void **) &input) == S_OK) {
|
|
|
|
|
IDeckLinkDisplayModeIterator *modeIterator;
|
|
|
|
|
if (input->GetDisplayModeIterator(&modeIterator) == S_OK) {
|
|
|
|
|
IDeckLinkDisplayMode *displayMode;
|
|
|
|
|
long long modeId = 1;
|
|
|
|
|
|
|
|
|
|
while (modeIterator->Next(&displayMode) == S_OK) {
|
|
|
|
|
if (displayMode == nullptr)
|
|
|
|
|
continue;
|
2016-02-23 23:16:51 +00:00
|
|
|
|
|
2019-07-27 12:47:10 +00:00
|
|
|
|
DeckLinkDeviceMode *mode =
|
|
|
|
|
new DeckLinkDeviceMode(displayMode, modeId);
|
|
|
|
|
inputModes.push_back(mode);
|
|
|
|
|
inputModeIdMap[modeId] = mode;
|
|
|
|
|
displayMode->Release();
|
|
|
|
|
++modeId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
modeIterator->Release();
|
2016-02-23 23:16:51 +00:00
|
|
|
|
}
|
2019-07-27 12:47:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get supported video connections
|
|
|
|
|
attributes->GetInt(BMDDeckLinkVideoInputConnections,
|
|
|
|
|
&supportedVideoInputConnections);
|
|
|
|
|
attributes->GetInt(BMDDeckLinkVideoOutputConnections,
|
|
|
|
|
&supportedVideoOutputConnections);
|
|
|
|
|
|
|
|
|
|
// Get supported audio connections
|
|
|
|
|
attributes->GetInt(BMDDeckLinkAudioInputConnections,
|
|
|
|
|
&supportedAudioInputConnections);
|
|
|
|
|
attributes->GetInt(BMDDeckLinkAudioOutputConnections,
|
|
|
|
|
&supportedAudioOutputConnections);
|
2016-02-23 23:16:51 +00:00
|
|
|
|
|
2019-07-27 12:47:10 +00:00
|
|
|
|
// find output modes
|
|
|
|
|
ComPtr<IDeckLinkOutput> output;
|
|
|
|
|
if (device->QueryInterface(IID_IDeckLinkOutput, (void **) &output) == S_OK) {
|
|
|
|
|
|
|
|
|
|
IDeckLinkDisplayModeIterator *modeIterator;
|
|
|
|
|
if (output->GetDisplayModeIterator(&modeIterator) == S_OK) {
|
|
|
|
|
IDeckLinkDisplayMode *displayMode;
|
|
|
|
|
long long modeId = 1;
|
|
|
|
|
|
|
|
|
|
while (modeIterator->Next(&displayMode) == S_OK) {
|
|
|
|
|
if (displayMode == nullptr)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
DeckLinkDeviceMode *mode =
|
|
|
|
|
new DeckLinkDeviceMode(displayMode, modeId);
|
|
|
|
|
outputModes.push_back(mode);
|
|
|
|
|
outputModeIdMap[modeId] = mode;
|
|
|
|
|
displayMode->Release();
|
|
|
|
|
++modeId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
modeIterator->Release();
|
|
|
|
|
}
|
2016-02-23 23:16:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-07-27 12:47:10 +00:00
|
|
|
|
// get keyer support
|
|
|
|
|
attributes->GetFlag(BMDDeckLinkSupportsExternalKeying,
|
|
|
|
|
&supportsExternalKeyer);
|
|
|
|
|
attributes->GetFlag(BMDDeckLinkSupportsInternalKeying,
|
|
|
|
|
&supportsInternalKeyer);
|
|
|
|
|
|
|
|
|
|
// Sub Device Counts
|
|
|
|
|
attributes->GetInt(BMDDeckLinkSubDeviceIndex, &subDeviceIndex);
|
|
|
|
|
attributes->GetInt(BMDDeckLinkNumberOfSubDevices, &numSubDevices);
|
|
|
|
|
|
2016-02-23 23:16:51 +00:00
|
|
|
|
decklink_string_t decklinkModelName;
|
|
|
|
|
decklink_string_t decklinkDisplayName;
|
|
|
|
|
|
|
|
|
|
if (device->GetModelName(&decklinkModelName) != S_OK)
|
|
|
|
|
return false;
|
|
|
|
|
DeckLinkStringToStdString(decklinkModelName, name);
|
|
|
|
|
|
|
|
|
|
if (device->GetDisplayName(&decklinkDisplayName) != S_OK)
|
|
|
|
|
return false;
|
|
|
|
|
DeckLinkStringToStdString(decklinkDisplayName, displayName);
|
|
|
|
|
|
|
|
|
|
hash = displayName;
|
|
|
|
|
|
|
|
|
|
if (result != S_OK)
|
|
|
|
|
return true;
|
|
|
|
|
|
2017-06-29 19:01:10 +00:00
|
|
|
|
int64_t channels;
|
|
|
|
|
/* Intensity Shuttle for Thunderbolt return 2; however, it supports 8 channels */
|
|
|
|
|
if (name == "Intensity Shuttle Thunderbolt")
|
|
|
|
|
maxChannel = 8;
|
|
|
|
|
else if (attributes->GetInt(BMDDeckLinkMaximumAudioChannels, &channels) == S_OK)
|
|
|
|
|
maxChannel = (int32_t)channels;
|
|
|
|
|
else
|
|
|
|
|
maxChannel = 2;
|
|
|
|
|
|
2016-05-24 19:53:01 +00:00
|
|
|
|
/* http://forum.blackmagicdesign.com/viewtopic.php?f=12&t=33967
|
|
|
|
|
* BMDDeckLinkTopologicalID for older devices
|
|
|
|
|
* BMDDeckLinkPersistentID for newer ones */
|
|
|
|
|
|
2016-02-23 23:16:51 +00:00
|
|
|
|
int64_t value;
|
2016-05-24 19:53:01 +00:00
|
|
|
|
if (attributes->GetInt(BMDDeckLinkPersistentID, &value) != S_OK &&
|
|
|
|
|
attributes->GetInt(BMDDeckLinkTopologicalID, &value) != S_OK)
|
2016-02-23 23:16:51 +00:00
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
std::ostringstream os;
|
|
|
|
|
os << value << "_" << name;
|
|
|
|
|
hash = os.str();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DeckLinkDevice::GetInput(IDeckLinkInput **input)
|
|
|
|
|
{
|
|
|
|
|
if (device->QueryInterface(IID_IDeckLinkInput, (void**)input) != S_OK)
|
|
|
|
|
return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-27 12:47:10 +00:00
|
|
|
|
bool DeckLinkDevice::GetOutput(IDeckLinkOutput **output)
|
2016-02-23 23:16:51 +00:00
|
|
|
|
{
|
2019-07-27 12:47:10 +00:00
|
|
|
|
if (device->QueryInterface(IID_IDeckLinkOutput, (void**)output) != S_OK)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DeckLinkDevice::GetKeyer(IDeckLinkKeyer **deckLinkKeyer)
|
|
|
|
|
{
|
|
|
|
|
if (device->QueryInterface(IID_IDeckLinkKeyer, (void**)deckLinkKeyer) != S_OK)
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "Could not obtain the IDeckLinkKeyer interface\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeckLinkDevice::SetKeyerMode(int newKeyerMode)
|
|
|
|
|
{
|
|
|
|
|
keyerMode = newKeyerMode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int DeckLinkDevice::GetKeyerMode(void)
|
|
|
|
|
{
|
|
|
|
|
return keyerMode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DeckLinkDeviceMode *DeckLinkDevice::FindInputMode(long long id)
|
|
|
|
|
{
|
|
|
|
|
return inputModeIdMap[id];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DeckLinkDeviceMode *DeckLinkDevice::FindOutputMode(long long id)
|
|
|
|
|
{
|
|
|
|
|
return outputModeIdMap[id];
|
2016-02-23 23:16:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const std::string& DeckLinkDevice::GetDisplayName(void)
|
|
|
|
|
{
|
|
|
|
|
return displayName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const std::string& DeckLinkDevice::GetHash(void) const
|
|
|
|
|
{
|
|
|
|
|
return hash;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-27 12:47:10 +00:00
|
|
|
|
const std::vector<DeckLinkDeviceMode *>& DeckLinkDevice::GetInputModes(void) const
|
|
|
|
|
{
|
|
|
|
|
return inputModes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const std::vector<DeckLinkDeviceMode *>& DeckLinkDevice::GetOutputModes(void) const
|
|
|
|
|
{
|
|
|
|
|
return outputModes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int64_t DeckLinkDevice::GetVideoInputConnections()
|
|
|
|
|
{
|
|
|
|
|
return supportedVideoInputConnections;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int64_t DeckLinkDevice::GetAudioInputConnections()
|
|
|
|
|
{
|
|
|
|
|
return supportedAudioInputConnections;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool DeckLinkDevice::GetSupportsExternalKeyer(void) const
|
|
|
|
|
{
|
|
|
|
|
return supportsExternalKeyer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DeckLinkDevice::GetSupportsInternalKeyer(void) const
|
|
|
|
|
{
|
|
|
|
|
return supportsInternalKeyer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int64_t DeckLinkDevice::GetSubDeviceCount()
|
|
|
|
|
{
|
|
|
|
|
return numSubDevices;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int64_t DeckLinkDevice::GetSubDeviceIndex()
|
2016-02-23 23:16:51 +00:00
|
|
|
|
{
|
2019-07-27 12:47:10 +00:00
|
|
|
|
return subDeviceIndex;
|
2016-02-23 23:16:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const std::string& DeckLinkDevice::GetName(void) const
|
|
|
|
|
{
|
|
|
|
|
return name;
|
|
|
|
|
}
|
2017-06-29 19:01:10 +00:00
|
|
|
|
|
|
|
|
|
int32_t DeckLinkDevice::GetMaxChannel(void) const
|
|
|
|
|
{
|
|
|
|
|
return maxChannel;
|
|
|
|
|
}
|