X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavdevice%2Fdecklink_common.cpp;h=362567341edca24fdcff95d769b80801ed11a235;hb=da89c6e37cf2fb3645611e8196cc28b6acfb9bd6;hp=ac7964cd171eba58baa44e8b6b30d04d0c3b22ae;hpb=abb3cc46d595dcb186ae30ec7339a56cd9803f45;p=ffmpeg diff --git a/libavdevice/decklink_common.cpp b/libavdevice/decklink_common.cpp index ac7964cd171..362567341ed 100644 --- a/libavdevice/decklink_common.cpp +++ b/libavdevice/decklink_common.cpp @@ -98,6 +98,35 @@ HRESULT ff_decklink_get_display_name(IDeckLink *This, const char **displayName) return hr; } +static int decklink_select_input(AVFormatContext *avctx, BMDDeckLinkConfigurationID cfg_id) +{ + struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data; + struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx; + BMDDeckLinkAttributeID attr_id = (cfg_id == bmdDeckLinkConfigAudioInputConnection) ? BMDDeckLinkAudioInputConnections : BMDDeckLinkVideoInputConnections; + int64_t bmd_input = (cfg_id == bmdDeckLinkConfigAudioInputConnection) ? ctx->audio_input : ctx->video_input; + const char *type_name = (cfg_id == bmdDeckLinkConfigAudioInputConnection) ? "audio" : "video"; + int64_t supported_connections = 0; + HRESULT res; + + if (bmd_input) { + res = ctx->attr->GetInt(attr_id, &supported_connections); + if (res != S_OK) { + av_log(avctx, AV_LOG_ERROR, "Failed to query supported %s inputs.\n", type_name); + return AVERROR_EXTERNAL; + } + if ((supported_connections & bmd_input) != bmd_input) { + av_log(avctx, AV_LOG_ERROR, "Device does not support selected %s input.\n", type_name); + return AVERROR(ENOSYS); + } + res = ctx->cfg->SetInt(cfg_id, bmd_input); + if (res != S_OK) { + av_log(avctx, AV_LOG_ERROR, "Failed to select %s input.\n", type_name); + return AVERROR_EXTERNAL; + } + } + return 0; +} + int ff_decklink_set_format(AVFormatContext *avctx, int width, int height, int tb_num, int tb_den, @@ -111,7 +140,31 @@ int ff_decklink_set_format(AVFormatContext *avctx, int i = 1; HRESULT res; + if (ctx->duplex_mode) { + bool duplex_supported = false; + + if (ctx->attr->GetFlag(BMDDeckLinkSupportsDuplexModeConfiguration, &duplex_supported) != S_OK) + duplex_supported = false; + + if (duplex_supported) { + res = ctx->cfg->SetInt(bmdDeckLinkConfigDuplexMode, ctx->duplex_mode == 2 ? bmdDuplexModeFull : bmdDuplexModeHalf); + if (res != S_OK) + av_log(avctx, AV_LOG_WARNING, "Setting duplex mode failed.\n"); + else + av_log(avctx, AV_LOG_VERBOSE, "Succesfully set duplex mode to %s duplex.\n", ctx->duplex_mode == 2 ? "full" : "half"); + } else { + av_log(avctx, AV_LOG_WARNING, "Unable to set duplex mode, because it is not supported.\n"); + } + } + if (direction == DIRECTION_IN) { + int ret; + ret = decklink_select_input(avctx, bmdDeckLinkConfigAudioInputConnection); + if (ret < 0) + return ret; + ret = decklink_select_input(avctx, bmdDeckLinkConfigVideoInputConnection); + if (ret < 0) + return ret; res = ctx->dli->GetDisplayModeIterator (&itermode); } else { res = ctx->dlo->GetDisplayModeIterator (&itermode); @@ -207,6 +260,13 @@ int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t direct HRESULT res; if (direction == DIRECTION_IN) { + int ret; + ret = decklink_select_input(avctx, bmdDeckLinkConfigAudioInputConnection); + if (ret < 0) + return ret; + ret = decklink_select_input(avctx, bmdDeckLinkConfigVideoInputConnection); + if (ret < 0) + return ret; res = ctx->dli->GetDisplayModeIterator (&itermode); } else { res = ctx->dlo->GetDisplayModeIterator (&itermode); @@ -239,3 +299,61 @@ int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t direct return 0; } + +void ff_decklink_cleanup(AVFormatContext *avctx) +{ + struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data; + struct decklink_ctx *ctx = (struct decklink_ctx *) cctx->ctx; + + if (ctx->dli) + ctx->dli->Release(); + if (ctx->dlo) + ctx->dlo->Release(); + if (ctx->attr) + ctx->attr->Release(); + if (ctx->cfg) + ctx->cfg->Release(); + if (ctx->dl) + ctx->dl->Release(); +} + +int ff_decklink_init_device(AVFormatContext *avctx, const char* name) +{ + struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data; + struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx; + IDeckLink *dl = NULL; + IDeckLinkIterator *iter = CreateDeckLinkIteratorInstance(); + if (!iter) { + av_log(avctx, AV_LOG_ERROR, "Could not create DeckLink iterator\n"); + 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); + ctx->dl = dl; + break; + } + av_free((void *)displayName); + dl->Release(); + } + iter->Release(); + if (!ctx->dl) + return AVERROR(ENXIO); + + if (ctx->dl->QueryInterface(IID_IDeckLinkConfiguration, (void **)&ctx->cfg) != S_OK) { + av_log(avctx, AV_LOG_ERROR, "Could not get configuration interface for '%s'\n", name); + ff_decklink_cleanup(avctx); + return AVERROR_EXTERNAL; + } + + if (ctx->dl->QueryInterface(IID_IDeckLinkAttributes, (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; + } + + return 0; +}