avdevice/decklink_dec: Used av_parity instead of duplicated function
[ffmpeg.git] / libavdevice / decklink_common.cpp
index bd5ab91..ff2df95 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+/* Include internal.h first to avoid conflict between winsock.h (used by
+ * DeckLink headers) and winsock2.h (used by libavformat) in MSVC++ builds */
+extern "C" {
+#include "libavformat/internal.h"
+}
+
 #include <DeckLinkAPI.h>
 #ifdef _WIN32
 #include <DeckLinkAPI_i.c>
 #include <DeckLinkAPIDispatch.cpp>
 #endif
 
-#include <pthread.h>
-#include <semaphore.h>
-
 extern "C" {
 #include "libavformat/avformat.h"
-#include "libavformat/internal.h"
 #include "libavutil/imgutils.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/bswap.h"
 }
 
 #include "decklink_common.h"
@@ -103,7 +107,7 @@ HRESULT ff_decklink_get_display_name(IDeckLink *This, const char **displayName)
 
 static int decklink_select_input(AVFormatContext *avctx, BMDDeckLinkConfigurationID cfg_id)
 {
-    struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
+    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;
@@ -130,12 +134,26 @@ static int decklink_select_input(AVFormatContext *avctx, BMDDeckLinkConfiguratio
     return 0;
 }
 
+static DECKLINK_BOOL field_order_eq(enum AVFieldOrder field_order, BMDFieldDominance bmd_field_order)
+{
+    if (field_order == AV_FIELD_UNKNOWN)
+        return true;
+    if ((field_order == AV_FIELD_TT || field_order == AV_FIELD_TB) && bmd_field_order == bmdUpperFieldFirst)
+        return true;
+    if ((field_order == AV_FIELD_BB || field_order == AV_FIELD_BT) && bmd_field_order == bmdLowerFieldFirst)
+        return true;
+    if (field_order == AV_FIELD_PROGRESSIVE && (bmd_field_order == bmdProgressiveFrame || bmd_field_order == bmdProgressiveSegmentedFrame))
+        return true;
+    return false;
+}
+
 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)
 {
-    struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
+    struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data;
     struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx;
     BMDDisplayModeSupport support;
     IDeckLinkDisplayModeIterator *itermode;
@@ -143,6 +161,9 @@ int ff_decklink_set_format(AVFormatContext *avctx,
     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)");
+
     if (ctx->duplex_mode) {
         DECKLINK_BOOL duplex_supported = false;
 
@@ -154,7 +175,7 @@ int ff_decklink_set_format(AVFormatContext *avctx,
             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");
+                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");
         }
@@ -178,29 +199,36 @@ int ff_decklink_set_format(AVFormatContext *avctx,
             return AVERROR(EIO);
     }
 
-
-    if (tb_num == 1) {
-        tb_num *= 1000;
-        tb_den *= 1000;
-    }
+    char format_buf[] = "    ";
+    if (cctx->format_code)
+        memcpy(format_buf, cctx->format_code, FFMIN(strlen(cctx->format_code), sizeof(format_buf)));
+    BMDDisplayMode target_mode = (BMDDisplayMode)AV_RB32(format_buf);
+    AVRational target_tb = av_make_q(tb_num, tb_den);
     ctx->bmd_mode = bmdModeUnknown;
     while ((ctx->bmd_mode == bmdModeUnknown) && itermode->Next(&mode) == S_OK) {
         BMDTimeValue bmd_tb_num, bmd_tb_den;
         int bmd_width  = mode->GetWidth();
         int bmd_height = mode->GetHeight();
+        BMDDisplayMode bmd_mode = mode->GetDisplayMode();
+        BMDFieldDominance bmd_field_dominance = mode->GetFieldDominance();
 
         mode->GetFrameRate(&bmd_tb_num, &bmd_tb_den);
-
-        if ((bmd_width == width && bmd_height == height &&
-            bmd_tb_num == tb_num && bmd_tb_den == tb_den) || i == num) {
-            ctx->bmd_mode   = mode->GetDisplayMode();
+        AVRational mode_tb = av_make_q(bmd_tb_num, bmd_tb_den);
+
+        if ((bmd_width == width &&
+             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;
             ctx->bmd_height = bmd_height;
             ctx->bmd_tb_den = bmd_tb_den;
             ctx->bmd_tb_num = bmd_tb_num;
-            ctx->bmd_field_dominance = mode->GetFieldDominance();
+            ctx->bmd_field_dominance = bmd_field_dominance;
             av_log(avctx, AV_LOG_INFO, "Found Decklink mode %d x %d with rate %.2f%s\n",
-                bmd_width, bmd_height, (float)bmd_tb_den/(float)bmd_tb_num,
+                bmd_width, bmd_height, 1/av_q2d(mode_tb),
                 (ctx->bmd_field_dominance==bmdLowerFieldFirst || ctx->bmd_field_dominance==bmdUpperFieldFirst)?"(i)":"");
         }
 
@@ -213,7 +241,7 @@ int ff_decklink_set_format(AVFormatContext *avctx,
     if (ctx->bmd_mode == bmdModeUnknown)
         return -1;
     if (direction == DIRECTION_IN) {
-        if (ctx->dli->DoesSupportVideoMode(ctx->bmd_mode, bmdFormat8BitYUV,
+        if (ctx->dli->DoesSupportVideoMode(ctx->bmd_mode, (BMDPixelFormat) cctx->raw_format,
                                            bmdVideoOutputFlagDefault,
                                            &support, NULL) != S_OK)
             return -1;
@@ -230,7 +258,7 @@ int ff_decklink_set_format(AVFormatContext *avctx,
 }
 
 int ff_decklink_set_format(AVFormatContext *avctx, decklink_direction_t direction, int num) {
-    return ff_decklink_set_format(avctx, 0, 0, 0, 0, direction, num);
+    return ff_decklink_set_format(avctx, 0, 0, 0, 0, AV_FIELD_UNKNOWN, direction, num);
 }
 
 int ff_decklink_list_devices(AVFormatContext *avctx)
@@ -255,11 +283,11 @@ int ff_decklink_list_devices(AVFormatContext *avctx)
 
 int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t direction)
 {
-    struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
+    struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data;
     struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx;
     IDeckLinkDisplayModeIterator *itermode;
     IDeckLinkDisplayMode *mode;
-    int i=0;
+    uint32_t format_code;
     HRESULT res;
 
     if (direction == DIRECTION_IN) {
@@ -280,13 +308,14 @@ int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t direct
             return AVERROR(EIO);
     }
 
-    av_log(avctx, AV_LOG_INFO, "Supported formats for '%s':\n",
+    av_log(avctx, AV_LOG_INFO, "Supported formats for '%s':\n\tformat_code\tdescription",
                avctx->filename);
     while (itermode->Next(&mode) == S_OK) {
         BMDTimeValue tb_num, tb_den;
         mode->GetFrameRate(&tb_num, &tb_den);
-        av_log(avctx, AV_LOG_INFO, "\t%d\t%ldx%ld at %d/%d fps",
-                ++i,mode->GetWidth(), mode->GetHeight(),
+        format_code = av_bswap32(mode->GetDisplayMode());
+        av_log(avctx, AV_LOG_INFO, "\n\t%.4s\t\t%ldx%ld at %d/%d fps",
+                (char*) &format_code, mode->GetWidth(), mode->GetHeight(),
                 (int) tb_den, (int) tb_num);
         switch (mode->GetFieldDominance()) {
         case bmdLowerFieldFirst:
@@ -294,9 +323,9 @@ int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t direct
         case bmdUpperFieldFirst:
         av_log(avctx, AV_LOG_INFO, " (interlaced, upper field first)"); break;
         }
-        av_log(avctx, AV_LOG_INFO, "\n");
         mode->Release();
     }
+    av_log(avctx, AV_LOG_INFO, "\n");
 
     itermode->Release();
 
@@ -305,8 +334,8 @@ int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t direct
 
 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;
+    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();