#else
iter = CreateDeckLinkIteratorInstance();
#endif
- if (!iter)
+ if (!iter) {
av_log(avctx, AV_LOG_ERROR, "Could not create DeckLink iterator. "
"Make sure you have DeckLink drivers " BLACKMAGIC_DECKLINK_API_VERSION_STRING " or newer installed.\n");
+ } else {
+ IDeckLinkAPIInformation *api;
+ int64_t version;
+#ifdef _WIN32
+ if (CoCreateInstance(CLSID_CDeckLinkAPIInformation, NULL, CLSCTX_ALL,
+ IID_IDeckLinkAPIInformation, (void**) &api) != S_OK) {
+ api = NULL;
+ }
+#else
+ api = CreateDeckLinkAPIInformationInstance();
+#endif
+ if (api && api->GetInt(BMDDeckLinkAPIVersion, &version) == S_OK) {
+ if (version < BLACKMAGIC_DECKLINK_API_VERSION)
+ av_log(avctx, AV_LOG_WARNING, "Installed DeckLink drivers are too old and may be incompatible with the SDK this module was built against. "
+ "Make sure you have DeckLink drivers " BLACKMAGIC_DECKLINK_API_VERSION_STRING " or newer installed.\n");
+ } else {
+ av_log(avctx, AV_LOG_ERROR, "Failed to check installed DeckLink API version.\n");
+ }
+ if (api)
+ api->Release();
+ }
return iter;
}
-HRESULT ff_decklink_get_display_name(IDeckLink *This, const char **displayName)
+static int decklink_get_attr_string(IDeckLink *dl, BMDDeckLinkAttributeID cfg_id, const char **s)
{
- DECKLINK_STR tmpDisplayName;
- HRESULT hr = This->GetDisplayName(&tmpDisplayName);
- if (hr != S_OK)
- return hr;
- *displayName = DECKLINK_STRDUP(tmpDisplayName);
- DECKLINK_FREE(tmpDisplayName);
- return hr;
+ DECKLINK_STR tmp;
+ HRESULT hr;
+ IDeckLinkProfileAttributes *attr;
+ *s = NULL;
+ if (dl->QueryInterface(IID_IDeckLinkProfileAttributes, (void **)&attr) != S_OK)
+ return AVERROR_EXTERNAL;
+ hr = attr->GetString(cfg_id, &tmp);
+ attr->Release();
+ if (hr == S_OK) {
+ *s = DECKLINK_STRDUP(tmp);
+ DECKLINK_FREE(tmp);
+ if (!*s)
+ return AVERROR(ENOMEM);
+ } else if (hr == E_FAIL) {
+ return AVERROR_EXTERNAL;
+ }
+ return 0;
}
static int decklink_select_input(AVFormatContext *avctx, BMDDeckLinkConfigurationID cfg_id)
if (ctx->duplex_mode) {
DECKLINK_BOOL duplex_supported = false;
+#if BLACKMAGIC_DECKLINK_API_VERSION >= 0x0b000000
+ IDeckLinkProfileManager *manager = NULL;
+ if (ctx->dl->QueryInterface(IID_IDeckLinkProfileManager, (void **)&manager) == S_OK)
+ duplex_supported = true;
+#else
if (ctx->attr->GetFlag(BMDDeckLinkSupportsDuplexModeConfiguration, &duplex_supported) != S_OK)
duplex_supported = false;
+#endif
if (duplex_supported) {
+#if BLACKMAGIC_DECKLINK_API_VERSION >= 0x0b000000
+ IDeckLinkProfile *profile = NULL;
+ BMDProfileID bmd_profile_id = ctx->duplex_mode == 2 ? bmdProfileOneSubDeviceFullDuplex : bmdProfileTwoSubDevicesHalfDuplex;
+ res = manager->GetProfile(bmd_profile_id, &profile);
+ if (res == S_OK) {
+ res = profile->SetActive();
+ profile->Release();
+ }
+ manager->Release();
+#else
res = ctx->cfg->SetInt(bmdDeckLinkConfigDuplexMode, ctx->duplex_mode == 2 ? bmdDuplexModeFull : bmdDuplexModeHalf);
+#endif
if (res != S_OK)
av_log(avctx, AV_LOG_WARNING, "Setting duplex mode failed.\n");
else
if (ret < 0)
return ret;
}
+ if (direction == DIRECTION_OUT && cctx->timing_offset != INT_MIN) {
+ res = ctx->cfg->SetInt(bmdDeckLinkConfigReferenceInputTimingOffset, cctx->timing_offset);
+ if (res != S_OK)
+ av_log(avctx, AV_LOG_WARNING, "Setting timing offset failed.\n");
+ }
return 0;
}
int width, int height,
int tb_num, int tb_den,
enum AVFieldOrder field_order,
- decklink_direction_t direction, int num)
+ decklink_direction_t direction)
{
struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data;
struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx;
+#if BLACKMAGIC_DECKLINK_API_VERSION >= 0x0b000000
+ DECKLINK_BOOL support;
+#else
BMDDisplayModeSupport support;
+#endif
IDeckLinkDisplayModeIterator *itermode;
IDeckLinkDisplayMode *mode;
int i = 1;
HRESULT res;
- av_log(avctx, AV_LOG_DEBUG, "Trying to find mode for frame size %dx%d, frame timing %d/%d, field order %d, direction %d, mode number %d, format code %s\n",
- width, height, tb_num, tb_den, field_order, direction, num, (cctx->format_code) ? cctx->format_code : "(unset)");
+ av_log(avctx, AV_LOG_DEBUG, "Trying to find mode for frame size %dx%d, frame timing %d/%d, field order %d, direction %d, format code %s\n",
+ width, height, tb_num, tb_den, field_order, direction, cctx->format_code ? cctx->format_code : "(unset)");
if (direction == DIRECTION_IN) {
res = ctx->dli->GetDisplayModeIterator (&itermode);
bmd_height == height &&
!av_cmp_q(mode_tb, target_tb) &&
field_order_eq(field_order, bmd_field_dominance))
- || i == num
|| target_mode == bmd_mode) {
ctx->bmd_mode = bmd_mode;
ctx->bmd_width = bmd_width;
if (ctx->bmd_mode == bmdModeUnknown)
return -1;
+
+#if BLACKMAGIC_DECKLINK_API_VERSION >= 0x0b050000
+ if (direction == DIRECTION_IN) {
+ BMDDisplayMode actualMode = ctx->bmd_mode;
+ if (ctx->dli->DoesSupportVideoMode(ctx->video_input, ctx->bmd_mode, ctx->raw_format,
+ bmdNoVideoInputConversion, bmdSupportedVideoModeDefault,
+ &actualMode, &support) != S_OK || !support || ctx->bmd_mode != actualMode)
+ return -1;
+ } else {
+ BMDDisplayMode actualMode = ctx->bmd_mode;
+ if (ctx->dlo->DoesSupportVideoMode(bmdVideoConnectionUnspecified, ctx->bmd_mode, ctx->raw_format,
+ bmdNoVideoOutputConversion, bmdSupportedVideoModeDefault,
+ &actualMode, &support) != S_OK || !support || ctx->bmd_mode != actualMode)
+ return -1;
+ }
+ return 0;
+#elif BLACKMAGIC_DECKLINK_API_VERSION >= 0x0b000000
+ if (direction == DIRECTION_IN) {
+ if (ctx->dli->DoesSupportVideoMode(ctx->video_input, ctx->bmd_mode, ctx->raw_format,
+ bmdSupportedVideoModeDefault,
+ &support) != S_OK)
+ return -1;
+ } else {
+ BMDDisplayMode actualMode = ctx->bmd_mode;
+ if (ctx->dlo->DoesSupportVideoMode(bmdVideoConnectionUnspecified, ctx->bmd_mode, ctx->raw_format,
+ bmdSupportedVideoModeDefault,
+ &actualMode, &support) != S_OK || !support || ctx->bmd_mode != actualMode) {
+ return -1;
+ }
+
+ }
+ if (support)
+ return 0;
+#else
if (direction == DIRECTION_IN) {
- if (ctx->dli->DoesSupportVideoMode(ctx->bmd_mode, (BMDPixelFormat) cctx->raw_format,
+ if (ctx->dli->DoesSupportVideoMode(ctx->bmd_mode, ctx->raw_format,
bmdVideoOutputFlagDefault,
&support, NULL) != S_OK)
return -1;
} else {
if (!ctx->supports_vanc || ctx->dlo->DoesSupportVideoMode(ctx->bmd_mode, ctx->raw_format,
bmdVideoOutputVANC,
- &support, NULL) != S_OK) {
+ &support, NULL) != S_OK || support != bmdDisplayModeSupported) {
/* Try without VANC enabled */
if (ctx->dlo->DoesSupportVideoMode(ctx->bmd_mode, ctx->raw_format,
bmdVideoOutputFlagDefault,
}
if (support == bmdDisplayModeSupported)
return 0;
+#endif
return -1;
}
-int ff_decklink_set_format(AVFormatContext *avctx, decklink_direction_t direction, int num) {
- return ff_decklink_set_format(avctx, 0, 0, 0, 0, AV_FIELD_UNKNOWN, direction, num);
+int ff_decklink_set_format(AVFormatContext *avctx, decklink_direction_t direction) {
+ return ff_decklink_set_format(avctx, 0, 0, 0, 0, AV_FIELD_UNKNOWN, direction);
}
int ff_decklink_list_devices(AVFormatContext *avctx,
while (ret == 0 && iter->Next(&dl) == S_OK) {
IDeckLinkOutput *output_config;
IDeckLinkInput *input_config;
- const char *displayName;
+ const char *display_name = NULL;
+ const char *unique_name = NULL;
AVDeviceInfo *new_device = NULL;
int add = 0;
- ff_decklink_get_display_name(dl, &displayName);
+ ret = decklink_get_attr_string(dl, BMDDeckLinkDisplayName, &display_name);
+ if (ret < 0)
+ goto next;
+ ret = decklink_get_attr_string(dl, BMDDeckLinkDeviceHandle, &unique_name);
+ if (ret < 0)
+ goto next;
if (show_outputs) {
if (dl->QueryInterface(IID_IDeckLinkOutput, (void **)&output_config) == S_OK) {
goto next;
}
- new_device->device_name = av_strdup(displayName);
- new_device->device_description = av_strdup(displayName);
+ new_device->device_name = av_strdup(unique_name ? unique_name : display_name);
+ new_device->device_description = av_strdup(display_name);
if (!new_device->device_name ||
!new_device->device_description ||
}
next:
- av_freep(&displayName);
+ av_freep(&display_name);
+ av_freep(&unique_name);
dl->Release();
}
iter->Release();
av_log(avctx, AV_LOG_INFO, "Blackmagic DeckLink %s devices:\n",
show_inputs ? "input" : "output");
for (int i = 0; i < device_list->nb_devices; i++) {
- av_log(avctx, AV_LOG_INFO, "\t'%s'\n", device_list->devices[i]->device_name);
+ av_log(avctx, AV_LOG_INFO, "\t'%s'\n", device_list->devices[i]->device_description);
}
}
avdevice_free_list_devices(&device_list);
return AVERROR_EXTERNAL;
while (iter->Next(&dl) == S_OK) {
- const char *displayName;
- ff_decklink_get_display_name(dl, &displayName);
- if (!strcmp(name, displayName)) {
- av_free((void *)displayName);
+ const char *display_name = NULL;
+ const char *unique_name = NULL;
+ decklink_get_attr_string(dl, BMDDeckLinkDisplayName, &display_name);
+ decklink_get_attr_string(dl, BMDDeckLinkDeviceHandle, &unique_name);
+ if (display_name && !strcmp(name, display_name) || unique_name && !strcmp(name, unique_name)) {
+ av_free((void *)unique_name);
+ av_free((void *)display_name);
ctx->dl = dl;
break;
}
- av_free((void *)displayName);
+ av_free((void *)display_name);
+ av_free((void *)unique_name);
dl->Release();
}
iter->Release();
return AVERROR_EXTERNAL;
}
- if (ctx->dl->QueryInterface(IID_IDeckLinkAttributes, (void **)&ctx->attr) != S_OK) {
+ if (ctx->dl->QueryInterface(IID_IDeckLinkProfileAttributes, (void **)&ctx->attr) != S_OK) {
av_log(avctx, AV_LOG_ERROR, "Could not get attributes interface for '%s'\n", name);
ff_decklink_cleanup(avctx);
return AVERROR_EXTERNAL;