UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
decklink.cpp File Reference
#include <DeckLinkAPIVersion.h>
#include <algorithm>
#include <array>
#include <atomic>
#include <cctype>
#include <chrono>
#include <cinttypes>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <exception>
#include <iostream>
#include <iterator>
#include <map>
#include <memory>
#include <mutex>
#include <queue>
#include <sstream>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
#include "audio/types.h"
#include "blackmagic_common.hpp"
#include "compat/htonl.h"
#include "compat/strings.h"
#include "debug.h"
#include "host.h"
#include "lib_common.h"
#include "module.h"
#include "tv.h"
#include "ug_runtime_error.hpp"
#include "utils/macros.h"
#include "utils/math.h"
#include "utils/misc.h"
#include "utils/string.h"
#include "video.h"
#include "video_display.h"
#include "video_display/decklink_drift_fix.hpp"
Include dependency graph for decklink.cpp:

Go to the source code of this file.

Classes

struct  state_decklink
 
struct  state_decklink::aud_desc
 
struct  state_decklink::vid_desc
 

Macros

#define CALL_AND_CHECK(cmd, name)
 
#define CHECK_CH_COUNT(channels)
 only 2, 8, 16, 32 and 64 are supported according to BMD SDK doc
 
#define DECKLINK_MAGIC   to_fourcc('v', 'd', 'D', 'L')
 
#define EXIT_IF_FAILED(cmd, name)
 
#define MOD_NAME   "[DeckLink display] "
 
#define RELEASE_IF_NOT_NULL(x)
 
#define STDMETHODCALLTYPE
 

Typedefs

using hrc = std::chrono::high_resolution_clock
 

Functions

static DeckLinkFrame * allocate_new_decklink_frame (struct state_decklink *s)
 
static void debug_print_metadata_id (const char *fn_name, BMDDeckLinkFrameMetadataID metadataID)
 
static void display_decklink_done (void *state)
 
static bool display_decklink_get_property (void *state, int property, void *val, size_t *len)
 
static struct video_frame * display_decklink_getf (void *state)
 
static void * display_decklink_init (struct module *parent, const char *fmt, unsigned int flags)
 
static void display_decklink_probe (struct device_info **available_cards, int *count, void(**deleter)(void *))
 
static void display_decklink_put_audio_frame (void *state, const struct audio_frame *frame)
 
static bool display_decklink_putf (void *state, struct video_frame *frame, long long timeout_ns)
 
static bool display_decklink_reconfigure (void *state, struct video_desc desc)
 
static bool display_decklink_reconfigure_audio (void *state, int quant_samples, int channels, int sample_rate)
 
static bool enable_audio (struct state_decklink *s, int bps, int channels)
 
static BMDDisplayMode get_mode (IDeckLinkOutput *deckLinkOutput, struct video_desc desc, BMDTimeValue *frameRateDuration, BMDTimeScale *frameRateScale, bool stereo)
 
static bool operator== (const REFIID &first, const REFIID &second)
 
static void print_output_modes (IDeckLink *deckLink, const char *query_prop_fcc)
 
 REGISTER_MODULE (decklink, &display_decklink_info, LIBRARY_CLASS_VIDEO_DISPLAY, VIDEO_DISPLAY_ABI_VERSION)
 
static void set_audio_props (state_decklink *s, IDeckLinkConfiguration *deckLinkConfiguration, unsigned int audio_output)
 
static void set_low_latency (struct state_decklink *s, bool on)
 
static bool settings_init (struct state_decklink *s, const char *fmt, string &cardId)
 
static void show_help (bool full, const char *query_prop_fcc=nullptr)
 
static void update_timecode (DeckLinkTimecode *tc, double fps)
 

Variables

static const struct video_display_info display_decklink_info
 

Detailed Description

Author
Martin Benes marti.nosp@m.nben.nosp@m.esh@g.nosp@m.mail.nosp@m..com
Lukas Hejtmanek xhejt.nosp@m.man@.nosp@m.ics.m.nosp@m.uni..nosp@m.cz
Petr Holub hopet.nosp@m.@ics.nosp@m..muni.nosp@m..cz
Milos Liska xlisk.nosp@m.a@fi.nosp@m..muni.nosp@m..cz
Jiri Matela matel.nosp@m.a@ic.nosp@m.s.mun.nosp@m.i.cz
Dalibor Matura 25589.nosp@m.9@ma.nosp@m.il.mu.nosp@m.ni.c.nosp@m.z
Martin Pulec pulec.nosp@m.@ces.nosp@m.net.c.nosp@m.z

TestPattern example from BMD SDK was used to consult correct BMD workflow usage and also SignalGenerator was used for scheduled playback.

Definition in file decklink.cpp.

Macro Definition Documentation

◆ CALL_AND_CHECK

#define CALL_AND_CHECK ( cmd,
name )
Value:
do {\
const HRESULT result = cmd;\
if (FAILED(result)) {;\
LOG(LOG_LEVEL_WARNING) << MOD_NAME << name << ": " << bmd_hresult_to_string(result) << "\n";\
}\
} while (0)
string bmd_hresult_to_string(HRESULT res)
#define LOG_LEVEL_WARNING
less severe errors
Definition debug.h:60
const char * name
Definition settings.cpp:193
@ FAILED

Definition at line 114 of file decklink.cpp.

114#define CALL_AND_CHECK(cmd, name) \
115 do {\
116 const HRESULT result = cmd;\
117 if (FAILED(result)) {;\
118 LOG(LOG_LEVEL_WARNING) << MOD_NAME << name << ": " << bmd_hresult_to_string(result) << "\n";\
119 }\
120 } while (0)

Referenced by display_decklink_reconfigure().

◆ CHECK_CH_COUNT

#define CHECK_CH_COUNT ( channels)
Value:
assert((channels) >= 2 && (channels) != 4 && (channels) <= 64 && \
int int channels
bool is_power_of_two(unsigned long long x)
Definition math.c:69

only 2, 8, 16, 32 and 64 are supported according to BMD SDK doc

Definition at line 1325 of file decklink.cpp.

1325#define CHECK_CH_COUNT(channels) \
1326 assert((channels) >= 2 && (channels) != 4 && (channels) <= 64 && \
1327 is_power_of_two((channels)))

Referenced by display_decklink_reconfigure_audio(), and set_audio_props().

◆ DECKLINK_MAGIC

#define DECKLINK_MAGIC   to_fourcc('v', 'd', 'D', 'L')

◆ EXIT_IF_FAILED

#define EXIT_IF_FAILED ( cmd,
name )
Value:
do {\
const HRESULT result = cmd;\
if (FAILED(result)) {;\
LOG(LOG_LEVEL_ERROR) << MOD_NAME << name << ": " << bmd_hresult_to_string(result) << "\n";\
return false;\
}\
} while (0)
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59

Definition at line 104 of file decklink.cpp.

104#define EXIT_IF_FAILED(cmd, name) \
105 do {\
106 const HRESULT result = cmd;\
107 if (FAILED(result)) {;\
108 LOG(LOG_LEVEL_ERROR) << MOD_NAME << name << ": " << bmd_hresult_to_string(result) << "\n";\
109 return false;\
110 }\
111 } while (0)

Referenced by display_decklink_reconfigure(), and enable_audio().

◆ MOD_NAME

#define MOD_NAME   "[DeckLink display] "

Definition at line 73 of file decklink.cpp.

Referenced by display_decklink_reconfigure(), and get_mode().

◆ RELEASE_IF_NOT_NULL

#define RELEASE_IF_NOT_NULL ( x)
Value:
if ((x) != nullptr) { (x)->Release(); (x) = nullptr; }

Definition at line 97 of file decklink.cpp.

◆ STDMETHODCALLTYPE

#define STDMETHODCALLTYPE

Definition at line 94 of file decklink.cpp.

Typedef Documentation

◆ hrc

using hrc = std::chrono::high_resolution_clock

Definition at line 122 of file decklink.cpp.

Function Documentation

◆ allocate_new_decklink_frame()

static DeckLinkFrame * allocate_new_decklink_frame ( struct state_decklink * s)
static

Definition at line 688 of file decklink.cpp.

689{
690 const int linesize =
691 vc_get_linesize(s->vid_desc.width, s->vid_desc.color_spec);
692 return s->stereo
693 ? DeckLink3DFrame::Create(
694 s->vid_desc.width, s->vid_desc.height, linesize,
696 : DeckLinkFrame::Create(
697 s->vid_desc.width, s->vid_desc.height, linesize,
698 s->pixelFormat, s->buffer_pool, s->requested_hdr_mode);
699}
int vc_get_linesize(unsigned int width, codec_t codec)

References state_decklink::buffer_pool, state_decklink::pixelFormat, state_decklink::requested_hdr_mode, state_decklink::stereo, and vc_get_linesize().

Referenced by display_decklink_getf().

Here is the call graph for this function:

◆ debug_print_metadata_id()

static void debug_print_metadata_id ( const char * fn_name,
BMDDeckLinkFrameMetadataID metadataID )
inlinestatic

Definition at line 2011 of file decklink.cpp.

2011 {
2013 return;
2014 }
2015 array<char, sizeof metadataID + 1> fourcc{};
2016 copy(reinterpret_cast<char *>(&metadataID), reinterpret_cast<char *>(&metadataID) + sizeof metadataID, fourcc.data());
2017 LOG(LOG_LEVEL_DEBUG2) << MOD_NAME << "DecklLinkFrame " << fn_name << ": " << fourcc.data() << "\n";
2018}
#define LOG_LEVEL_DEBUG2
Definition debug.h:67
#define LOG(level)
Definition debug.h:313
volatile int log_level
Definition debug.cpp:65

References LOG, log_level, LOG_LEVEL_DEBUG2, and MOD_NAME.

◆ display_decklink_done()

static void display_decklink_done ( void * state)
static

Definition at line 1573 of file decklink.cpp.

1574{
1575 debug_msg("display_decklink_done\n"); /* TOREMOVE */
1576 struct state_decklink *s = (struct state_decklink *)state;
1577
1578 assert (s != NULL);
1579
1580 if (s->initialized) {
1581 if (!s->low_latency) {
1583 s->deckLinkOutput->StopScheduledPlayback(0, nullptr, 0),
1584 "StopScheduledPlayback");
1585 }
1586 s->deckLinkOutput->SetScheduledFrameCompletionCallback(nullptr);
1587 if (s->play_audio) {
1589 s->deckLinkOutput->DisableAudioOutput(),
1590 "DisableAudiioOutput");
1591 }
1592 CALL_AND_CHECK(s->deckLinkOutput->DisableVideoOutput(),
1593 "DisableVideoOutput");
1594 }
1595
1600
1601 while (!s->buffer_pool.frame_queue.empty()) {
1602 auto tmp = s->buffer_pool.frame_queue.front();
1603 s->buffer_pool.frame_queue.pop();
1604 tmp->Release();
1605 }
1606
1607 delete s->timecode;
1608
1610 delete s;
1611}
void ** state
void decklink_uninitialize(bool *com_initialized)
#define debug_msg(...)
#define debug_msg(...) log_msg(LOG_LEVEL_DEBUG, "[pid/%d +%d %s] ", getpid(), LINE,...
Definition debug.h:92

References state_decklink::buffer_pool, CALL_AND_CHECK, state_decklink::com_initialized, debug_msg, state_decklink::deckLink, decklink_uninitialize(), state_decklink::deckLinkAttributes, state_decklink::deckLinkConfiguration, state_decklink::deckLinkOutput, state_decklink::initialized, state_decklink::low_latency, state_decklink::play_audio, RELEASE_IF_NOT_NULL, state, and state_decklink::timecode.

Referenced by display_decklink_init().

Here is the call graph for this function:

◆ display_decklink_get_property()

static bool display_decklink_get_property ( void * state,
int property,
void * val,
size_t * len )
static

Definition at line 1613 of file decklink.cpp.

1614{
1615 struct state_decklink *s = (struct state_decklink *)state;
1616 vector<codec_t> codecs(uv_to_bmd_codec_map.size());
1617 int rgb_shift[] = {16, 8, 0};
1619 int count = 0;
1620 for (auto & c : uv_to_bmd_codec_map) {
1621 if (decklink_supports_codec(s->deckLinkOutput, c.second)) {
1622 codecs[count++] = c.first;
1623 }
1624 }
1625
1626 switch (property) {
1628 if(sizeof(codec_t) * count <= *len) {
1629 memcpy(val, codecs.data(), sizeof(codec_t) * count);
1630 *len = sizeof(codec_t) * count;
1631 } else {
1632 return false;
1633 }
1634 break;
1636 if(sizeof(rgb_shift) > *len) {
1637 return false;
1638 }
1639 memcpy(val, rgb_shift, sizeof(rgb_shift));
1640 *len = sizeof(rgb_shift);
1641 break;
1643 *(int *) val = PITCH_DEFAULT;
1644 *len = sizeof(int);
1645 break;
1648 *len = sizeof(int);
1649 break;
1651 if(sizeof(supported_il_modes) <= *len) {
1652 memcpy(val, supported_il_modes, sizeof(supported_il_modes));
1653 } else {
1654 return false;
1655 }
1656 *len = sizeof(supported_il_modes);
1657 break;
1659 {
1660 assert(*len == sizeof(struct audio_desc));
1661 struct audio_desc *desc = (struct audio_desc *) val;
1662 desc->sample_rate = 48000;
1663 if (desc->ch_count >= s->max_aud_chans) {
1664 desc->ch_count = (int) s->max_aud_chans;
1665 } else if (desc->ch_count <= 2) {
1666 desc->ch_count = 2;
1667 } else if (desc->ch_count <= 8) {
1668 desc->ch_count = 8;
1669 } else {
1670 desc->ch_count =
1671 next_power_of_two(desc->ch_count);
1672 }
1673 desc->codec = AC_PCM;
1674 desc->bps = desc->bps < 3 ? 2 : 4;
1675 }
1676 break;
1677 default:
1678 return false;
1679 }
1680 return true;
1681}
int void * val
struct video_desc desc
int void size_t * len
int property
@ AC_PCM
Definition types.h:53
bool decklink_supports_codec(T *deckLink, BMDPixelFormat pf)
static std::vector< std::pair< codec_t, BMDPixelFormat > > uv_to_bmd_codec_map
#define PITCH_DEFAULT
default pitch, i. e. respective linesize
@ DISPLAY_PROPERTY_BUF_PITCH
requested framebuffer pitch - int (bytes), may be PITCH_DEFAULT
@ DISPLAY_PROPERTY_RGB_SHIFT
red,green,blue shift - int[3] (bits)
@ DISPLAY_PROPERTY_SUPPORTED_IL_MODES
display supported interlacing modes - enum interlacing_t[]
@ DISPLAY_PROPERTY_VIDEO_MODE
requested video mode - int (one of display_prop_vid_mode)
@ DISPLAY_PROPERTY_CODECS
list of natively supported codecs - codec_t[]
@ DISPLAY_PROPERTY_AUDIO_FORMAT
@ DISPLAY_PROPERTY_VIDEO_SEPARATE_3D
same as MERGED but 2 streams should be handled as separate 3D tiles
int count
Definition hd-rum.c:44
unsigned long long next_power_of_two(unsigned long long x)
Definition math.c:79
interlacing_t
Definition types.h:163
@ PROGRESSIVE
progressive frame
Definition types.h:164
@ SEGMENTED_FRAME
Segmented frame. Contains the same data as progressive frame.
Definition types.h:168
@ INTERLACED_MERGED
Columngs of both fields are interlaced together.
Definition types.h:167
codec_t
Definition types.h:65
static struct @76 codecs[]

References AC_PCM, codecs, count, decklink_supports_codec(), state_decklink::deckLinkOutput, desc, DISPLAY_PROPERTY_AUDIO_FORMAT, DISPLAY_PROPERTY_BUF_PITCH, DISPLAY_PROPERTY_CODECS, DISPLAY_PROPERTY_RGB_SHIFT, DISPLAY_PROPERTY_SUPPORTED_IL_MODES, DISPLAY_PROPERTY_VIDEO_MODE, DISPLAY_PROPERTY_VIDEO_SEPARATE_3D, INTERLACED_MERGED, len, state_decklink::max_aud_chans, next_power_of_two(), PITCH_DEFAULT, PROGRESSIVE, property, SEGMENTED_FRAME, state, uv_to_bmd_codec_map, and val.

Here is the call graph for this function:

◆ display_decklink_getf()

static struct video_frame * display_decklink_getf ( void * state)
static

Definition at line 702 of file decklink.cpp.

703{
704 struct state_decklink *s = (struct state_decklink *)state;
705 assert(s->magic == DECKLINK_MAGIC);
706 assert(s->initialized);
707
708 if (s->audio_reconfigure) {
710 MSG(FATAL, "Cannot reinit after audio reconf!\n");
711 abort();
712 }
713 s->audio_reconfigure = false;
714 }
715
716 struct video_frame *out = vf_alloc_desc(s->vid_desc);
717 static auto dispose = [](struct video_frame *frame) {
718 vf_free(frame);
719 };
720 out->callbacks.dispose = dispose;
721
722 const int linesize = vc_get_linesize(s->vid_desc.width, s->vid_desc.color_spec);
723 DeckLinkFrame *deckLinkFrame = nullptr;
724 lock_guard<mutex> lg(s->buffer_pool.lock);
725
726 while (!s->buffer_pool.frame_queue.empty()) {
727 auto tmp = s->buffer_pool.frame_queue.front();
728 DeckLinkFrame *frame =
729 s->stereo ? dynamic_cast<DeckLink3DFrame *>(tmp)
730 : dynamic_cast<DeckLinkFrame *>(tmp);
731 s->buffer_pool.frame_queue.pop();
732 if (!frame || // wrong type
733 frame->GetWidth() != (long)s->vid_desc.width ||
734 frame->GetHeight() != (long)s->vid_desc.height ||
735 frame->GetRowBytes() != linesize || frame->GetPixelFormat() != s->pixelFormat) {
736 tmp->Release();
737 } else {
738 deckLinkFrame = frame;
739 deckLinkFrame->AddRef();
740 break;
741 }
742 }
743 if (!deckLinkFrame) {
744 deckLinkFrame = allocate_new_decklink_frame(s);
745 }
746 out->callbacks.dispose_udata = (void *) deckLinkFrame;
747
748 deckLinkFrame->GetBytes((void **)&out->tiles[0].data);
749
750 if (s->stereo) {
751 IDeckLinkVideoFrame *deckLinkFrameRight = nullptr;
752 DeckLink3DFrame *frame3D = dynamic_cast<DeckLink3DFrame *>(deckLinkFrame);
753 assert(frame3D != nullptr);
754 frame3D->GetFrameForRightEye(&deckLinkFrameRight);
755 deckLinkFrameRight->GetBytes((void **)&out->tiles[1].data);
756 // release immedieatelly (parent still holds the reference)
757 deckLinkFrameRight->Release();
758 }
759
760 return out;
761}
struct video_frame * frame
void vf_free(struct video_frame *buf)
Frees video_frame structure.
struct video_frame * vf_alloc_desc(struct video_desc desc)
Allocates video frame accordig given desc.
#define MSG(l, fmt,...)
Definition debug.h:96
char * data
Raw tile data. Pointer must be at least 4B aligned.
Definition types.h:287
void(* dispose)(struct video_frame *)
Definition types.h:245
Struct video_frame represents a video frame and contains video description.
Definition types.h:305
struct tile tiles[FLEXIBLE_ARRAY_MEMBER]
Definition types.h:345
struct video_frame_callbacks callbacks
Definition types.h:324

References allocate_new_decklink_frame(), state_decklink::audio_reconfigure, state_decklink::buffer_pool, video_frame::callbacks, tile::data, DECKLINK_MAGIC, display_decklink_reconfigure(), video_frame_callbacks::dispose, video_frame_callbacks::dispose_udata, frame, state_decklink::initialized, state_decklink::magic, MSG, state_decklink::pixelFormat, state, state_decklink::stereo, video_frame::tiles, vc_get_linesize(), vf_alloc_desc(), and vf_free().

Here is the call graph for this function:

◆ display_decklink_init()

static void * display_decklink_init ( struct module * parent,
const char * fmt,
unsigned int flags )
static

Definition at line 1392 of file decklink.cpp.

1393{
1394 HRESULT result;
1395 string cardId("0");
1396 IDeckLinkConfiguration* deckLinkConfiguration = NULL;
1397 // for Decklink Studio which has switchable XLR - analog 3 and 4 or AES/EBU 3,4 and 5,6
1398
1399 if (strcmp(fmt, "help") == 0 || strcmp(fmt, "fullhelp") == 0) {
1400 show_help(strcmp(fmt, "fullhelp") == 0);
1401 return INIT_NOERR;
1402 }
1403 if (IS_KEY_PREFIX(fmt, "query")) {
1404 show_help(true, strchr(fmt, '=') + 1);
1405 return INIT_NOERR;
1406 }
1407
1409 return NULL;
1410 }
1411
1412 auto *s = new state_decklink();
1413 s->audio_drift_fixer.set_root(get_root_module(parent));
1414
1415 bool succeeded = false;
1416 try {
1417 succeeded = settings_init(s, fmt, cardId);
1418 } catch (exception &e) {
1419 if (invalid_arg_is_numeric(e.what())) {
1420 MSG(ERROR, "Invalid number passed where numeric "
1421 "argument expected!\n");
1422 } else {
1423 MSG(ERROR, "%s\n", e.what());
1424 }
1425 }
1426 if (!succeeded) {
1427 delete s;
1428 return NULL;
1429 }
1430
1431 // Connect to the first DeckLink instance
1432 for (auto &d : bmd_get_sorted_devices(&s->com_initialized, true)) {
1433 s->deckLink = get<0>(d).release(); // unmanage
1434 string deviceName = bmd_get_device_name(s->deckLink);
1435
1436 if (!deviceName.empty() && deviceName == cardId) {
1437 break;
1438 }
1439 // topological ID
1440 const unsigned long tid = strtoul(cardId.c_str(), nullptr, 16);
1441 if (get<unsigned>(d) == tid) {
1442 break;
1443 }
1444 // natural (old) index
1445 if (isdigit(cardId.c_str()[0])) {
1446 if (atoi(cardId.c_str()) == get<int>(d)) {
1447 break;
1448 }
1449 }
1450 // new (character) index
1451 if (cardId.length() == 1 && cardId[0] >= 'a') {
1452 if (cardId[0] == get<char>(d)) {
1453 break;
1454 }
1455 }
1456
1457 s->deckLink->Release();
1458 s->deckLink = nullptr;
1459 }
1460 if (s->deckLink == nullptr) {
1461 LOG(LOG_LEVEL_ERROR) << "No DeckLink PCI card " << cardId << " found\n";
1463 return nullptr;
1464 }
1465 // Print the model name of the DeckLink card
1466 string deviceName = bmd_get_device_name(s->deckLink);
1467 if (!deviceName.empty()) {
1468 LOG(LOG_LEVEL_INFO) << MOD_NAME "Using device " << deviceName << "\n";
1469 }
1470
1471 // Get IDeckLinkAttributes object
1472 result = s->deckLink->QueryInterface(
1473 IID_IDeckLinkProfileAttributes,
1474 reinterpret_cast<void **>(&s->deckLinkAttributes));
1475 if (result != S_OK) {
1477 << MOD_NAME "Could not query device attributes: "
1478 << bmd_hresult_to_string(result) << "\n";
1480 return nullptr;
1481 }
1482
1483 if(s->emit_timecode) {
1484 s->timecode = new DeckLinkTimecode;
1485 } else {
1486 s->timecode = NULL;
1487 }
1488
1489 if (!s->keep_device_defaults && !s->profile_req.keep()) {
1490 if (!decklink_set_profile(s->deckLink, s->profile_req,
1491 s->stereo)) {
1493 return nullptr;
1494 }
1495 }
1496
1497 // Obtain the audio/video output interface (IDeckLinkOutput)
1498 if ((result = s->deckLink->QueryInterface(
1499 IID_IDeckLinkOutput, reinterpret_cast<void **>(&s->deckLinkOutput))) != S_OK) {
1501 MOD_NAME "Could not obtain the IDeckLinkOutput interface: %08x\n",
1502 (int)result);
1504 return nullptr;
1505 }
1506
1507 // Query the DeckLink for its configuration interface
1508 result = s->deckLink->QueryInterface(IID_IDeckLinkConfiguration,
1509 reinterpret_cast<void **>(&deckLinkConfiguration));
1510 s->deckLinkConfiguration = deckLinkConfiguration;
1511 if (result != S_OK) {
1513 "Could not obtain the IDeckLinkConfiguration interface: %08x\n",
1514 (int)result);
1516 return nullptr;
1517 }
1518
1519 for (const auto &o : s->device_options) {
1520 if (s->keep_device_defaults && !o.second.is_user_set()) {
1521 continue;
1522 }
1523 if (!o.second.device_write(deckLinkConfiguration, o.first, MOD_NAME)) {
1525 return nullptr;
1526 }
1527 }
1528
1529 if (s->requested_hdr_mode.EOTF != static_cast<int64_t>(HDR_EOTF::NONE)) {
1530 BMD_BOOL hdr_supp = BMD_FALSE;
1531 if (s->deckLinkAttributes->GetFlag(BMDDeckLinkSupportsHDRMetadata, &hdr_supp) !=
1532 S_OK) {
1534 << MOD_NAME
1535 << "HDR requested, but unable to validate HDR support. Will "
1536 "try to pass it anyway which may result in blank image if "
1537 "not supported - remove the option if so.\n";
1538 } else {
1539 if (hdr_supp != BMD_TRUE) {
1541 << MOD_NAME
1542 << "HDR requested, but card doesn't support that.\n";
1544 return nullptr;
1545 }
1546 }
1547
1548 BMD_BOOL rec2020_supp = BMD_FALSE;
1549 if (s->deckLinkAttributes->GetFlag(BMDDeckLinkSupportsColorspaceMetadata,
1550 &rec2020_supp) != S_OK) {
1552 << MOD_NAME << "Cannot check Rec. 2020 color space metadata support.\n";
1553 } else {
1554 if (rec2020_supp != BMD_TRUE) {
1556 << MOD_NAME
1557 << "Rec. 2020 color space metadata not supported.\n";
1558 }
1559 }
1560 }
1561
1562 set_audio_props(s, deckLinkConfiguration,
1564
1565 if (!s->low_latency) {
1566 s->delegate.SetDecklinkOutput(s->deckLinkOutput);
1567 }
1568 // s->state.at(i).deckLinkOutput->DisableAudioOutput();
1569
1570 return (void *)s;
1571}
const char * fmt
const char unsigned int flags
bool blackmagic_api_version_check()
string bmd_get_device_name(IDeckLink *decklink)
bool decklink_set_profile(IDeckLink *deckLink, bmd_option const &req_profile, bool stereo)
std::vector< bmd_dev > bmd_get_sorted_devices(bool *com_initialized, bool verbose, bool natural_sort)
#define BMD_BOOL
#define BMD_FALSE
#define BMD_TRUE
static void show_help()
Definition wasapi.cpp:193
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_INFO
normal reporting
Definition debug.h:62
#define DISPLAY_FLAG_AUDIO_ANY
struct module * get_root_module(struct module *node)
Definition module.c:203
#define INIT_NOERR
Definition host.h:73
#define IS_KEY_PREFIX(tok, key)
expands to true value if <k> from tok in format <k>=<v> is prefix of key
Definition macros.h:138
bool invalid_arg_is_numeric(const char *what)
Definition misc.cpp:340
const char * parent
Definition settings.cpp:198

References state_decklink::audio_drift_fixer, blackmagic_api_version_check(), BMD_BOOL, BMD_FALSE, bmd_get_device_name(), bmd_get_sorted_devices(), bmd_hresult_to_string(), BMD_TRUE, state_decklink::com_initialized, state_decklink::deckLink, decklink_set_profile(), state_decklink::deckLinkAttributes, state_decklink::deckLinkConfiguration, state_decklink::deckLinkOutput, state_decklink::delegate, state_decklink::device_options, display_decklink_done(), DISPLAY_FLAG_AUDIO_ANY, state_decklink::emit_timecode, flags, fmt, get_root_module(), INIT_NOERR, invalid_arg_is_numeric(), IS_KEY_PREFIX, bmd_option::keep(), state_decklink::keep_device_defaults, LOG, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_WARNING, log_msg(), state_decklink::low_latency, MOD_NAME, MSG, parent, state_decklink::profile_req, state_decklink::requested_hdr_mode, set_audio_props(), AudioDriftFixer::set_root(), settings_init(), show_help(), state_decklink::stereo, and state_decklink::timecode.

Here is the call graph for this function:

◆ display_decklink_probe()

static void display_decklink_probe ( struct device_info ** available_cards,
int * count,
void(** deleter )(void *) )
static

Definition at line 1132 of file decklink.cpp.

1133{
1134 UNUSED(deleter);
1135
1136 *count = 0;
1137 *available_cards = nullptr;
1138
1139 bool com_initialized = false;
1140 // Enumerate all cards in this system
1141 for (auto &d : bmd_get_sorted_devices(&com_initialized, false)) {
1142 IDeckLink *deckLink = get<0>(d).get();
1143 string deviceName = bmd_get_device_name(deckLink);
1144 if (deviceName.empty()) {
1145 deviceName = "(unknown)";
1146 }
1147
1148 *count += 1;
1149 *available_cards = (struct device_info *)
1150 realloc(*available_cards, *count * sizeof(struct device_info));
1151 memset(*available_cards + *count - 1, 0, sizeof(struct device_info));
1152 snprintf((*available_cards)[*count - 1].dev,
1153 sizeof(*available_cards)[*count - 1].dev, ":device=%6x",
1154 get<unsigned>(d));
1155 snprintf((*available_cards)[*count - 1].extra, sizeof (*available_cards)[*count - 1].extra, "\"embeddedAudioAvailable\":\"t\"");
1156 (*available_cards)[*count - 1].repeatable = false;
1157
1158 strncpy((*available_cards)[*count - 1].name, deviceName.c_str(),
1159 sizeof (*available_cards)[*count - 1].name - 1);
1160
1161 dev_add_option(&(*available_cards)[*count - 1], "3D", "3D", "3D", ":3D", true);
1162 dev_add_option(&(*available_cards)[*count - 1], "Profile", "Duplex profile can be one of: 1dhd, 2dhd, 2dfd, 4dhd, keep", "profile", ":profile=", false);
1163 dev_add_option(&(*available_cards)[*count - 1], "HDR", "Can be one of: SDR, HDR, PQ, HLG or int 0-7", "hdr", ":HDR=", false);
1164 }
1165
1166 decklink_uninitialize(&com_initialized);
1167}
#define UNUSED(x)
int void(** deleter)(void *))
char extra[1024]
Definition types.h:389
char dev[1024]
Definition types.h:383
void dev_add_option(struct device_info *dev, const char *name, const char *desc, const char *key, const char *opt_str, bool is_boolean)

References bmd_get_device_name(), bmd_get_sorted_devices(), count, decklink_uninitialize(), deleter, dev_add_option(), name, and UNUSED.

Here is the call graph for this function:

◆ display_decklink_put_audio_frame()

static void display_decklink_put_audio_frame ( void * state,
const struct audio_frame * frame )
static

Definition at line 1728 of file decklink.cpp.

1729{
1730 struct state_decklink *s = (struct state_decklink *)state;
1731 assert(s->play_audio);
1732 if (s->audio_reconfigure) {
1733 return;
1734 }
1735 const unsigned int sampleFrameCount =
1736 frame->data_len / (frame->bps * frame->ch_count);
1737 uint32_t sampleFramesWritten = sampleFrameCount;
1738
1739 uint32_t buffered = 0;
1740 s->deckLinkOutput->GetBufferedAudioSampleFrameCount(&buffered);
1741 if (buffered == 0) {
1742 LOG(LOG_LEVEL_WARNING) << MOD_NAME << "audio buffer underflow!\n";
1743 }
1744
1745 if (s->low_latency) {
1746 HRESULT res = s->deckLinkOutput->WriteAudioSamplesSync(frame->data, sampleFrameCount,
1747 &sampleFramesWritten);
1748 if (FAILED(res)) {
1749 log_msg(LOG_LEVEL_WARNING, MOD_NAME "WriteAudioSamplesSync failed.\n");
1750 return;
1751 }
1752 } else {
1753 s->delegate.ScheduleAudio(frame, &sampleFramesWritten,
1754 buffered == 0);
1755 }
1756 const bool overflow = sampleFramesWritten != sampleFrameCount;
1757 if (overflow || log_level >= LOG_LEVEL_DEBUG) {
1758 ostringstream details_oss;
1760 details_oss
1761 << " (" << sampleFramesWritten << " written, "
1762 << sampleFrameCount - sampleFramesWritten
1763 << " dropped, " << buffered << " buffer size)";
1764 }
1765 int level = overflow ? LOG_LEVEL_WARNING : LOG_LEVEL_DEBUG;
1766 LOG(level) << MOD_NAME << "audio buffer"
1767 << (overflow ? " overflow!" : "")
1768 << details_oss.str() << "\n";
1769 }
1770 s->audio_drift_fixer.update(buffered, sampleFrameCount, sampleFramesWritten);
1771}
void update(uint32_t buffered_count, uint32_t sample_frame_count, uint32_t sampleFramesWritten)
#define LOG_LEVEL_VERBOSE
Definition debug.h:63
#define LOG_LEVEL_DEBUG
Definition kernels.cu:48

References state_decklink::audio_drift_fixer, state_decklink::audio_reconfigure, state_decklink::deckLinkOutput, state_decklink::delegate, FAILED, frame, LOG, log_level, LOG_LEVEL_DEBUG, LOG_LEVEL_VERBOSE, LOG_LEVEL_WARNING, log_msg(), state_decklink::low_latency, MOD_NAME, state_decklink::play_audio, state, and AudioDriftFixer::update().

Here is the call graph for this function:

◆ display_decklink_putf()

static bool display_decklink_putf ( void * state,
struct video_frame * frame,
long long timeout_ns )
static

Definition at line 803 of file decklink.cpp.

805{
806 struct state_decklink *s = (struct state_decklink *)state;
807 bool ret = true;
808
809 if (frame == NULL)
810 return true;
811
812 assert(s->magic == DECKLINK_MAGIC);
813
815 for (unsigned i = 0; i < frame->tile_count; ++i) {
817 }
818 }
819
820 auto *deckLinkFrame = (DeckLinkFrame *) frame->callbacks.dispose_udata;
821 if (s->emit_timecode) {
822 deckLinkFrame->SetTimecode(bmdTimecodeRP188Any, s->timecode);
823 }
824
825 if (s->low_latency) {
826 s->deckLinkOutput->DisplayVideoFrameSync(deckLinkFrame);
827 deckLinkFrame->Release();
828 } else {
829 deckLinkFrame->timestamp = frame->timestamp;
830 ret = s->delegate.EnqueueFrame(deckLinkFrame);
831 }
832 if(s->emit_timecode) {
834 }
835
837
838 s->delegate.PrintStats();
839
840 return ret;
841}
void r10k_full_to_limited(const char *in, char *out, size_t len)
#define R10K_FULL_OPT
const char * get_commandline_param(const char *key)
Definition host.cpp:894
unsigned int data_len
length of the data
Definition types.h:288
int64_t timestamp
Definition types.h:331
unsigned int tile_count
Definition types.h:344
codec_t color_spec
Definition types.h:306
@ R10k
RGB 10-bit packed - RGBX, big-endian (2 bit padding)
Definition types.h:73

References video_frame::callbacks, video_frame::color_spec, tile::data, tile::data_len, DECKLINK_MAGIC, state_decklink::deckLinkFrame, state_decklink::deckLinkOutput, state_decklink::delegate, video_frame_callbacks::dispose, video_frame_callbacks::dispose_udata, state_decklink::emit_timecode, frame, get_commandline_param(), state_decklink::low_latency, state_decklink::magic, R10k, R10K_FULL_OPT, r10k_full_to_limited(), state, video_frame::tile_count, video_frame::tiles, state_decklink::timecode, video_frame::timestamp, and update_timecode().

Here is the call graph for this function:

◆ display_decklink_reconfigure()

static bool display_decklink_reconfigure ( void * state,
struct video_desc desc )
static

Definition at line 923 of file decklink.cpp.

924{
925 auto *s = (struct state_decklink *) state;
926 assert(s->magic == DECKLINK_MAGIC);
927
928 BMDDisplayMode displayMode;
929 BMD_BOOL supported;
930 HRESULT result;
931
932 const unique_lock<mutex> lk(s->audio_reconf_lock);
933 s->delegate.ResetAudio(); // disables audio until full reconf
934
935 s->vid_desc = desc;
936
937 if (s->initialized) {
938 if (!s->low_latency) {
939 CALL_AND_CHECK(s->deckLinkOutput->StopScheduledPlayback(
940 0, nullptr, 0),
941 "StopScheduledPlayback");
942 }
943 s->deckLinkOutput->SetScheduledFrameCompletionCallback(nullptr);
944 CALL_AND_CHECK(s->deckLinkOutput->DisableVideoOutput(),
945 "DisableVideoOutput");
946 if (s->play_audio) {
947 CALL_AND_CHECK(s->deckLinkOutput->DisableAudioOutput(),
948 "DisableAudioOutput");
949 }
950 s->initialized = false;
951 }
952
953 s->delegate.Reset();
954
956 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Using limited range R10k as specified by BMD, use '--param "
957 R10K_FULL_OPT "' to override.\n");
958 }
959
960 auto it = std::find_if(uv_to_bmd_codec_map.begin(),
962 [&desc](const std::pair<codec_t, BMDPixelFormat>& el){ return el.first == desc.color_spec; });
963 if (it == uv_to_bmd_codec_map.end()) {
964 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unsupported pixel format!\n");
965 return false;
966 }
967 s->pixelFormat = it->second;
968
969 if (desc.tile_count <= 2 && desc.tile_count != (s->stereo ? 2 : 1)) {
970 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Stereo %s enabled but receiving %u streams. %sabling "
971 "it. This behavior is experimental so please report any problems. "
972 "You can also specify (or not) `3D` option explicitly.\n"
973 , s->stereo ? "" : "not", desc.tile_count, s->stereo ? "dis" : "en");
974 s->stereo = !s->stereo;
975 }
976
977 if (s->stereo) {
978 bmd_check_stereo_profile(s->deckLink);
979 if ((int) desc.tile_count != 2) {
980 log_msg(LOG_LEVEL_ERROR, MOD_NAME "In stereo mode exactly "
981 "2 streams expected, %d received.\n", desc.tile_count);
982 return false;
983 }
984 } else {
985 if ((int) desc.tile_count == 2) {
986 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Received 2 streams but stereo mode is not enabled! Did you forget a \"3D\" parameter?\n");
987 }
988 }
989
990 BMDVideoOutputFlags outputFlags = bmdVideoOutputFlagDefault;
991 BMDSupportedVideoModeFlags supportedFlags = bmdSupportedVideoModeDefault;
992
993 BMDTimeValue frameRateDuration{};
994 BMDTimeScale frameRateScale{};
995 displayMode = get_mode(s->deckLinkOutput, desc, &frameRateDuration,
996 &frameRateScale, s->stereo);
997 if (displayMode == bmdModeUnknown) {
998 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Could not find suitable video mode.\n");
999 return false;
1000 }
1001 s->delegate.SetFrameTimes(frameRateDuration, frameRateScale);
1002
1003 if (s->emit_timecode) {
1004 outputFlags = (BMDVideoOutputFlags)(outputFlags | bmdVideoOutputRP188);
1005 }
1006
1007 if (s->stereo) {
1008 outputFlags = (BMDVideoOutputFlags)(outputFlags | bmdVideoOutputDualStream3D);
1009 supportedFlags = (BMDSupportedVideoModeFlags)(supportedFlags |
1010 bmdSupportedVideoModeDualStream3D);
1011 }
1012
1013 const bmd_option subsampling_444(codec_is_a_rgb(desc.color_spec),
1014 false); // we don't have pixfmt for 444 YCbCr
1015 subsampling_444.device_write(s->deckLinkConfiguration, bmdDeckLinkConfig444SDIVideoOutput,
1016 MOD_NAME);
1017
1018 if (!s->keep_device_defaults &&
1019 s->device_options.find(bmdDeckLinkConfigSDIOutputLinkConfiguration) ==
1020 s->device_options.end()) {
1021 const int64_t link = desc.width == 7680 ? bmdLinkConfigurationQuadLink
1022 : bmdLinkConfigurationSingleLink;
1023 bmd_option(link).device_write(s->deckLinkConfiguration,
1024 bmdDeckLinkConfigSDIOutputLinkConfiguration,
1025 MOD_NAME);
1026 }
1027
1028 int64_t link = 0;
1029 s->deckLinkConfiguration->GetInt(bmdDeckLinkConfigSDIOutputLinkConfiguration, &link);
1030 if (!s->keep_device_defaults && s->profile_req.is_default() &&
1031 link == bmdLinkConfigurationQuadLink) {
1033 << MOD_NAME "Quad-link detected - setting 1-subdevice-1/2-duplex "
1034 "profile automatically, use 'profile=keep' to override.\n";
1036 s->deckLink, bmd_option((int64_t)bmdProfileOneSubDeviceHalfDuplex), s->stereo);
1037 } else if (link == bmdLinkConfigurationQuadLink &&
1038 (!s->profile_req.keep() &&
1039 s->profile_req.get_int() != bmdProfileOneSubDeviceHalfDuplex)) {
1040 LOG(LOG_LEVEL_WARNING) << MOD_NAME "Setting quad-link and an incompatible device "
1041 "profile may not be supported!\n";
1042 }
1043
1044 BMD_BOOL quad_link_supp = BMD_FALSE;
1045 if (s->deckLinkAttributes->GetFlag(BMDDeckLinkSupportsQuadLinkSDI, &quad_link_supp) ==
1046 S_OK &&
1047 quad_link_supp == BMD_TRUE) {
1048 s->quad_square_division_split.device_write(
1049 s->deckLinkConfiguration,
1050 bmdDeckLinkConfigQuadLinkSDIVideoOutputSquareDivisionSplit, MOD_NAME);
1051 }
1052
1053 const BMDVideoOutputConversionMode conversion_mode =
1054 s->device_options.find(bmdDeckLinkConfigVideoOutputConversionMode) !=
1055 s->device_options.end()
1056 ? (BMDVideoOutputConversionMode)s->device_options
1057 .at(bmdDeckLinkConfigVideoOutputConversionMode)
1058 .get_int()
1059 : (BMDVideoOutputConversionMode)bmdNoVideoOutputConversion;
1060 EXIT_IF_FAILED(s->deckLinkOutput->DoesSupportVideoMode(
1061 bmdVideoConnectionUnspecified, displayMode, s->pixelFormat,
1062 conversion_mode, supportedFlags, nullptr, &supported),
1063 "DoesSupportVideoMode");
1064 if (!supported) {
1066 MOD_NAME "Requested parameters "
1067 "combination not supported - %d * %dx%d@%f, timecode %s.\n",
1069 (outputFlags & bmdVideoOutputRP188 ? "ON" : "OFF"));
1070 return false;
1071 }
1072
1073 result = s->deckLinkOutput->EnableVideoOutput(displayMode, outputFlags);
1074 if (FAILED(result)) {
1075 if (result == E_ACCESSDENIED) {
1077 MOD_NAME "Unable to access the hardware or output "
1078 "stream currently active (another application "
1079 "using it?).\n");
1080 } else {
1082 << MOD_NAME << "EnableVideoOutput: " << bmd_hresult_to_string(result)
1083 << "\n";
1084 }
1085 return false;
1086 }
1087
1088 if (s->play_audio) {
1089 if (!enable_audio(s, s->aud_desc.bps, s->aud_desc.ch_count)) {
1090 return false;
1091 }
1092 }
1093
1094 if (!s->low_latency) {
1095 // Provide this class as a delegate to a video output interface
1096 s->deckLinkOutput->SetScheduledFrameCompletionCallback(
1097 &s->delegate);
1098 if (!s->delegate.Preroll(s)) {
1099 return false;
1100 }
1101 }
1102
1103 s->initialized = true;
1104 s->audio_reconfigure = false;
1105 return true;
1106}
bool bmd_check_stereo_profile(IDeckLink *deckLink)
bool device_write(IDeckLinkConfiguration *deckLinkConfiguration, BMDDeckLinkConfigurationID opt, std::string const &log_prefix="[DeckLink] ") const
unsigned int tile_count
Definition types.h:185
codec_t color_spec
Definition types.h:182
double fps
Definition types.h:183
unsigned int width
width of every tile (!)
Definition types.h:179
unsigned int height
height of every tile (!)
Definition types.h:180
bool codec_is_a_rgb(codec_t codec)
Returns TRUE if specified pixelformat is some form of RGB (not YUV).

References BMD_BOOL, bmd_check_stereo_profile(), BMD_FALSE, bmd_hresult_to_string(), BMD_TRUE, CALL_AND_CHECK, codec_is_a_rgb(), video_desc::color_spec, DECKLINK_MAGIC, decklink_set_profile(), desc, bmd_option::device_write(), enable_audio(), EXIT_IF_FAILED, FAILED, video_desc::fps, state_decklink::frameRateDuration, state_decklink::frameRateScale, get_commandline_param(), get_mode(), video_desc::height, LOG, LOG_LEVEL_ERROR, LOG_LEVEL_WARNING, log_msg(), MOD_NAME, R10k, R10K_FULL_OPT, state, video_desc::tile_count, uv_to_bmd_codec_map, and video_desc::width.

Referenced by display_decklink_getf().

Here is the call graph for this function:

◆ display_decklink_reconfigure_audio()

static bool display_decklink_reconfigure_audio ( void * state,
int quant_samples,
int channels,
int sample_rate )
static

Definition at line 1773 of file decklink.cpp.

1774 {
1775 struct state_decklink *s = (struct state_decklink *)state;
1776
1777 assert(s->play_audio);
1779 assert(quant_samples == 16 || quant_samples == 32);
1780
1781 const int bps = quant_samples / 8;
1782 const unique_lock<mutex> lk(s->audio_reconf_lock);
1783 if (bps != s->aud_desc.bps || sample_rate != s->aud_desc.sample_rate ||
1784 channels != s->aud_desc.ch_count) {
1786 AC_PCM};
1787 s->audio_reconfigure = true;
1789 << MOD_NAME << "Audio reconfigured to: " << s->aud_desc
1790 << "\n";
1791 }
1792
1793 return true;
1794}
int int int sample_rate
int quant_samples

References AC_PCM, state_decklink::audio_reconf_lock, state_decklink::audio_reconfigure, channels, CHECK_CH_COUNT, LOG, LOG_LEVEL_VERBOSE, MOD_NAME, state_decklink::play_audio, quant_samples, sample_rate, and state.

◆ enable_audio()

static bool enable_audio ( struct state_decklink * s,
int bps,
int channels )
static

Definition at line 907 of file decklink.cpp.

908{
909 const BMDAudioSampleType sample_type =
910 bps == 2 ? bmdAudioSampleType16bitInteger
911 : bmdAudioSampleType32bitInteger;
912 const BMDAudioOutputStreamType stream_type =
913 s->low_latency ? bmdAudioOutputStreamContinuous
914 : bmdAudioOutputStreamTimestamped;
916 s->deckLinkOutput->EnableAudioOutput(
917 bmdAudioSampleRate48kHz, sample_type, channels, stream_type),
918 "EnableAudioOutput");
919 return true;
920}

References channels, state_decklink::deckLinkOutput, EXIT_IF_FAILED, and state_decklink::low_latency.

Referenced by display_decklink_reconfigure().

◆ get_mode()

static BMDDisplayMode get_mode ( IDeckLinkOutput * deckLinkOutput,
struct video_desc desc,
BMDTimeValue * frameRateDuration,
BMDTimeScale * frameRateScale,
bool stereo )
static

Definition at line 843 of file decklink.cpp.

845{ IDeckLinkDisplayModeIterator *displayModeIterator;
846 IDeckLinkDisplayMode* deckLinkDisplayMode;
847 BMDDisplayMode displayMode = bmdModeUnknown;
848
849 // Populate the display mode combo with a list of display modes supported by the installed DeckLink card
850 if (FAILED(deckLinkOutput->GetDisplayModeIterator(&displayModeIterator)))
851 {
852 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Fatal: cannot create display mode iterator.\n");
853 return bmdModeUnknown;
854 }
855
856 while (displayModeIterator->Next(&deckLinkDisplayMode) == S_OK)
857 {
858 BMD_STR modeNameString;
859 if (deckLinkDisplayMode->GetName(&modeNameString) == S_OK)
860 {
861 if (deckLinkDisplayMode->GetWidth() == (long) desc.width &&
862 deckLinkDisplayMode->GetHeight() == (long) desc.height)
863 {
864 double displayFPS;
865 BMDFieldDominance dominance;
866 bool interlaced;
867
868 dominance = deckLinkDisplayMode->GetFieldDominance();
869 if (dominance == bmdLowerFieldFirst ||
870 dominance == bmdUpperFieldFirst) {
871 if (dominance == bmdLowerFieldFirst) {
872 bug_msg(
874 "Lower field first format "
875 "detected, fields can be "
876 "switched! ");
877 }
878 interlaced = true;
879 } else { // progressive, psf, unknown
880 interlaced = false;
881 }
882
883 deckLinkDisplayMode->GetFrameRate(frameRateDuration,
884 frameRateScale);
885 displayFPS = (double) *frameRateScale / *frameRateDuration;
886 if (fabs(desc.fps - displayFPS) < 0.01 && (desc.interlacing == INTERLACED_MERGED) == interlaced) {
887 MSG(INFO, "Selected mode: %s%s\n",
889 modeNameString)
890 .c_str(),
891 stereo ? " (3D)" : "");
892 displayMode = deckLinkDisplayMode->GetDisplayMode();
893 release_bmd_api_str(modeNameString);
894 deckLinkDisplayMode->Release();
895 break;
896 }
897 }
898 release_bmd_api_str(modeNameString);
899 }
900 deckLinkDisplayMode->Release();
901 }
902 displayModeIterator->Release();
903
904 return displayMode;
905}
void release_bmd_api_str(BMD_STR string)
std::string get_str_from_bmd_api_str(BMD_STR string)
#define BMD_STR
void bug_msg(int level, const char *format,...)
prints the error with the advice to report the bug
Definition debug.cpp:379
enum interlacing_t interlacing
Definition types.h:184

References BMD_STR, bug_msg(), state_decklink::deckLinkOutput, desc, FAILED, video_desc::fps, state_decklink::frameRateDuration, state_decklink::frameRateScale, get_str_from_bmd_api_str(), video_desc::height, INTERLACED_MERGED, video_desc::interlacing, LOG_LEVEL_ERROR, LOG_LEVEL_WARNING, log_msg(), MOD_NAME, MSG, release_bmd_api_str(), state_decklink::stereo, and video_desc::width.

Referenced by display_decklink_reconfigure().

Here is the call graph for this function:

◆ operator==()

static bool operator== ( const REFIID & first,
const REFIID & second )
static

Definition at line 1797 of file decklink.cpp.

1797 {
1798 return (first.byte0 == second.byte0) &&
1799 (first.byte1 == second.byte1) &&
1800 (first.byte2 == second.byte2) &&
1801 (first.byte3 == second.byte3) &&
1802 (first.byte4 == second.byte4) &&
1803 (first.byte5 == second.byte5) &&
1804 (first.byte6 == second.byte6) &&
1805 (first.byte7 == second.byte7) &&
1806 (first.byte8 == second.byte8) &&
1807 (first.byte9 == second.byte9) &&
1808 (first.byte10 == second.byte10) &&
1809 (first.byte11 == second.byte11) &&
1810 (first.byte12 == second.byte12) &&
1811 (first.byte13 == second.byte13) &&
1812 (first.byte14 == second.byte14) &&
1813 (first.byte15 == second.byte15);
1814}
codec_t first
Definition sdl2.c:423
uint32_t second
Definition sdl2.c:424

References first, and second.

◆ print_output_modes()

static void print_output_modes ( IDeckLink * deckLink,
const char * query_prop_fcc )
static

Definition at line 2161 of file decklink.cpp.

2162{
2163 IDeckLinkOutput* deckLinkOutput = NULL;
2164 IDeckLinkDisplayModeIterator* displayModeIterator = NULL;
2165 IDeckLinkDisplayMode* displayMode = NULL;
2166 HRESULT result;
2167 int displayModeNumber = 0;
2168
2169 // Query the DeckLink for its configuration interface
2170 result = deckLink->QueryInterface(IID_IDeckLinkOutput, (void**)&deckLinkOutput);
2171 if (result != S_OK)
2172 {
2173 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Could not obtain the IDeckLinkOutput interface - result = %08x\n", (int) result);
2174 if (result == E_NOINTERFACE) {
2175 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Device doesn't support video playback.\n");
2176 }
2177 goto bail;
2178 }
2179
2180 // Obtain an IDeckLinkDisplayModeIterator to enumerate the display modes supported on output
2181 result = deckLinkOutput->GetDisplayModeIterator(&displayModeIterator);
2182 if (result != S_OK)
2183 {
2184 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Could not obtain the video output display mode iterator - result = %08x\n", (int) result);
2185 goto bail;
2186 }
2187
2188 // List all supported output display modes
2189 printf("\tdisplay modes:\n");
2190 while (displayModeIterator->Next(&displayMode) == S_OK)
2191 {
2192 BMD_STR displayModeString = NULL;
2193
2194 result = displayMode->GetName(&displayModeString);
2195
2196 if (result == S_OK)
2197 {
2198 BMDTimeValue frameRateDuration;
2199 BMDTimeScale frameRateScale;
2200
2201 // Obtain the display mode's properties
2202 string flags_str = bmd_get_flags_str(displayMode->GetFlags());
2203 int modeWidth = displayMode->GetWidth();
2204 int modeHeight = displayMode->GetHeight();
2205 uint32_t field_dominance_n = ntohl(displayMode->GetFieldDominance());
2206 displayMode->GetFrameRate(&frameRateDuration, &frameRateScale);
2207 printf(
2208 "\t\t%2d) %-20s %d x %d \t %2.2f FPS %.4s, "
2209 "flags: %s\n",
2210 displayModeNumber,
2211 get_str_from_bmd_api_str(displayModeString).c_str(),
2212 modeWidth, modeHeight,
2213 (float) ((double) frameRateScale /
2214 (double) frameRateDuration),
2215 (char *) &field_dominance_n, flags_str.c_str());
2216 release_bmd_api_str(displayModeString);
2217 }
2218
2219 // Release the IDeckLinkDisplayMode object to prevent a leak
2220 displayMode->Release();
2221
2222 displayModeNumber++;
2223 }
2224 color_printf("\n\tsupported pixel formats:" TERM_BOLD);
2225 for (auto & c : uv_to_bmd_codec_map) {
2226 if (decklink_supports_codec(deckLinkOutput, c.second)) {
2227 printf(" %s", get_codec_name(c.first));
2228 }
2229 }
2231
2232 if (query_prop_fcc != nullptr) {
2233 IDeckLinkProfileAttributes *deckLinkAttributes = nullptr;
2234 if (deckLink->QueryInterface(IID_IDeckLinkProfileAttributes,
2235 (void **) &deckLinkAttributes) ==
2236 S_OK) {
2237 cout << "\n";
2238 print_bmd_attribute(deckLinkAttributes, query_prop_fcc);
2239 deckLinkAttributes->Release();
2240 } else {
2241 MSG(ERROR, "Could not query device attributes.\n\n");
2242 }
2243 }
2244
2245 color_printf("\n");
2246
2247bail:
2248 // Ensure that the interfaces we obtained are released to prevent a memory leak
2249 if (displayModeIterator != NULL)
2250 displayModeIterator->Release();
2251
2252 if (deckLinkOutput != NULL)
2253 deckLinkOutput->Release();
2254}
const char * get_codec_name(codec_t codec)
string bmd_get_flags_str(BMDDisplayModeFlags flags)
void print_bmd_attribute(IDeckLinkProfileAttributes *deckLinkAttributes, const char *query_prop_fcc)
int color_printf(const char *format,...)
#define TERM_BOLD
Definition color_out.h:48
#define TERM_RESET
Definition color_out.h:47

References bmd_get_flags_str(), BMD_STR, color_printf(), decklink_supports_codec(), get_codec_name(), get_str_from_bmd_api_str(), LOG_LEVEL_ERROR, log_msg(), MOD_NAME, MSG, print_bmd_attribute(), release_bmd_api_str(), TERM_BOLD, TERM_RESET, and uv_to_bmd_codec_map.

Referenced by show_help().

Here is the call graph for this function:

◆ REGISTER_MODULE()

REGISTER_MODULE ( decklink ,
& display_decklink_info,
LIBRARY_CLASS_VIDEO_DISPLAY ,
VIDEO_DISPLAY_ABI_VERSION  )

◆ set_audio_props()

static void set_audio_props ( state_decklink * s,
IDeckLinkConfiguration * deckLinkConfiguration,
unsigned int audio_output )
static

Definition at line 1330 of file decklink.cpp.

1333{
1334 if (audio_output == 0U) {
1335 s->play_audio = false;
1336 return;
1337 }
1338 s->play_audio = true;
1339
1340 int64_t max_aud_chans = 0;
1341 HRESULT result = s->deckLinkAttributes->GetInt(
1342 BMDDeckLinkMaximumAudioChannels, &max_aud_chans);
1343 if (result != S_OK) {
1344 MSG(WARNING, "Cannot get maximum audio channels: %s\n",
1345 bmd_hresult_to_string(result).c_str());
1346 } else {
1347 s->max_aud_chans = (int) max_aud_chans;
1349 }
1350 MSG(VERBOSE, "Using maximum audio channels: %d\n", s->max_aud_chans);
1351
1352 MSG(INFO, "Using audio output: %s\n",
1353 get_audio_conn_flag_name(audio_output));
1354
1355 /* Actually no action is required to set audio connection because BMD
1356 * card plays audio through all its outputs (AES/SDI/analog) .... */
1357 BMDAudioOutputAnalogAESSwitch audioConnection{};
1358 switch (audio_output) {
1360 return;
1362 audioConnection = bmdAudioOutputSwitchAESEBU;
1363 break;
1365 audioConnection = bmdAudioOutputSwitchAnalog;
1366 break;
1367 default:
1368 MSG(ERROR, "Unsupporetd audio connection: %d.\n", audio_output);
1369 abort();
1370 }
1371 /* .... one exception is a card that has switchable cables between
1372 * AES/EBU and analog. (But this applies only for channels 3 and above.)
1373 */
1374 result = deckLinkConfiguration->SetInt(
1375 bmdDeckLinkConfigAudioOutputAESAnalogSwitch, audioConnection);
1376 if (result == S_OK) { // has switchable channels
1377 MSG(INFO, "Card with switchable audio channels detected. "
1378 "Switched to correct format.\n");
1379 } else if (result == E_NOTIMPL) {
1380 // normal case - without switchable channels
1381 MSG(VERBOSE,
1382 "Not setting switchable AESEBU/analog - not supported.\n");
1383 } else {
1384 MSG(WARNING,
1385 "Unable to switch audio output for channels 3 or "
1386 "above although the card shall support it: %s\nCheck if "
1387 "it is ok. Continuing anyway.\n",
1388 bmd_hresult_to_string(result).c_str());
1389 }
1390}
#define DISPLAY_FLAG_AUDIO_ANALOG
#define DISPLAY_FLAG_AUDIO_AESEBU
const char * get_audio_conn_flag_name(int audio_init_flag)
#define DISPLAY_FLAG_AUDIO_EMBEDDED

References bmd_hresult_to_string(), CHECK_CH_COUNT, state_decklink::deckLinkAttributes, DISPLAY_FLAG_AUDIO_AESEBU, DISPLAY_FLAG_AUDIO_ANALOG, DISPLAY_FLAG_AUDIO_EMBEDDED, get_audio_conn_flag_name(), state_decklink::max_aud_chans, MSG, and state_decklink::play_audio.

Referenced by display_decklink_init().

Here is the call graph for this function:

◆ set_low_latency()

static void set_low_latency ( struct state_decklink * s,
bool on )
static

Definition at line 1187 of file decklink.cpp.

1188{
1189 if (on) {
1190 MSG(WARNING, "Low latency option unneeded (implicit).\n");
1191 assert(s->low_latency); // check if really so
1192 return;
1193 }
1194 MSG(WARNING, "Deprecated, do not use - "
1195 "see option \"synchroninzed\" instead.\n");
1196 s->low_latency = false;
1197}

References state_decklink::low_latency, and MSG.

Referenced by settings_init().

◆ settings_init()

static bool settings_init ( struct state_decklink * s,
const char * fmt,
string & cardId )
static

Definition at line 1199 of file decklink.cpp.

1200 {
1201 if (strlen(fmt) == 0) {
1202 return true;
1203 }
1204
1205 auto tmp = static_cast<char *>(alloca(strlen(fmt) + 1));
1206 strcpy(tmp, fmt);
1207 char *ptr;
1208 char *save_ptr = nullptr;
1209
1210 ptr = strtok_r(tmp, ":", &save_ptr);
1211 assert(ptr != nullptr);
1212 int i = 0;
1213 bool first_option_is_device = true;
1214 while (ptr[i] != '\0') {
1215 if (!isdigit(ptr[i]) && ptr[i] != ',') {
1216 first_option_is_device = false;
1217 break;
1218 }
1219 i++;
1220 }
1221 if (first_option_is_device) {
1222 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Unnamed device index "
1223 "deprecated. Use \"device=%s\" instead.\n", ptr);
1224 cardId = ptr;
1225 ptr = strtok_r(nullptr, ":", &save_ptr);
1226 }
1227
1228 while (ptr != nullptr) {
1229 const char *val = strchr(ptr, '=') + 1;
1230 if (IS_KEY_PREFIX(ptr, "device")) {
1231 cardId = strchr(ptr, '=') + 1;
1232 } else if (IS_KEY_PREFIX(ptr, "profile")) {
1233 s->profile_req.parse(strchr(ptr, '=') + 1);
1234 } else if (strcasecmp(ptr, "3D") == 0) {
1235 s->stereo = true;
1236 } else if (strcasecmp(ptr, "timecode") == 0) {
1237 s->emit_timecode = true;
1238 } else if (strcasecmp(ptr, "single-link") == 0) {
1239 s->device_options[bmdDeckLinkConfigSDIOutputLinkConfiguration].set_int(bmdLinkConfigurationSingleLink);
1240 } else if (strcasecmp(ptr, "dual-link") == 0) {
1241 s->device_options[bmdDeckLinkConfigSDIOutputLinkConfiguration].set_int(bmdLinkConfigurationDualLink);
1242 } else if (strcasecmp(ptr, "quad-link") == 0) {
1243 s->device_options[bmdDeckLinkConfigSDIOutputLinkConfiguration].set_int(bmdLinkConfigurationQuadLink);
1244 } else if (strcasecmp(ptr, "full-duplex") == 0) {
1245 s->profile_req.set_int(bmdProfileOneSubDeviceFullDuplex);
1246 } else if (strcasecmp(ptr, "half-duplex") == 0) {
1247 s->profile_req.set_int(bmdDuplexHalf);
1248 } else if (strcasecmp(ptr, "simplex") == 0) {
1249 s->profile_req.set_int(bmdProfileOneSubDeviceHalfDuplex);
1250 } else if (strcasecmp(ptr, "LevelA") == 0) {
1251 s->device_options[bmdDeckLinkConfigSMPTELevelAOutput].set_flag(true);
1252 } else if (strcasecmp(ptr, "LevelB") == 0) {
1253 s->device_options[bmdDeckLinkConfigSMPTELevelAOutput].set_flag(false);
1254 } else if (strncasecmp(ptr, "HDMI3DPacking=", strlen("HDMI3DPacking=")) == 0) {
1255 char *packing = ptr + strlen("HDMI3DPacking=");
1256 if (strcasecmp(packing, "SideBySideHalf") == 0) {
1257 s->device_options[bmdDeckLinkConfigHDMI3DPackingFormat].set_int(bmdVideo3DPackingSidebySideHalf);
1258 } else if (strcasecmp(packing, "LineByLine") == 0) {
1259 s->device_options[bmdDeckLinkConfigHDMI3DPackingFormat].set_int(bmdVideo3DPackingLinebyLine);
1260 } else if (strcasecmp(packing, "TopAndBottom") == 0) {
1261 s->device_options[bmdDeckLinkConfigHDMI3DPackingFormat].set_int(bmdVideo3DPackingTopAndBottom);
1262 } else if (strcasecmp(packing, "FramePacking") == 0) {
1263 s->device_options[bmdDeckLinkConfigHDMI3DPackingFormat].set_int(bmdVideo3DPackingFramePacking);
1264 } else if (strcasecmp(packing, "LeftOnly") == 0) {
1265 s->device_options[bmdDeckLinkConfigHDMI3DPackingFormat].set_int(bmdVideo3DPackingRightOnly);
1266 } else if (strcasecmp(packing, "RightOnly") == 0) {
1267 s->device_options[bmdDeckLinkConfigHDMI3DPackingFormat].set_int(bmdVideo3DPackingLeftOnly);
1268 } else {
1269 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unknown HDMI 3D packing %s.\n", packing);
1270 return false;
1271 }
1272 } else if (strncasecmp(ptr, "audio_level=", strlen("audio_level=")) == 0) {
1274 [bmdDeckLinkConfigAnalogAudioConsumerLevels] =
1276 } else if (IS_KEY_PREFIX(ptr, "conversion")) {
1277 s->device_options[bmdDeckLinkConfigVideoOutputConversionMode].parse(strchr(ptr, '=') + 1);
1278 } else if (is_prefix_of(ptr, "Use1080pNotPsF") || is_prefix_of(ptr, "Use1080PsF")) {
1279 s->device_options[bmdDeckLinkConfigOutput1080pAsPsF].parse(strchr(ptr, '=') + 1);
1280 if (strncasecmp(ptr, "Use1080pNotPsF", strlen("Use1080pNotPsF")) == 0) { // compat, inverse
1281 s->device_options[bmdDeckLinkConfigOutput1080pAsPsF].set_flag(s->device_options[bmdDeckLinkConfigOutput1080pAsPsF].get_flag());
1282 }
1283 } else if (strcasecmp(ptr, "low-latency") == 0 || strcasecmp(ptr, "no-low-latency") == 0) {
1284 set_low_latency(s, strcasecmp(ptr, "low-latency") == 0);
1285 } else if (IS_PREFIX(ptr, "synchronized")) {
1286 s->low_latency = false;
1287 s->delegate.SetSynchronized(strchr(ptr, '='));
1288 } else if (strcasecmp(ptr, "quad-square") == 0 || strcasecmp(ptr, "no-quad-square") == 0) {
1289 s->quad_square_division_split.set_flag(strcasecmp(ptr, "quad-square") == 0);
1290 } else if (strncasecmp(ptr, "hdr", strlen("hdr")) == 0) {
1291 s->requested_hdr_mode.EOTF = static_cast<int64_t>(HDR_EOTF::HDR); // default
1292 if (strncasecmp(ptr, "hdr=", strlen("hdr=")) == 0) {
1293 try {
1294 s->requested_hdr_mode.Init(ptr + strlen("hdr="));
1295 } catch (ug_no_error const &e) {
1296 return false;
1297 } catch (exception const &e) {
1298 LOG(LOG_LEVEL_ERROR) << MOD_NAME << "HDR mode init: " << e.what() << "\n";
1299 return false;
1300 }
1301 }
1302 } else if (strstr(ptr, "keep-settings") == ptr) {
1303 s->keep_device_defaults = true;
1304 } else if (strstr(ptr, "drift_fix") == ptr) {
1306 } else if (strncasecmp(ptr, "maxresample=", strlen("maxresample=")) == 0) {
1307 s->audio_drift_fixer.set_max_hz(parse_uint32(strchr(ptr, '=') + 1));
1308 } else if (strncasecmp(ptr, "minresample=", strlen("minresample=")) == 0) {
1309 s->audio_drift_fixer.set_min_hz(parse_uint32(strchr(ptr, '=') + 1));
1310 } else if (strncasecmp(ptr, "targetbuffer=", strlen("targetbuffer=")) == 0) {
1311 s->audio_drift_fixer.set_target_buffer(parse_uint32(strchr(ptr, '=') + 1));
1312 } else if ((strchr(ptr, '=') != nullptr && strchr(ptr, '=') - ptr == 4) || strlen(ptr) == 4) {
1313 s->device_options[(BMDDeckLinkConfigurationID) bmd_read_fourcc(ptr)].parse(strchr(ptr, '=') + 1);
1314 } else {
1315 log_msg(LOG_LEVEL_ERROR, MOD_NAME "unknown option in config string: %s\n", ptr);
1316 return false;
1317 }
1318 ptr = strtok_r(nullptr, ":", &save_ptr);
1319 }
1320
1321 return true;
1322}
bool bmd_parse_audio_levels(const char *opt) noexcept(false)
TOREMOVE (implicit "aacl" option is preferred)
uint32_t bmd_read_fourcc(const char *str)
void set_target_buffer(uint32_t target_buffer)
Set the target buffer object.
void set_max_hz(uint32_t max_hz)
Set the max hz object.
void set_min_hz(uint32_t min_hz)
Set the min hz object.
#define IS_PREFIX(tok, key)
similar as above, but also key without a value is accepted (value optional)
Definition macros.h:142
uint32_t parse_uint32(const char *value_str) noexcept(false)
Definition misc.cpp:296
bool is_prefix_of(const char *haystack, const char *needle)
Definition string.c:91
void set_int(int64_t val_)
void parse(const char *)
void set_flag(bool val_)

References state_decklink::audio_drift_fixer, bmd_parse_audio_levels(), bmd_read_fourcc(), state_decklink::delegate, state_decklink::device_options, state_decklink::emit_timecode, AudioDriftFixer::enable(), fmt, IS_KEY_PREFIX, IS_PREFIX, is_prefix_of(), state_decklink::keep_device_defaults, LOG, LOG_LEVEL_ERROR, LOG_LEVEL_WARNING, log_msg(), state_decklink::low_latency, MOD_NAME, bmd_option::parse(), parse_uint32(), state_decklink::profile_req, state_decklink::quad_square_division_split, state_decklink::requested_hdr_mode, bmd_option::set_flag(), bmd_option::set_int(), set_low_latency(), AudioDriftFixer::set_max_hz(), AudioDriftFixer::set_min_hz(), AudioDriftFixer::set_target_buffer(), state_decklink::stereo, and val.

Here is the call graph for this function:

◆ show_help()

static void show_help ( bool full,
const char * query_prop_fcc = nullptr )
static
Parameters
query_prop_fccif not NULL, print corresponding BMDDeckLinkAttribute

Definition at line 550 of file decklink.cpp.

551 {
552 int numDevices = 0;
553
554 col() << "DeckLink display options:\n";
555 col() << SBOLD(SRED("\t-d decklink")
556 << "[:d[evice]=<device>][:Level{A|B}][:3D][:half-"
557 "duplex][:HDR[=<t>][:drift_fix]]\n");
558 col() << SBOLD(SRED("\t-d decklink") << ":[full]help") << " | "
559 << SBOLD(SRED("-d decklink") << ":query=<FourCC>"
560 "\n");
561 col() << "\nOptions:\n";
562 if (!full) {
563 col() << SBOLD("\tfullhelp") << "\tdisplay additional options and more details\n";
564 }
565 col() << SBOLD("\tdevice") << "\t\tindex or name of output device\n";
566 col() << SBOLD("\tLevelA/LevelB") << "\tspecifies 3G-SDI output level\n";
567 col() << SBOLD("\t3D") << "\t\t3D stream will be received (see also HDMI3DPacking option)\n";
568 col() << SBOLD("\thalf-duplex | full-duplex | simplex")
569 << "\tset a profile that allows maximal number of simultaneous "
570 "IOs / set device to better compatibility (3D, dual-link) / "
571 "use all connectors as single input\n";
572 col() << SBOLD("\tHDR[=HDR|PQ|HLG|<int>|help]") << " - enable HDR metadata (optionally specifying EOTF, int 0-7 as per CEA 861.), help for extended help\n";
573 col() << SBOLD("\tdrift_fix") << " activates a time drift fix for the DeckLink cards with resampler (experimental)\n";
574
575 col() << SBOLD("\t<option_FourCC>=<value>")
576 << "\tarbitrary BMD option (given a FourCC) and corresponding "
577 "value, i.a.:\n";
578 col()
579 << SBOLD("\t\taacl[=no]")
580 << "\tset maximum analog audio attenuation (consumer line level)\n";
581 col() << SBOLD("\t\tvoio=blac|lafa")
582 << "\tdisplay either black or last frame when idle\n";
583
584 if (!full) {
585 col() << SBOLD("\tconversion") << "\toutput size conversion, use '-d decklink:fullhelp' for list of conversions\n";
586 col() << "\n\t(other options available, use \"" << SBOLD("fullhelp") << "\" to see complete list of options)\n";
587 } else {
588 col() << SBOLD("\tsingle-link/dual-link/quad-link") << "\tspecifies if the video output will be in a single-link (HD/3G/6G/12G), dual-link HD-SDI mode or quad-link HD/3G/6G/12G\n";
589 col() << SBOLD("\ttimecode") << "\temit timecode\n";
590 col() << SBOLD("\t[no-]quad-square") << " set Quad-link SDI is output in Square Division Quad Split mode\n";
591 col() << SBOLD("\tsynchronized[=m[,M]]")
592 << " use regular scheduled mode for synchrized output"
593 "\n\t\t(m - minimum "
594 "scheduled frames /default "
595 << PlaybackDelegate::DEFAULT_MIN_SCHED_FRAMES
596 << "/, M - max sched\n\t\tframes /default "
597 << PlaybackDelegate::DEFAULT_MAX_SCHED_FRAMES << "/), shortcut sync\n";
598 col() << SBOLD("\tconversion") << "\toutput size conversion, can be:\n" <<
599 SBOLD("\t\tnone") << " - no conversion\n" <<
600 SBOLD("\t\tltbx") << " - down-converted letterbox SD\n" <<
601 SBOLD("\t\tamph") << " - down-converted anamorphic SD\n" <<
602 SBOLD("\t\t720c") << " - HD720 to HD1080 conversion\n" <<
603 SBOLD("\t\tHWlb") << " - simultaneous output of HD and down-converted letterbox SD\n" <<
604 SBOLD("\t\tHWam") << " - simultaneous output of HD and down-converted anamorphic SD\n" <<
605 SBOLD("\t\tHWcc") << " - simultaneous output of HD and center cut SD\n" <<
606 SBOLD("\t\txcap") << " - simultaneous output of 720p and 1080p cross-conversion\n" <<
607 SBOLD("\t\tua7p") << " - simultaneous output of SD and up-converted anamorphic 720p\n" <<
608 SBOLD("\t\tua1i") << " - simultaneous output of SD and up-converted anamorphic 1080i\n" <<
609 SBOLD("\t\tu47p") << " - simultaneous output of SD and up-converted anamorphic widescreen aspect ratio 14:9 to 720p\n" <<
610 SBOLD("\t\tu41i") << " - simultaneous output of SD and up-converted anamorphic widescreen aspect ratio 14:9 to 1080i\n" <<
611 SBOLD("\t\tup7p") << " - simultaneous output of SD and up-converted pollarbox 720p\n" <<
612 SBOLD("\t\tup1i") << " - simultaneous output of SD and up-converted pollarbox 1080i\n";
613 col() << SBOLD("\tHDMI3DPacking") << " can be (used in conjunction with \"3D\" option):\n" <<
614 SBOLD("\t\tSideBySideHalf, LineByLine, TopAndBottom, FramePacking, LeftOnly, RightOnly\n");
615 col() << SBOLD("\tUse1080PsF[=true|false|keep]") << " flag sets use of PsF on output instead of progressive (default is false)\n";
616 col() << SBOLD("\tprofile=<P>") << "\tuse desired device profile:\n";
618 col() << SBOLD("\tmaxresample=<N>") << " maximum amount the resample delta can be when scaling is applied. Measured in Hz\n";
619 col() << SBOLD("\tminresample=<N>") << " minimum amount the resample delta can be when scaling is applied. Measured in Hz\n";
620 col() << SBOLD("\ttargetbuffer=<N>") << " target amount of samples to have in the buffer (per channel)\n";
621 col() << SBOLD("\tkeep-settings") << "\tdo not apply any DeckLink settings by UG than required (keep user-selected defaults)\n";
622 col() << SBOLD("\tquery=<FourCC>") << "\tquery specified device argument in help listing\n";
623 }
624
625 col() << "\nRecognized pixel formats:";
626 for_each(uv_to_bmd_codec_map.cbegin(), uv_to_bmd_codec_map.cend(), [](auto const &i) { col() << " " << SBOLD(get_codec_name(i.first)); } );
627 cout << "\n";
628
629 col() << "Devices (idx, topological ID, name):\n";
630 // Create an IDeckLinkIterator object to enumerate all DeckLink cards in the system
631 bool com_initialized = false;
632
633 // Enumerate all cards in this system
634 const bool natural_sort =
636 for (auto &d :
637 bmd_get_sorted_devices(&com_initialized, true, natural_sort)) {
638 IDeckLink *deckLink = get<0>(d).get();
639 string deviceName = bmd_get_device_name(deckLink);
640 if (deviceName.empty()) {
641 deviceName = "(unable to get name)";
642 }
643
644 char index[STR_LEN] = "";
645 if (!natural_sort) {
646 snprintf(index, sizeof index,
647 TBOLD("%c") ") ", get<char>(d));
648 }
649 if (full || natural_sort) {
650 snprintf(index + strlen(index),
651 sizeof index - strlen(index), TBOLD("%d") ") ",
652 get<int>(d));
653 }
654 // *** Print the model name of the DeckLink card
655 color_printf("\t%s" TBOLD("%6x") ") " TBOLD(
656 TGREEN("%s")) "\n",
657 index, get<unsigned>(d),
658 deviceName.c_str());
659 if (full) {
660 print_output_modes(deckLink, query_prop_fcc);
661 }
662
663 // Increment the total number of DeckLink cards found
664 numDevices++;
665 }
666
667 if (!full) {
668 col() << "(use \"" << SBOLD("fullhelp") << "\" to see device modes)\n";
669 }
670
671 decklink_uninitialize(&com_initialized);
672
673 // If no DeckLink cards were found in the system, inform the user
674 if (numDevices == 0)
675 {
676 log_msg(LOG_LEVEL_WARNING, "\nNo Blackmagic Design devices were found.\n");
677 return;
678 }
679
680 printf("\n");
681 if (full) {
683 printf("\n");
684 }
685 }
void print_bmd_device_profiles(const char *line_prefix)
void print_decklink_version()
#define BMD_NAT_SORT
#define SRED(x)
Definition color_out.h:85
#define TGREEN(x)
Definition color_out.h:72
#define SBOLD(x)
Definition color_out.h:80
#define TBOLD(x)
Definition color_out.h:70
@ STR_LEN
"standard" string length placeholder
Definition macros.h:134

References bmd_get_device_name(), bmd_get_sorted_devices(), BMD_NAT_SORT, color_printf(), decklink_uninitialize(), get_commandline_param(), LOG_LEVEL_WARNING, log_msg(), print_bmd_device_profiles(), print_decklink_version(), print_output_modes(), SBOLD, SRED, STR_LEN, TBOLD, TGREEN, and uv_to_bmd_codec_map.

Here is the call graph for this function:

◆ update_timecode()

static void update_timecode ( DeckLinkTimecode * tc,
double fps )
static

Definition at line 763 of file decklink.cpp.

764{
765 const float epsilon = 0.005;
766 uint8_t hours, minutes, seconds, frames;
767 BMDTimecodeBCD bcd;
768 bool dropFrame = false;
769
770 if(ceil(fps) - fps > epsilon) { /* NTSCi drop framecode */
771 dropFrame = true;
772 }
773
774 tc->GetComponents (&hours, &minutes, &seconds, &frames);
775 frames++;
776
777 if((double) frames > fps - epsilon) {
778 frames = 0;
779 seconds++;
780 if(seconds >= 60) {
781 seconds = 0;
782 minutes++;
783 if(dropFrame) {
784 if(minutes % 10 != 0)
785 seconds = 2;
786 }
787 if(minutes >= 60) {
788 minutes = 0;
789 hours++;
790 if(hours >= 24) {
791 hours = 0;
792 }
793 }
794 }
795 }
796
797 bcd = (frames % 10) | (frames / 10) << 4 | (seconds % 10) << 8 | (seconds / 10) << 12 | (minutes % 10) << 16 | (minutes / 10) << 20 |
798 (hours % 10) << 24 | (hours / 10) << 28;
799
800 tc->SetBCD(bcd);
801}

References video_frame::fps.

Referenced by display_decklink_putf().

Variable Documentation

◆ display_decklink_info

const struct video_display_info display_decklink_info
static
Initial value:
= {
NULL,
}

Definition at line 2256 of file decklink.cpp.