]> git.sesse.net Git - ffmpeg/blobdiff - libavdevice/decklink_common.cpp
avdevice/opengl: add support of wrapped avframe codec
[ffmpeg] / libavdevice / decklink_common.cpp
index 503417bb3539d86167654a9ddc7d1a171fe73a93..53b57ffe4e256bbd904a5dee81505f51e9124a63 100644 (file)
@@ -77,15 +77,25 @@ static IDeckLinkIterator *decklink_create_iterator(AVFormatContext *avctx)
     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)
@@ -139,11 +149,28 @@ int ff_decklink_set_configs(AVFormatContext *avctx,
     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
@@ -161,6 +188,11 @@ int ff_decklink_set_configs(AVFormatContext *avctx,
         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;
 }
 
@@ -168,18 +200,22 @@ int ff_decklink_set_format(AVFormatContext *avctx,
                                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);
@@ -212,7 +248,6 @@ int ff_decklink_set_format(AVFormatContext *avctx,
              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;
@@ -233,6 +268,40 @@ int ff_decklink_set_format(AVFormatContext *avctx,
 
     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, (BMDPixelFormat) cctx->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, (BMDPixelFormat) cctx->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,
                                            bmdVideoOutputFlagDefault,
@@ -241,7 +310,7 @@ int ff_decklink_set_format(AVFormatContext *avctx,
     } 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,
@@ -254,12 +323,13 @@ int ff_decklink_set_format(AVFormatContext *avctx,
     }
     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,
@@ -276,11 +346,17 @@ 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) {
@@ -303,8 +379,8 @@ int ff_decklink_list_devices(AVFormatContext *avctx,
                 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 ||
@@ -318,7 +394,8 @@ int ff_decklink_list_devices(AVFormatContext *avctx,
         }
 
     next:
-        av_freep(&displayName);
+        av_freep(&display_name);
+        av_freep(&unique_name);
         dl->Release();
     }
     iter->Release();
@@ -343,7 +420,7 @@ void ff_decklink_list_devices_legacy(AVFormatContext *avctx,
         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);
@@ -427,14 +504,18 @@ int ff_decklink_init_device(AVFormatContext *avctx, const char* name)
         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();
@@ -447,7 +528,7 @@ int ff_decklink_init_device(AVFormatContext *avctx, const char* name)
         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;