PR #21029 opened by Thomas Gritzan (Phygon) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21029 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21029.patch
This patch adds support for DeckLink SDK 14.3 and newer by using the legacy interfaces in the header <DeckLinkAPI_v14_2_1.h>. The missing QueryInterface implementations are also provided. >From 5e59f62d266d5be1d5d0a79e920b3f0065711ce5 Mon Sep 17 00:00:00 2001 From: Thomas Gritzan <[email protected]> Date: Thu, 27 Nov 2025 02:30:25 +0100 Subject: [PATCH] libavdevice/decklink: add support for DeckLink SDK 14.3 This patch adds support for DeckLink SDK 14.3 and newer by using the legacy interfaces in the header <DeckLinkAPI_v14_2_1.h>. The missing QueryInterface implementations are also provided. --- configure | 4 +-- libavdevice/decklink_common.cpp | 24 +++++++++++--- libavdevice/decklink_common.h | 23 ++++++++++++-- libavdevice/decklink_dec.cpp | 55 ++++++++++++++++++++++++++------- libavdevice/decklink_enc.cpp | 44 +++++++++++++++++++++----- 5 files changed, 123 insertions(+), 27 deletions(-) diff --git a/configure b/configure index 99734e9d03..55ba414302 100755 --- a/configure +++ b/configure @@ -7400,8 +7400,8 @@ fi if enabled decklink; then case $target_os in mingw32*|mingw64*|win32|win64) - decklink_outdev_extralibs="$decklink_outdev_extralibs -lole32 -loleaut32" - decklink_indev_extralibs="$decklink_indev_extralibs -lole32 -loleaut32" + decklink_outdev_extralibs="$decklink_outdev_extralibs -lole32 -luuid -loleaut32" + decklink_indev_extralibs="$decklink_indev_extralibs -lole32 -luuid -loleaut32" ;; esac fi diff --git a/libavdevice/decklink_common.cpp b/libavdevice/decklink_common.cpp index 47de7ef6b0..51919a3501 100644 --- a/libavdevice/decklink_common.cpp +++ b/libavdevice/decklink_common.cpp @@ -25,8 +25,14 @@ extern "C" { #include "libavformat/internal.h" } +#include <DeckLinkAPIVersion.h> #include <DeckLinkAPI.h> +#if BLACKMAGIC_DECKLINK_API_VERSION >= 0x0e030000 +#include <DeckLinkAPI_v14_2_1.h> +#endif + #ifdef _WIN32 +#include <guiddef.h> #include <DeckLinkAPI_i.c> #else /* The file provided by the SDK is known to be missing prototypes, which doesn't @@ -512,8 +518,8 @@ int ff_decklink_list_devices(AVFormatContext *avctx, return AVERROR(EIO); while (ret == 0 && iter->Next(&dl) == S_OK) { - IDeckLinkOutput *output_config; - IDeckLinkInput *input_config; + IDeckLinkOutput_v14_2_1 *output_config; + IDeckLinkInput_v14_2_1 *input_config; const char *display_name = NULL; const char *unique_name = NULL; AVDeviceInfo *new_device = NULL; @@ -527,14 +533,14 @@ int ff_decklink_list_devices(AVFormatContext *avctx, goto next; if (show_outputs) { - if (dl->QueryInterface(IID_IDeckLinkOutput, (void **)&output_config) == S_OK) { + if (dl->QueryInterface(IID_IDeckLinkOutput_v14_2_1, (void **)&output_config) == S_OK) { output_config->Release(); add = 1; } } if (show_inputs) { - if (dl->QueryInterface(IID_IDeckLinkInput, (void **)&input_config) == S_OK) { + if (dl->QueryInterface(IID_IDeckLinkInput_v14_2_1, (void **)&input_config) == S_OK) { input_config->Release(); add = 1; } @@ -704,3 +710,13 @@ int ff_decklink_init_device(AVFormatContext *avctx, const char* name) return 0; } + +bool ff_decklink_equal_iid(const REFIID& riid1, const REFIID& riid2) +{ +#ifdef _WIN32 + return IsEqualIID(riid1, riid2); +#else + /* There is no guiddef.h in Linux builds, so we cannot use IsEqualIID() */ + return memcmp(&riid1, &riid2, sizeof(REFIID)) == 0; +#endif +} diff --git a/libavdevice/decklink_common.h b/libavdevice/decklink_common.h index 6b32dc2d09..c05a93a340 100644 --- a/libavdevice/decklink_common.h +++ b/libavdevice/decklink_common.h @@ -29,6 +29,23 @@ #define IDeckLinkProfileAttributes IDeckLinkAttributes #endif +#if BLACKMAGIC_DECKLINK_API_VERSION < 0x0e030000 +#define IDeckLinkInput_v14_2_1 IDeckLinkInput +#define IDeckLinkInputCallback_v14_2_1 IDeckLinkInputCallback +#define IDeckLinkMemoryAllocator_v14_2_1 IDeckLinkMemoryAllocator +#define IDeckLinkOutput_v14_2_1 IDeckLinkOutput +#define IDeckLinkVideoFrame_v14_2_1 IDeckLinkVideoFrame +#define IDeckLinkVideoInputFrame_v14_2_1 IDeckLinkVideoInputFrame +#define IDeckLinkVideoOutputCallback_v14_2_1 IDeckLinkVideoOutputCallback +#define IID_IDeckLinkInput_v14_2_1 IID_IDeckLinkInput +#define IID_IDeckLinkInputCallback_v14_2_1 IID_IDeckLinkInputCallback +#define IID_IDeckLinkMemoryAllocator_v14_2_1 IID_IDeckLinkMemoryAllocator +#define IID_IDeckLinkOutput_v14_2_1 IID_IDeckLinkOutput +#define IID_IDeckLinkVideoFrame_v14_2_1 IID_IDeckLinkVideoFrame +#define IID_IDeckLinkVideoInputFrame_v14_2_1 IID_IDeckLinkVideoInputFrame +#define IID_IDeckLinkVideoOutputCallback_v14_2_1 IID_IDeckLinkVideoOutputCallback +#endif + extern "C" { #include "libavutil/mem.h" #include "libavcodec/packet_internal.h" @@ -93,8 +110,8 @@ typedef struct DecklinkPacketQueue { struct decklink_ctx { /* DeckLink SDK interfaces */ IDeckLink *dl; - IDeckLinkOutput *dlo; - IDeckLinkInput *dli; + IDeckLinkOutput_v14_2_1 *dlo; + IDeckLinkInput_v14_2_1 *dli; IDeckLinkConfiguration *cfg; IDeckLinkProfileAttributes *attr; decklink_output_callback *output_callback; @@ -248,4 +265,6 @@ int ff_decklink_packet_queue_put(DecklinkPacketQueue *q, AVPacket *pkt); int ff_decklink_packet_queue_get(DecklinkPacketQueue *q, AVPacket *pkt, int block); int64_t ff_decklink_packet_queue_peekpts(DecklinkPacketQueue *q); +bool ff_decklink_equal_iid(const REFIID& riid1, const REFIID& riid2); + #endif /* AVDEVICE_DECKLINK_COMMON_H */ diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp index 418701e4e0..8c5a4ff895 100644 --- a/libavdevice/decklink_dec.cpp +++ b/libavdevice/decklink_dec.cpp @@ -31,7 +31,11 @@ extern "C" { #include "libavformat/internal.h" } +#include <DeckLinkAPIVersion.h> #include <DeckLinkAPI.h> +#if BLACKMAGIC_DECKLINK_API_VERSION >= 0x0e030000 +#include <DeckLinkAPI_v14_2_1.h> +#endif extern "C" { #include "config.h" @@ -105,7 +109,7 @@ static VANCLineNumber vanc_line_numbers[] = { {bmdModeUnknown, 0, -1, -1, -1} }; -class decklink_allocator : public IDeckLinkMemoryAllocator +class decklink_allocator : public IDeckLinkMemoryAllocator_v14_2_1 { public: decklink_allocator(): _refs(1) { } @@ -129,7 +133,21 @@ public: virtual HRESULT STDMETHODCALLTYPE Decommit() { return S_OK; } // IUnknown methods - virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; } + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID *ppv) + { + if (ff_decklink_equal_iid(riid, IID_IUnknown)) { + *ppv = static_cast<IUnknown*>(this); + } else if (ff_decklink_equal_iid(riid, IID_IDeckLinkMemoryAllocator_v14_2_1)) { + *ppv = static_cast<IDeckLinkMemoryAllocator_v14_2_1*>(this); + } else { + *ppv = NULL; + return E_NOINTERFACE; + } + + AddRef(); + return S_OK; + } + virtual ULONG STDMETHODCALLTYPE AddRef(void) { return ++_refs; } virtual ULONG STDMETHODCALLTYPE Release(void) { @@ -472,7 +490,7 @@ skip_packet: } -static void handle_klv(AVFormatContext *avctx, decklink_ctx *ctx, IDeckLinkVideoInputFrame *videoFrame, int64_t pts) +static void handle_klv(AVFormatContext *avctx, decklink_ctx *ctx, IDeckLinkVideoInputFrame_v14_2_1 *videoFrame, int64_t pts) { const uint8_t KLV_DID = 0x44; const uint8_t KLV_IN_VANC_SDID = 0x04; @@ -574,17 +592,30 @@ static void handle_klv(AVFormatContext *avctx, decklink_ctx *ctx, IDeckLinkVideo } } -class decklink_input_callback : public IDeckLinkInputCallback +class decklink_input_callback : public IDeckLinkInputCallback_v14_2_1 { public: explicit decklink_input_callback(AVFormatContext *_avctx); ~decklink_input_callback(); - virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; } + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID *ppv) + { + if (ff_decklink_equal_iid(riid, IID_IUnknown)) { + *ppv = static_cast<IUnknown*>(this); + } else if (ff_decklink_equal_iid(riid, IID_IDeckLinkInputCallback_v14_2_1)) { + *ppv = static_cast<IDeckLinkInputCallback_v14_2_1*>(this); + } else { + *ppv = NULL; + return E_NOINTERFACE; + } + + AddRef(); + return S_OK; + } virtual ULONG STDMETHODCALLTYPE AddRef(void); virtual ULONG STDMETHODCALLTYPE Release(void); virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(BMDVideoInputFormatChangedEvents, IDeckLinkDisplayMode*, BMDDetectedVideoInputFormatFlags); - virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame*, IDeckLinkAudioInputPacket*); + virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame_v14_2_1*, IDeckLinkAudioInputPacket*); private: std::atomic<int> _refs; @@ -593,7 +624,7 @@ private: int no_video; int64_t initial_video_pts; int64_t initial_audio_pts; - IDeckLinkVideoInputFrame* last_video_frame; + IDeckLinkVideoInputFrame_v14_2_1* last_video_frame; }; decklink_input_callback::decklink_input_callback(AVFormatContext *_avctx) : _refs(1) @@ -625,7 +656,7 @@ ULONG decklink_input_callback::Release(void) return ret; } -static int64_t get_pkt_pts(IDeckLinkVideoInputFrame *videoFrame, +static int64_t get_pkt_pts(IDeckLinkVideoInputFrame_v14_2_1 *videoFrame, IDeckLinkAudioInputPacket *audioFrame, int64_t wallclock, int64_t abs_wallclock, @@ -679,7 +710,7 @@ static int64_t get_pkt_pts(IDeckLinkVideoInputFrame *videoFrame, return pts; } -static int get_bmd_timecode(AVFormatContext *avctx, AVTimecode *tc, AVRational frame_rate, BMDTimecodeFormat tc_format, IDeckLinkVideoInputFrame *videoFrame) +static int get_bmd_timecode(AVFormatContext *avctx, AVTimecode *tc, AVRational frame_rate, BMDTimecodeFormat tc_format, IDeckLinkVideoInputFrame_v14_2_1 *videoFrame) { IDeckLinkTimecode *timecode; int ret = AVERROR(ENOENT); @@ -701,7 +732,7 @@ static int get_bmd_timecode(AVFormatContext *avctx, AVTimecode *tc, AVRational f return ret; } -static int get_frame_timecode(AVFormatContext *avctx, decklink_ctx *ctx, AVTimecode *tc, IDeckLinkVideoInputFrame *videoFrame) +static int get_frame_timecode(AVFormatContext *avctx, decklink_ctx *ctx, AVTimecode *tc, IDeckLinkVideoInputFrame_v14_2_1 *videoFrame) { AVRational frame_rate = ctx->video_st->r_frame_rate; int ret; @@ -726,7 +757,7 @@ static int get_frame_timecode(AVFormatContext *avctx, decklink_ctx *ctx, AVTimec } HRESULT decklink_input_callback::VideoInputFrameArrived( - IDeckLinkVideoInputFrame *videoFrame, IDeckLinkAudioInputPacket *audioFrame) + IDeckLinkVideoInputFrame_v14_2_1 *videoFrame, IDeckLinkAudioInputPacket *audioFrame) { void *frameBytes; void *audioFrameBytes; @@ -1141,7 +1172,7 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) goto error; /* Get input device. */ - if (ctx->dl->QueryInterface(IID_IDeckLinkInput, (void **) &ctx->dli) != S_OK) { + if (ctx->dl->QueryInterface(IID_IDeckLinkInput_v14_2_1, (void **) &ctx->dli) != S_OK) { av_log(avctx, AV_LOG_ERROR, "Could not open input device from '%s'\n", avctx->url); ret = AVERROR(EIO); diff --git a/libavdevice/decklink_enc.cpp b/libavdevice/decklink_enc.cpp index cb8f91730e..a898c25db2 100644 --- a/libavdevice/decklink_enc.cpp +++ b/libavdevice/decklink_enc.cpp @@ -28,7 +28,11 @@ extern "C" { #include "libavformat/internal.h" } +#include <DeckLinkAPIVersion.h> #include <DeckLinkAPI.h> +#if BLACKMAGIC_DECKLINK_API_VERSION >= 0x0e030000 +#include <DeckLinkAPI_v14_2_1.h> +#endif extern "C" { #include "libavformat/avformat.h" @@ -48,7 +52,7 @@ extern "C" { #endif /* DeckLink callback class declaration */ -class decklink_frame : public IDeckLinkVideoFrame +class decklink_frame : public IDeckLinkVideoFrame_v14_2_1 { public: decklink_frame(struct decklink_ctx *ctx, AVFrame *avframe, AVCodecID codec_id, int height, int width) : @@ -111,7 +115,20 @@ public: _ancillary->AddRef(); return S_OK; } - virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; } + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID *ppv) + { + if (ff_decklink_equal_iid(riid, IID_IUnknown)) { + *ppv = static_cast<IUnknown*>(this); + } else if (ff_decklink_equal_iid(riid, IID_IDeckLinkVideoFrame_v14_2_1)) { + *ppv = static_cast<IDeckLinkVideoFrame_v14_2_1*>(this); + } else { + *ppv = NULL; + return E_NOINTERFACE; + } + + AddRef(); + return S_OK; + } virtual ULONG STDMETHODCALLTYPE AddRef(void) { return ++_refs; } virtual ULONG STDMETHODCALLTYPE Release(void) { @@ -138,10 +155,10 @@ private: std::atomic<int> _refs; }; -class decklink_output_callback : public IDeckLinkVideoOutputCallback +class decklink_output_callback : public IDeckLinkVideoOutputCallback_v14_2_1 { public: - virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted(IDeckLinkVideoFrame *_frame, BMDOutputFrameCompletionResult result) + virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted(IDeckLinkVideoFrame_v14_2_1 *_frame, BMDOutputFrameCompletionResult result) { decklink_frame *frame = static_cast<decklink_frame *>(_frame); struct decklink_ctx *ctx = frame->_ctx; @@ -159,7 +176,20 @@ public: return S_OK; } virtual HRESULT STDMETHODCALLTYPE ScheduledPlaybackHasStopped(void) { return S_OK; } - virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; } + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID *ppv) + { + if (ff_decklink_equal_iid(riid, IID_IUnknown)) { + *ppv = static_cast<IUnknown*>(this); + } else if (ff_decklink_equal_iid(riid, IID_IDeckLinkVideoOutputCallback_v14_2_1)) { + *ppv = static_cast<IDeckLinkVideoOutputCallback_v14_2_1*>(this); + } else { + *ppv = NULL; + return E_NOINTERFACE; + } + + AddRef(); + return S_OK; + } virtual ULONG STDMETHODCALLTYPE AddRef(void) { return 1; } virtual ULONG STDMETHODCALLTYPE Release(void) { return 1; } }; @@ -739,7 +769,7 @@ static int decklink_write_video_packet(AVFormatContext *avctx, AVPacket *pkt) ctx->first_pts = pkt->pts; /* Schedule frame for playback. */ - hr = ctx->dlo->ScheduleVideoFrame((class IDeckLinkVideoFrame *) frame, + hr = ctx->dlo->ScheduleVideoFrame(frame, pkt->pts * ctx->bmd_tb_num, ctx->bmd_tb_num, ctx->bmd_tb_den); /* Pass ownership to DeckLink, or release on failure */ @@ -874,7 +904,7 @@ av_cold int ff_decklink_write_header(AVFormatContext *avctx) return ret; /* Get output device. */ - if (ctx->dl->QueryInterface(IID_IDeckLinkOutput, (void **) &ctx->dlo) != S_OK) { + if (ctx->dl->QueryInterface(IID_IDeckLinkOutput_v14_2_1, (void **) &ctx->dlo) != S_OK) { av_log(avctx, AV_LOG_ERROR, "Could not open output device from '%s'\n", avctx->url); ret = AVERROR(EIO); -- 2.49.1 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
