]> git.sesse.net Git - ffmpeg/blobdiff - libavdevice/decklink_common.cpp
diracdec: rewrite HQ slice decoding
[ffmpeg] / libavdevice / decklink_common.cpp
index ac7964cd171eba58baa44e8b6b30d04d0c3b22ae..b0f245fedb6c5b1479ba092f6b611980ac190e83 100644 (file)
@@ -70,6 +70,7 @@ static char *dup_wchar_to_utf8(wchar_t *w)
 #define DECKLINK_STR    OLECHAR *
 #define DECKLINK_STRDUP dup_wchar_to_utf8
 #define DECKLINK_FREE(s) SysFreeString(s)
+#define DECKLINK_BOOL BOOL
 #elif defined(__APPLE__)
 static char *dup_cfstring_to_utf8(CFStringRef w)
 {
@@ -80,11 +81,13 @@ static char *dup_cfstring_to_utf8(CFStringRef w)
 #define DECKLINK_STR    const __CFString *
 #define DECKLINK_STRDUP dup_cfstring_to_utf8
 #define DECKLINK_FREE(s) free((void *) s)
+#define DECKLINK_BOOL bool
 #else
 #define DECKLINK_STR    const char *
 #define DECKLINK_STRDUP av_strdup
 /* free() is needed for a string returned by the DeckLink SDL. */
 #define DECKLINK_FREE(s) free((void *) s)
+#define DECKLINK_BOOL bool
 #endif
 
 HRESULT ff_decklink_get_display_name(IDeckLink *This, const char **displayName)
@@ -98,6 +101,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) ? (int64_t)ctx->audio_input : (int64_t)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 +143,31 @@ int ff_decklink_set_format(AVFormatContext *avctx,
     int i = 1;
     HRESULT res;
 
+    if (ctx->duplex_mode) {
+        DECKLINK_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, "Successfully 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 +263,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 +302,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;
+}