refactor: DeckLinkReceiver cleanup and encapsulation
DeckLinkReceiver:
- Make InputCallback a private nested class — no longer exposed publicly
- DeckLinkReceiver owns all shared state (mutex, CVs, frame buffer)
- Replace get_input_callback() with clean wait_for_frame() API
- Fix device list leak: enumerate_devices stores raw IDeckLink* in
raw_devices; destructor releases all of them + selected_device's AddRef
- Remove dead members: device_config, device_status, deckLink_notification
- Remove dead SourceInfo::stride field; rename SourceInfo → VideoInfo
- Remove dead video_source_info public member
- Remove printf; use no logging in receiver (caller logs)
- Remove commented-out notification code
- Fix dead return false after throw in enumerate_devices
- Fix dead null check after new InputCallback
- Replace IDeckLinkVideoBuffer QueryInterface with simpler GetBytes()
- Replace plain bool frame_ready/format_detected with consistent usage
under mutex (no longer mixing atomic + CV pattern)
- Call StopStreams/DisableVideoInput in destructor
- Consistent snake_case naming throughout
decklinkin main.cpp:
- Rename NodeDeckLinkIn → DeckLinkInNode
- Get device_index from config().value("device_index", 0u)
- Remove unused includes: <time.h>, <algorithm>, <cstdio>, <DeckLinkAPI.h>
- Use clean receiver.wait_for_frame() instead of reaching into callback
- Use mxlGetCurrentIndex resync after sleep (consistent with other nodes)
- Fix return node.execute() (was node.execute(); return 0)
- Fix main() spacing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+175
-332
@@ -1,374 +1,217 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <numeric>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <DeckLinkAPI.h>
|
||||
|
||||
namespace dmf { class DeckLinkReceiver; }
|
||||
#include "Signal.hpp"
|
||||
|
||||
namespace dmf {
|
||||
|
||||
struct SourceInfo {
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int fps_num = 0;
|
||||
int fps_den = 0;
|
||||
int stride = 0;
|
||||
};
|
||||
class DeckLinkReceiver {
|
||||
public:
|
||||
struct VideoInfo {
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int fps_num = 0;
|
||||
int fps_den = 0;
|
||||
};
|
||||
|
||||
class DeckLinkInputCallback: public IDeckLinkInputCallback
|
||||
{
|
||||
struct DeviceInfo {
|
||||
uint32_t index;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
std::vector<DeviceInfo> devices;
|
||||
VideoInfo video_info{};
|
||||
|
||||
DeckLinkReceiver() { enumerate_devices(); }
|
||||
|
||||
~DeckLinkReceiver() {
|
||||
if (decklink_input) {
|
||||
decklink_input->StopStreams();
|
||||
decklink_input->DisableVideoInput();
|
||||
decklink_input->SetCallback(nullptr);
|
||||
decklink_input->Release();
|
||||
}
|
||||
delete input_callback;
|
||||
for (auto* d : raw_devices) d->Release();
|
||||
if (selected_device) selected_device->Release();
|
||||
}
|
||||
|
||||
void start_capture(uint32_t device_index) {
|
||||
if (device_index >= raw_devices.size())
|
||||
throw std::runtime_error("Device index out of range");
|
||||
|
||||
selected_device = raw_devices[device_index];
|
||||
selected_device->AddRef();
|
||||
|
||||
HRESULT r = selected_device->QueryInterface(IID_IDeckLinkInput, (void**)&decklink_input);
|
||||
if (r != S_OK) throw std::runtime_error("Could not obtain IDeckLinkInput");
|
||||
|
||||
input_callback = new InputCallback(*this);
|
||||
r = decklink_input->SetCallback(input_callback);
|
||||
if (r != S_OK) throw std::runtime_error("Could not set input callback");
|
||||
|
||||
r = decklink_input->EnableVideoInput(bmdModeNTSC, bmdFormat10BitYUV,
|
||||
bmdVideoInputEnableFormatDetection);
|
||||
if (r != S_OK) throw std::runtime_error("Could not enable video input");
|
||||
|
||||
r = decklink_input->StartStreams();
|
||||
if (r != S_OK) throw std::runtime_error("Could not start streams");
|
||||
}
|
||||
|
||||
bool wait_for_format(uint64_t timeout_ms = 5000) {
|
||||
std::unique_lock<std::mutex> lk(mutex);
|
||||
return format_cv.wait_for(lk, std::chrono::milliseconds(timeout_ms),
|
||||
[this] { return format_detected; });
|
||||
}
|
||||
|
||||
// Blocks until a fresh frame arrives or g_running goes false.
|
||||
// Copies frame data into dst with MXL stride. Returns false on shutdown.
|
||||
bool wait_for_frame(uint8_t* dst, uint32_t dst_stride, int width, int height) {
|
||||
std::unique_lock<std::mutex> lk(mutex);
|
||||
frame_cv.wait(lk, [this] {
|
||||
return frame_ready || !dmf::g_running.load(std::memory_order_relaxed);
|
||||
});
|
||||
if (!dmf::g_running.load(std::memory_order_relaxed)) return false;
|
||||
|
||||
const uint32_t src_stride = frame_row_bytes;
|
||||
const int rows = std::min(frame_height, height);
|
||||
const uint32_t copy_bytes = std::min(src_stride, dst_stride);
|
||||
|
||||
std::memset(dst, 0, static_cast<size_t>(dst_stride) * static_cast<size_t>(height));
|
||||
const uint8_t* src = frame_buffer.data();
|
||||
uint8_t* d = dst;
|
||||
for (int y = 0; y < rows; ++y, src += src_stride, d += dst_stride)
|
||||
std::memcpy(d, src, copy_bytes);
|
||||
|
||||
frame_ready = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
class InputCallback : public IDeckLinkInputCallback {
|
||||
public:
|
||||
bool is_video_info_set() const { return video_info_set.load(std::memory_order_acquire); }
|
||||
SourceInfo video_info{};
|
||||
|
||||
std::mutex frame_mutex;
|
||||
std::condition_variable frame_cv;
|
||||
std::vector<uint8_t> frame_buffer;
|
||||
std::atomic<bool> frame_ready{false};
|
||||
size_t frame_size = 0;
|
||||
uint32_t frame_row_bytes = 0; // actual stride from GetRowBytes()
|
||||
int frame_width = 0;
|
||||
int frame_height = 0;
|
||||
|
||||
DeckLinkInputCallback(
|
||||
dmf::DeckLinkReceiver* receiver,
|
||||
bool detection_enabled,
|
||||
std::mutex& mtx,
|
||||
std::condition_variable& cv
|
||||
)
|
||||
: decklink_receiver(receiver)
|
||||
, ref_count(1)
|
||||
, detection_enabled(detection_enabled)
|
||||
, format_mutex(mtx)
|
||||
, format_cv(cv)
|
||||
{}
|
||||
|
||||
void set_decklink_input(IDeckLinkInput* input) { deckLink_input = input; }
|
||||
explicit InputCallback(DeckLinkReceiver& owner) : owner(owner) {}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(
|
||||
BMDVideoInputFormatChangedEvents notification_events,
|
||||
IDeckLinkDisplayMode *new_display_mode,
|
||||
BMDDetectedVideoInputFormatFlags detected_signal_flags
|
||||
) override
|
||||
BMDVideoInputFormatChangedEvents events,
|
||||
IDeckLinkDisplayMode* mode,
|
||||
BMDDetectedVideoInputFormatFlags /*flags*/) override
|
||||
{
|
||||
store_format(new_display_mode, nullptr);
|
||||
long w = new_display_mode->GetWidth();
|
||||
long h = new_display_mode->GetHeight();
|
||||
BMDTimeValue dur; BMDTimeScale ts;
|
||||
new_display_mode->GetFrameRate(&dur, &ts);
|
||||
double fps = (double)ts / (double)dur;
|
||||
const char* name = nullptr;
|
||||
new_display_mode->GetName(&name);
|
||||
printf("Input changed to: %ldx%ld @ %.2f fps (%s)\n", w, h, fps, name ? name : "?");
|
||||
if (!(events & bmdVideoInputDisplayModeChanged)) return S_OK;
|
||||
|
||||
// Discard any stale frame from the placeholder mode
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(frame_mutex);
|
||||
frame_ready.store(false, std::memory_order_release);
|
||||
frame_width = 0;
|
||||
frame_height = 0;
|
||||
frame_buffer.clear();
|
||||
}
|
||||
|
||||
// Re-enable video input with the detected display mode (per SDK samples)
|
||||
if (deckLink_input && (notification_events & bmdVideoInputDisplayModeChanged)) {
|
||||
HRESULT r = deckLink_input->StopStreams();
|
||||
if (r == S_OK) {
|
||||
r = deckLink_input->EnableVideoInput(
|
||||
new_display_mode->GetDisplayMode(),
|
||||
bmdFormat10BitYUV,
|
||||
bmdVideoInputEnableFormatDetection);
|
||||
if (r == S_OK) {
|
||||
r = deckLink_input->StartStreams();
|
||||
if (r != S_OK) {
|
||||
printf("StartStreams after reconfig failed (0x%08x)\n", r);
|
||||
}
|
||||
} else {
|
||||
printf("EnableVideoInput after reconfig failed (0x%08x)\n", r);
|
||||
}
|
||||
} else {
|
||||
printf("StopStreams for reconfig failed (0x%08x)\n", r);
|
||||
std::lock_guard<std::mutex> lk(owner.mutex);
|
||||
owner.video_info.width = static_cast<int>(mode->GetWidth());
|
||||
owner.video_info.height = static_cast<int>(mode->GetHeight());
|
||||
BMDTimeValue dur = 0; BMDTimeScale ts = 0;
|
||||
mode->GetFrameRate(&dur, &ts);
|
||||
if (dur > 0 && ts > 0) {
|
||||
owner.video_info.fps_num = static_cast<int>(ts);
|
||||
owner.video_info.fps_den = static_cast<int>(dur);
|
||||
const int g = std::gcd(owner.video_info.fps_num, owner.video_info.fps_den);
|
||||
if (g > 1) { owner.video_info.fps_num /= g; owner.video_info.fps_den /= g; }
|
||||
}
|
||||
owner.frame_ready = false;
|
||||
owner.frame_buffer.clear();
|
||||
owner.format_detected = true;
|
||||
}
|
||||
owner.format_cv.notify_one();
|
||||
|
||||
HRESULT r = owner.decklink_input->StopStreams();
|
||||
if (r == S_OK) {
|
||||
r = owner.decklink_input->EnableVideoInput(
|
||||
mode->GetDisplayMode(), bmdFormat10BitYUV,
|
||||
bmdVideoInputEnableFormatDetection);
|
||||
if (r == S_OK) owner.decklink_input->StartStreams();
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(
|
||||
IDeckLinkVideoInputFrame* video_frame,
|
||||
IDeckLinkAudioInputPacket* audio_packet
|
||||
) override
|
||||
IDeckLinkVideoInputFrame* video_frame,
|
||||
IDeckLinkAudioInputPacket* /*audio_packet*/) override
|
||||
{
|
||||
if (!video_frame) return S_OK;
|
||||
|
||||
// One-time format detection from first frame (only when auto-detection
|
||||
// is OFF — otherwise VideoInputFormatChanged is authoritative).
|
||||
if (!detection_enabled
|
||||
&& !video_info_set.load(std::memory_order_relaxed))
|
||||
{
|
||||
BMDTimeValue frame_time = 0, frame_duration = 0;
|
||||
video_frame->GetStreamTime(&frame_time, &frame_duration, 10000000);
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(video_info_mutex);
|
||||
video_info.width = static_cast<int>(video_frame->GetWidth());
|
||||
video_info.height = static_cast<int>(video_frame->GetHeight());
|
||||
video_info.stride = static_cast<int>(video_frame->GetRowBytes());
|
||||
if (frame_duration > 0) {
|
||||
video_info.fps_num = 10000000;
|
||||
video_info.fps_den = static_cast<int>(frame_duration);
|
||||
int g = std::gcd(video_info.fps_num, video_info.fps_den);
|
||||
if (g > 1) { video_info.fps_num /= g; video_info.fps_den /= g; }
|
||||
}
|
||||
if (video_info.width > 0 && video_info.height > 0 && video_info.fps_num > 0) {
|
||||
video_info_set.store(true, std::memory_order_release);
|
||||
std::lock_guard<std::mutex> flk(format_mutex);
|
||||
format_cv.notify_one();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Always capture the frame
|
||||
IDeckLinkVideoBuffer* buf = nullptr;
|
||||
if (video_frame->QueryInterface(IID_IDeckLinkVideoBuffer, (void**)&buf) != S_OK)
|
||||
return S_OK;
|
||||
|
||||
buf->StartAccess(bmdBufferAccessRead);
|
||||
void* src = nullptr;
|
||||
buf->GetBytes(&src);
|
||||
if (src) {
|
||||
uint32_t row_bytes = static_cast<uint32_t>(video_frame->GetRowBytes());
|
||||
int fw = static_cast<int>(video_frame->GetWidth());
|
||||
int fh = static_cast<int>(video_frame->GetHeight());
|
||||
size_t sz = static_cast<size_t>(row_bytes)
|
||||
* static_cast<size_t>(fh);
|
||||
std::lock_guard<std::mutex> lk(frame_mutex);
|
||||
if (frame_buffer.size() < sz)
|
||||
frame_buffer.resize(sz);
|
||||
std::memcpy(frame_buffer.data(), src, sz);
|
||||
frame_size = sz;
|
||||
frame_row_bytes = row_bytes;
|
||||
frame_width = fw;
|
||||
frame_height = fh;
|
||||
frame_ready.store(true, std::memory_order_release);
|
||||
frame_cv.notify_one();
|
||||
video_frame->GetBytes(&src);
|
||||
if (!src) return S_OK;
|
||||
|
||||
const uint32_t row_bytes = static_cast<uint32_t>(video_frame->GetRowBytes());
|
||||
const int fw = static_cast<int>(video_frame->GetWidth());
|
||||
const int fh = static_cast<int>(video_frame->GetHeight());
|
||||
const size_t sz = static_cast<size_t>(row_bytes) * static_cast<size_t>(fh);
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(owner.mutex);
|
||||
if (owner.frame_buffer.size() < sz) owner.frame_buffer.resize(sz);
|
||||
std::memcpy(owner.frame_buffer.data(), src, sz);
|
||||
owner.frame_row_bytes = row_bytes;
|
||||
owner.frame_width = fw;
|
||||
owner.frame_height = fh;
|
||||
owner.frame_ready = true;
|
||||
}
|
||||
buf->EndAccess(bmdBufferAccessRead);
|
||||
buf->Release();
|
||||
owner.frame_cv.notify_one();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) override
|
||||
{
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE AddRef() override
|
||||
{
|
||||
return ++ref_count;
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE Release() override
|
||||
{
|
||||
return --ref_count; // DeckLinkReceiver destructor owns deletion
|
||||
}
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID*) override { return E_NOINTERFACE; }
|
||||
ULONG STDMETHODCALLTYPE AddRef() override { return ++ref_count; }
|
||||
ULONG STDMETHODCALLTYPE Release() override { return --ref_count; }
|
||||
|
||||
private:
|
||||
dmf::DeckLinkReceiver* decklink_receiver;
|
||||
IDeckLinkInput* deckLink_input = nullptr;
|
||||
std::atomic<int32_t> ref_count;
|
||||
bool detection_enabled = false;
|
||||
std::mutex& format_mutex;
|
||||
std::condition_variable& format_cv;
|
||||
DeckLinkReceiver& owner;
|
||||
std::atomic<int32_t> ref_count{1};
|
||||
};
|
||||
|
||||
std::atomic<bool> video_info_set{false};
|
||||
std::mutex video_info_mutex;
|
||||
std::vector<IDeckLink*> raw_devices;
|
||||
IDeckLink* selected_device = nullptr;
|
||||
IDeckLinkInput* decklink_input = nullptr;
|
||||
InputCallback* input_callback = nullptr;
|
||||
|
||||
void store_format(IDeckLinkDisplayMode* dm, IDeckLinkVideoInputFrame* /*vf*/) {
|
||||
if (!dm) return;
|
||||
std::lock_guard<std::mutex> lk(video_info_mutex);
|
||||
video_info.width = static_cast<int>(dm->GetWidth());
|
||||
video_info.height = static_cast<int>(dm->GetHeight());
|
||||
video_info.stride = video_info.width * 8 / 3; // V210
|
||||
BMDTimeValue dur = 0; BMDTimeScale ts = 0;
|
||||
dm->GetFrameRate(&dur, &ts);
|
||||
if (dur > 0 && ts > 0) {
|
||||
video_info.fps_num = static_cast<int>(ts);
|
||||
video_info.fps_den = static_cast<int>(dur);
|
||||
int g = std::gcd(video_info.fps_num, video_info.fps_den);
|
||||
if (g > 1) { video_info.fps_num /= g; video_info.fps_den /= g; }
|
||||
}
|
||||
if (video_info.width > 0 && video_info.height > 0 && video_info.fps_num > 0) {
|
||||
video_info_set.store(true, std::memory_order_release);
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(format_mutex);
|
||||
format_cv.notify_one();
|
||||
}
|
||||
printf("Format from change: %dx%d @ %d/%d fps stride=%d\n",
|
||||
video_info.width, video_info.height,
|
||||
video_info.fps_num, video_info.fps_den, video_info.stride);
|
||||
}
|
||||
}
|
||||
};
|
||||
std::mutex mutex;
|
||||
std::condition_variable format_cv;
|
||||
std::condition_variable frame_cv;
|
||||
bool format_detected = false;
|
||||
|
||||
struct DeviceInfo {
|
||||
uint32_t index;
|
||||
IDeckLink* device;
|
||||
std::string display_name;
|
||||
};
|
||||
std::vector<uint8_t> frame_buffer;
|
||||
uint32_t frame_row_bytes = 0;
|
||||
int frame_width = 0;
|
||||
int frame_height = 0;
|
||||
bool frame_ready = false;
|
||||
|
||||
class DeckLinkReceiver
|
||||
{
|
||||
public:
|
||||
SourceInfo video_source_info{};
|
||||
std::vector<DeviceInfo> devices_list;
|
||||
void enumerate_devices() {
|
||||
IDeckLinkIterator* it = CreateDeckLinkIteratorInstance();
|
||||
if (!it) throw std::runtime_error("DeckLink drivers not installed");
|
||||
|
||||
DeckLinkReceiver() {
|
||||
selected_device_index = 0;
|
||||
selected_device = nullptr;
|
||||
device_config = nullptr;
|
||||
device_status = nullptr;
|
||||
deckLink_notification = nullptr;
|
||||
// notificationCallback = nullptr;
|
||||
deckLink_input = nullptr;
|
||||
input_callback = nullptr;
|
||||
if (!get_input_device_list()) {
|
||||
throw std::runtime_error("DeckLink devices not found");
|
||||
}
|
||||
}
|
||||
|
||||
~DeckLinkReceiver() {
|
||||
if (input_callback) {
|
||||
if (deckLink_input) deckLink_input->SetCallback(nullptr);
|
||||
delete input_callback;
|
||||
input_callback = nullptr;
|
||||
}
|
||||
// if (m_notificationCallback)
|
||||
// {
|
||||
// m_deckLinkNotification->Unsubscribe(bmdStatusChanged, m_notificationCallback);
|
||||
// m_notificationCallback->Release();
|
||||
// }
|
||||
if (selected_device) selected_device->Release();
|
||||
if (device_config) device_config->Release();
|
||||
if (device_status) device_status->Release();
|
||||
if (deckLink_input) deckLink_input->Release();
|
||||
if (deckLink_notification) deckLink_notification->Release();
|
||||
}
|
||||
|
||||
HRESULT start_capture(uint32_t device_index)
|
||||
{
|
||||
const bool detection = true; // format-detection mode
|
||||
setup(device_index, detection);
|
||||
|
||||
HRESULT result = deckLink_input->EnableVideoInput(
|
||||
bmdModeNTSC, // placeholder; detection will override
|
||||
bmdFormat10BitYUV,
|
||||
bmdVideoInputEnableFormatDetection
|
||||
);
|
||||
if (result != S_OK)
|
||||
{
|
||||
throw std::runtime_error("Could not enable video input");
|
||||
}
|
||||
|
||||
result = deckLink_input->StartStreams();
|
||||
if (result != S_OK)
|
||||
{
|
||||
throw std::runtime_error("Could not start capture");
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
DeckLinkInputCallback* get_input_callback() {
|
||||
return input_callback;
|
||||
}
|
||||
|
||||
IDeckLinkInput* get_input() { return deckLink_input; }
|
||||
|
||||
bool wait_for_format(uint64_t timeout_ms = 5000) {
|
||||
std::unique_lock<std::mutex> lk(mutex);
|
||||
return signal_condition.wait_for(lk, std::chrono::milliseconds(timeout_ms),
|
||||
[this] { return input_callback && input_callback->is_video_info_set(); });
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t selected_device_index = 0;
|
||||
IDeckLink* selected_device = nullptr;
|
||||
IDeckLinkConfiguration* device_config;
|
||||
IDeckLinkStatus* device_status;
|
||||
IDeckLinkNotification* deckLink_notification;
|
||||
// NotificationCallback* m_notificationCallback;
|
||||
IDeckLinkInput* deckLink_input;
|
||||
DeckLinkInputCallback* input_callback;
|
||||
std::mutex mutex;
|
||||
std::condition_variable signal_condition;
|
||||
|
||||
bool get_input_device_list()
|
||||
{
|
||||
IDeckLinkIterator* decklink_iterator = CreateDeckLinkIteratorInstance();
|
||||
if (!decklink_iterator) {
|
||||
throw std::runtime_error("A DeckLink iterator could not be created. The DeckLink drivers may not be installed");
|
||||
return false;
|
||||
}
|
||||
|
||||
IDeckLink* device = nullptr;
|
||||
IDeckLinkInput* input = nullptr;
|
||||
uint32_t index = 0;
|
||||
while (true) {
|
||||
device = nullptr;
|
||||
HRESULT result = decklink_iterator->Next(&device);
|
||||
if (result != S_OK) break;
|
||||
input = nullptr;
|
||||
result = device->QueryInterface(IID_IDeckLinkInput, (void**)&input);
|
||||
if (input) input->Release();
|
||||
if (result != S_OK) { device->Release(); continue; }
|
||||
const char* display_name = nullptr;
|
||||
device->GetDisplayName(&display_name);
|
||||
devices_list.push_back({index, device, std::string(display_name ? display_name : "?")});
|
||||
IDeckLink* device = nullptr;
|
||||
uint32_t index = 0;
|
||||
while (it->Next(&device) == S_OK) {
|
||||
IDeckLinkInput* inp = nullptr;
|
||||
if (device->QueryInterface(IID_IDeckLinkInput, (void**)&inp) == S_OK) {
|
||||
inp->Release();
|
||||
const char* name = nullptr;
|
||||
device->GetDisplayName(&name);
|
||||
devices.push_back({index, name ? name : "?"});
|
||||
raw_devices.push_back(device);
|
||||
index++;
|
||||
} else {
|
||||
device->Release();
|
||||
}
|
||||
if (decklink_iterator) decklink_iterator->Release();
|
||||
return index > 0;
|
||||
}
|
||||
|
||||
HRESULT setup(uint32_t device_index, bool detection_enabled) {
|
||||
selected_device_index = device_index;
|
||||
selected_device = devices_list.at(selected_device_index).device;
|
||||
selected_device->AddRef();
|
||||
|
||||
HRESULT result = selected_device->QueryInterface(IID_IDeckLinkConfiguration, (void**)&device_config);
|
||||
if (result != S_OK) {
|
||||
throw std::runtime_error("Could not obtain the IDeckLinkConfiguration interface");
|
||||
}
|
||||
|
||||
result = selected_device->QueryInterface(IID_IDeckLinkStatus, (void**)&device_status);
|
||||
if (result != S_OK) {
|
||||
throw std::runtime_error("Could not obtain the IDeckLinkStatus interface");
|
||||
}
|
||||
|
||||
result = selected_device->QueryInterface(IID_IDeckLinkInput, (void**)&deckLink_input);
|
||||
if (result != S_OK) {
|
||||
throw std::runtime_error("Could not obtain the IDeckLinkInput interface - result");
|
||||
}
|
||||
|
||||
input_callback = new DeckLinkInputCallback(this, detection_enabled, mutex, signal_condition);
|
||||
if (!input_callback) {
|
||||
throw std::runtime_error("Could not create input callback object");
|
||||
}
|
||||
|
||||
result = deckLink_input->SetCallback(input_callback);
|
||||
if (result != S_OK) {
|
||||
throw std::runtime_error("Could not set input callback - result");
|
||||
}
|
||||
|
||||
input_callback->set_decklink_input(deckLink_input);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
it->Release();
|
||||
if (raw_devices.empty())
|
||||
throw std::runtime_error("No DeckLink input devices found");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace dmf
|
||||
|
||||
Reference in New Issue
Block a user