UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
decklink.cpp File Reference
#include <algorithm>
#include <cassert>
#include <cctype>
#include <chrono>
#include <climits>
#include <condition_variable>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <exception>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <memory>
#include <mutex>
#include <queue>
#include <string>
#include <tuple>
#include <unordered_map>
#include <utility>
#include <vector>
#include "blackmagic_common.hpp"
#include "audio/types.h"
#include "audio/utils.h"
#include "compat/htonl.h"
#include "compat/strings.h"
#include "debug.h"
#include "host.h"
#include "lib_common.h"
#include "types.h"
#include "utils/color_out.h"
#include "utils/macros.h"
#include "utils/math.h"
#include "utils/windows.h"
#include "video.h"
#include "video_capture.h"
Include dependency graph for decklink.cpp:

Go to the source code of this file.

Classes

struct  device_state
 
struct  vidcap_decklink_state
 
struct  vidcap_decklink_state::audio
 
class  VideoDelegate
 

Macros

#define CALL_AND_CHECK(cmd, ...)
 
#define CALL_AND_CHECK_2(cmd, name)
 
#define CALL_AND_CHECK_3(cmd, name, msg)
 
#define CALL_AND_CHECK_CHOOSER(...)
 
#define EXIT_IF_FAILED(cmd, name)
 
#define GET_3TH_ARG(arg1, arg2, arg3, ...)
 
#define INIT_ERR()
 
#define MOD_NAME   "[DeckLink capture] "
 
#define RELEASE_IF_NOT_NULL(x)
 
#define STDMETHODCALLTYPE
 

Functions

static void cleanup_common (struct vidcap_decklink_state *s)
 
static bool decklink_cap_configure_audio (struct vidcap_decklink_state *s, unsigned int audio_src_flag, BMDAudioConnection *audioConnection)
 
static int decklink_help (bool full, const char *query_prop_fcc=nullptr)
 
static bool detect_format (struct vidcap_decklink_state *s, BMDDisplayMode *outDisplayMode, struct device_state *device)
 
static list< tuple< int, string, string, string > > get_input_modes (IDeckLink *deckLink)
 
static int nr_frames (struct vidcap_decklink_state *s)
 
static void parse_devices (struct vidcap_decklink_state *s, const char *devs)
 
static bool parse_option (struct vidcap_decklink_state *s, const char *opt)
 
static void postprocess_frame (struct vidcap_decklink_state *s)
 
static void print_input_modes (IDeckLink *deckLink)
 
static audio_frame * process_new_audio_packets (struct vidcap_decklink_state *s)
 
 REGISTER_MODULE (decklink, &vidcap_decklink_info, LIBRARY_CLASS_VIDEO_CAPTURE, VIDEO_CAPTURE_ABI_VERSION)
 
static HRESULT set_display_mode_properties (struct vidcap_decklink_state *s, struct tile *tile, IDeckLinkDisplayMode *displayMode, BMDPixelFormat *pf)
 
static bool settings_init (struct vidcap_decklink_state *s, char *fmt)
 
static bool settings_init_key_val (struct vidcap_decklink_state *s, char **save_ptr)
 
static void vidcap_decklink_done (void *state)
 
static struct video_frame * vidcap_decklink_grab (void *state, struct audio_frame **audio)
 
static int vidcap_decklink_init (struct vidcap_params *params, void **state)
 
static void vidcap_decklink_print_card_info (IDeckLink *deckLink, const char *query_prop_fcc)
 
static void vidcap_decklink_probe (device_info **available_cards, int *card_count, void(**deleter)(void *))
 

Variables

constexpr const int DEFAULT_AUDIO_BPS = 4
 
constexpr const size_t MAX_AUDIO_PACKETS = 10
 
static const struct video_capture_info vidcap_decklink_info
 

Macro Definition Documentation

◆ CALL_AND_CHECK

#define CALL_AND_CHECK ( cmd,
... )
Value:
CALL_AND_CHECK_CHOOSER(__VA_ARGS__)(cmd, __VA_ARGS__)

Definition at line 165 of file decklink.cpp.

Referenced by display_decklink_done(), device_state::init(), and VideoDelegate::VideoInputFormatChanged().

◆ CALL_AND_CHECK_2

#define CALL_AND_CHECK_2 ( cmd,
name )
Value:
do {\
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 143 of file decklink.cpp.

143#define CALL_AND_CHECK_2(cmd, name) \
144 do {\
145 HRESULT result = cmd;\
146 if (FAILED(result)) {;\
147 LOG(LOG_LEVEL_WARNING) << MOD_NAME << name << ": " << bmd_hresult_to_string(result) << "\n";\
148 }\
149 } while (0)

◆ CALL_AND_CHECK_3

#define CALL_AND_CHECK_3 ( cmd,
name,
msg )
Value:
do {\
HRESULT result = cmd;\
if (FAILED(result)) {;\
LOG(LOG_LEVEL_WARNING) << MOD_NAME << name << ": " << bmd_hresult_to_string(result) << "\n";\
} else {\
LOG(LOG_LEVEL_INFO) << MOD_NAME << name << ": " << msg << "\n";\
}\
} while (0)
#define LOG_LEVEL_INFO
normal reporting
Definition debug.h:62

Definition at line 151 of file decklink.cpp.

151#define CALL_AND_CHECK_3(cmd, name, msg) \
152 do {\
153 HRESULT result = cmd;\
154 if (FAILED(result)) {;\
155 LOG(LOG_LEVEL_WARNING) << MOD_NAME << name << ": " << bmd_hresult_to_string(result) << "\n";\
156 } else {\
157 LOG(LOG_LEVEL_INFO) << MOD_NAME << name << ": " << msg << "\n";\
158 }\
159 } while (0)

◆ CALL_AND_CHECK_CHOOSER

#define CALL_AND_CHECK_CHOOSER ( ...)
Value:

Definition at line 162 of file decklink.cpp.

162#define CALL_AND_CHECK_CHOOSER(...) \
163 GET_3TH_ARG(__VA_ARGS__, CALL_AND_CHECK_3, CALL_AND_CHECK_2, )

◆ EXIT_IF_FAILED

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

Definition at line 133 of file decklink.cpp.

133#define EXIT_IF_FAILED(cmd, name) \
134 do {\
135 HRESULT result = cmd;\
136 if (FAILED(result)) {;\
137 LOG(LOG_LEVEL_ERROR) << MOD_NAME << name << ": " << bmd_hresult_to_string(result) << "\n";\
138 goto error;\
139 }\
140 } while (0)

◆ GET_3TH_ARG

#define GET_3TH_ARG ( arg1,
arg2,
arg3,
... )
Value:
arg3

Definition at line 161 of file decklink.cpp.

◆ INIT_ERR

#define INIT_ERR ( )
Value:
do { RELEASE_IF_NOT_NULL(displayMode); RELEASE_IF_NOT_NULL(displayModeIterator); return false; } while (0)

Definition at line 1134 of file decklink.cpp.

Referenced by device_state::init().

◆ MOD_NAME

◆ 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.

Referenced by VideoDelegate::~VideoDelegate(), cleanup_common(), get_input_modes(), vidcap_decklink_print_card_info(), vidcap_decklink_probe(), and VideoDelegate::VideoInputFrameArrived().

◆ STDMETHODCALLTYPE

#define STDMETHODCALLTYPE

Definition at line 94 of file decklink.cpp.

Function Documentation

◆ cleanup_common()

static void cleanup_common ( struct vidcap_decklink_state * s)
static

Definition at line 1498 of file decklink.cpp.

1498 {
1499 while (!s->audioPackets.empty()) {
1500 auto *audioPacket = s->audioPackets.front();
1501 s->audioPackets.pop();
1502 audioPacket->Release();
1503 }
1504
1505 for (int i = 0; i < s->devices_cnt; ++i) {
1506 RELEASE_IF_NOT_NULL(s->state[i].deckLinkConfiguration);
1507 RELEASE_IF_NOT_NULL(s->state[i].deckLinkAttributes);
1508 RELEASE_IF_NOT_NULL(s->state[i].deckLinkInput);
1509 RELEASE_IF_NOT_NULL(s->state[i].deckLink);
1510 }
1511
1512 free(s->audio.data);
1513
1514 vf_free(s->frame);
1515 delete s;
1516}
void vf_free(struct video_frame *buf)
Frees video_frame structure.

References vidcap_decklink_state::audioPackets, vidcap_decklink_state::devices_cnt, vidcap_decklink_state::frame, RELEASE_IF_NOT_NULL, vidcap_decklink_state::state, and vf_free().

Referenced by vidcap_decklink_done(), and vidcap_decklink_init().

Here is the call graph for this function:

◆ decklink_cap_configure_audio()

static bool decklink_cap_configure_audio ( struct vidcap_decklink_state * s,
unsigned int audio_src_flag,
BMDAudioConnection * audioConnection )
static

Definition at line 1086 of file decklink.cpp.

1086 {
1087 if (audio_src_flag == 0U) {
1088 return true;
1089 }
1090
1091 s->state[0].audio = true;
1092 switch (audio_src_flag) {
1094 *audioConnection = bmdAudioConnectionEmbedded;
1095 break;
1097 *audioConnection = bmdAudioConnectionAESEBU;
1098 break;
1100 *audioConnection = bmdAudioConnectionAnalog;
1101 break;
1102 default:
1103 LOG(LOG_LEVEL_FATAL) << MOD_NAME << "Unexpected audio flag " << audio_src_flag << " encountered.\n";
1104 abort();
1105 }
1107 if (s->audio.bps != 2 && s->audio.bps != 4) {
1109 << MOD_NAME << "Unsupported audio Bps "
1111 << "! Supported is 2 or 4 bytes only!\n";
1112 return false;
1113 }
1114 if (audio_capture_sample_rate != 0 && audio_capture_sample_rate != bmdAudioSampleRate48kHz) {
1115 LOG(LOG_LEVEL_ERROR) << MOD_NAME "Unsupported sample rate " << audio_capture_sample_rate << "! Only " << bmdAudioSampleRate48kHz << " is supported.\n";
1116 return false;
1117 }
1118 s->audio.sample_rate = bmdAudioSampleRate48kHz;
1120 s->audio.max_size = (s->audio.sample_rate / 10) * s->audio.ch_count * s->audio.bps;
1121 s->audio.data = (char *) malloc(s->audio.max_size);
1122 s->audio.flags |= TIMESTAMP_VALID;
1123
1124 return true;
1125}
#define LOG(level)
Definition debug.h:313
#define LOG_LEVEL_FATAL
errors that prevent UG run
Definition debug.h:58
unsigned int audio_capture_bps
Definition host.cpp:164
unsigned int audio_capture_sample_rate
Definition host.cpp:165
unsigned int audio_capture_channels
Definition host.cpp:163
#define DEFAULT_AUDIO_CAPTURE_CHANNELS
Definition host.h:89
@ TIMESTAMP_VALID
timestamp set by source (in 90 kHz clock)
Definition types.h:223
#define VIDCAP_FLAG_AUDIO_AESEBU
AES/EBU audio.
#define VIDCAP_FLAG_AUDIO_ANALOG
(balanced) analog audio
#define VIDCAP_FLAG_AUDIO_EMBEDDED
HD-SDI embedded audio.

References audio_capture_bps, audio_capture_channels, audio_capture_sample_rate, DEFAULT_AUDIO_BPS, DEFAULT_AUDIO_CAPTURE_CHANNELS, LOG, LOG_LEVEL_ERROR, LOG_LEVEL_FATAL, MOD_NAME, vidcap_decklink_state::state, TIMESTAMP_VALID, VIDCAP_FLAG_AUDIO_AESEBU, VIDCAP_FLAG_AUDIO_ANALOG, and VIDCAP_FLAG_AUDIO_EMBEDDED.

Referenced by vidcap_decklink_init().

◆ decklink_help()

static int decklink_help ( bool full,
const char * query_prop_fcc = nullptr )
static

Definition at line 523 of file decklink.cpp.

524{
525 col() << "\nDeckLink options:\n";
526 col() << SBOLD(SRED("\t-t decklink") << ":[full]help") << " | "
527 << SBOLD(SRED("-t decklink") << ":query=<FourCC>") << "\n";
528 col() << SBOLD(SRED("\t-t decklink")
529 << "{:m[ode]=<mode>|:d[evice]=<idx|ID|name>|:c[odec]=<colorspace>...<key>=<"
530 "val>}*")
531 << "\n";
532 col() << SBOLD(SRED("\t-t decklink")
533 << "[:<device_index(indices)>[:<mode>:<colorspace>[:3D]["
534 ":sync_timecode][:connection=<input>][:detect-"
535 "format][:conversion=<conv_mode>]]")
536 << "\n";
537 col() << "\t(mode specification is mandatory if your card does not support format autodetection; syntax on the first line is recommended, the second is obsolescent)\n";
538 col() << "\n";
539
540 col() << SBOLD("3D") << "\n";
541 printf("\tUse this to capture 3D from supported card (eg. DeckLink HD 3D Extreme).\n");
542 printf("\tDo not use it for eg. Quad or Duo. Availability of the mode is indicated\n");
543 printf("\tin video format listing above by flag \"3D\".\n");
544 printf("\n");
545
546 col() << SBOLD("fullhelp") << "\n";
547 col() << "\tPrint description of all available options.\n";
548 col() << "\n";
549
550 col() << SBOLD("half-duplex | full-duplex | simplex") << "\n";
551 col() << "\tSet a profile that allows maximal number of simultaneous "
552 "IOs / set device to better compatibility (3D, dual-link) / "
553 "use all connectors as single input.\n";
554 col() << "\n";
555
556 col() << SBOLD("[no]passthrough[=keep]") << "\n";
557 col() << "\tDisables/enables/keeps capture passthrough (default is "
558 "disable).\n";
559 col() << "\n";
560
561 if (full) {
562 col() << SBOLD("conversion") << "\n";
563 col() << SBOLD("\tnone") << " - No video input conversion\n";
564 col() << SBOLD("\t10lb") << " - HD1080 to SD video input down conversion\n";
565 col() << SBOLD("\t10am") << " - Anamorphic from HD1080 to SD video input down conversion\n";
566 col() << SBOLD("\t72lb") << " - Letter box from HD720 to SD video input down conversion\n";
567 col() << SBOLD("\t72ab") << " - Letterbox video input up conversion\n";
568 col() << SBOLD("\tamup") << " - Anamorphic video input up conversion\n";
569 col() << "\tThen use the set the resulting mode (!) for capture, eg. for 1080p to PAL conversion:\n"
570 "\t\t-t decklink:mode=pal:conversion=10lb\n";
571 col() << "\n";
572
573 col() << SBOLD("query=<FourCC>") << "\n";
574 col() << "\tQueries device attribute, eg. `decklink:q=mach` to "
575 "see max embed. channels).\n";
576 col() << "\n";
577
578 col() << SBOLD("p_not_i") << "\n";
579 col() << "\tIncoming signal should be treated as progressive even if detected as interlaced (PsF).\n";
580 col() << "\n";
581
582 col() << SBOLD("Use1080PsF[=true|false]") << "\n";
583 col() << "\tIncoming signal should be treated as PsF instead of progressive.\n";
584 col() << "\n";
585
586 col() << SBOLD("nosig-send") << "\n";
587 col() << "\tSend video even if no signal was detected (useful when video interrupts\n"
588 "\tbut the video stream needs to be preserved, eg. to keep sync with audio).\n";
589 col() << "\n";
590
591 col() << SBOLD("detect-format") << "\n";
592 col() << "\tTry to detect input video format even if the "
593 "device doesn't support\n"
594 "\tautodetect, eg. \"-t "
595 "decklink:connection=HDMI:detect-format\".\n";
596 col() << "\n";
597
598 col() << SBOLD("profile=<FourCC>") << " - use desired device profile:\n";
600 col() << "\n";
601 col() << SBOLD("sync_timecode") << "\n";
602 col() << "\tTry to synchronize inputs based on timecode (for multiple inputs, eg. tiled 4K)\n";
603 col() << "\n";
604 col() << SBOLD("keep-settings") << "\n\tdo not apply any DeckLink settings by UG than required (keep user-selected defaults)\n";
605 col() << "\n";
606 col() << SBOLD("<option_FourCC>=<value>") << " - arbitrary BMD option (given a FourCC) and corresponding value, i.a.:\n";
607 col() << SBOLD("\taacl[=no]")
608 << "\t\tset analog audio levels to maximum gain "
609 "(consumer audio level)\n";
610 col() << "\n";
611 } else {
612 col() << "(other options available, use \"" << SBOLD("fullhelp") << "\" to see complete list of options)\n\n";
613 }
614
615 col() << "Available color spaces:";
616 for (auto & i : uv_to_bmd_codec_map) {
617 if (i != *uv_to_bmd_codec_map.begin()) {
618 col() << ",";
619 }
620
621 col() << " " << SBOLD(get_codec_name(i.first));
622 }
623 cout << "\n";
624 if (!full) {
625 col() << "Possible connections: " << TBOLD("SDI") << ", " << TBOLD("HDMI") << ", " << TBOLD("OpticalSDI") << ", " << TBOLD("Component") << ", " << TBOLD("Composite") << ", " << TBOLD("SVideo") << "\n";
626 }
627 cout << "\n";
628
629 // Create an IDeckLinkIterator object to enumerate all DeckLink cards in the system
630 bool com_initialized = false;
631
632 cout << "Devices (idx, topological ID, name):\n";
633 // Enumerate all cards in this system
634 int numDevices = 0;
635 const bool natural_sort =
637 for (auto &d :
638 bmd_get_sorted_devices(&com_initialized, true, natural_sort)) {
639 IDeckLink *deckLink = get<0>(d).get();
640 string deviceName = bmd_get_device_name(deckLink);
641 if (deviceName.empty()) {
642 deviceName = "(unable to get name)";
643 }
644
645 char index[STR_LEN] = "";
646 if (!natural_sort) {
647 snprintf(index, sizeof index,
648 TBOLD("%c") ") ", get<char>(d));
649 }
650 if (full || natural_sort) {
651 snprintf(index + strlen(index),
652 sizeof index - strlen(index), TBOLD("%d") ") ",
653 get<int>(d));
654 }
655 // *** Print the model name of the DeckLink card
656 color_printf("\t%s" TBOLD("%6x") ") " TBOLD(
657 TGREEN("%s")) "\n",
658 index, get<unsigned>(d),
659 deviceName.c_str());
660
661 // Increment the total number of DeckLink cards found
662 numDevices++;
663
664 if (full) {
665 vidcap_decklink_print_card_info(deckLink, query_prop_fcc);
666 }
667 }
668 if (!full) {
669 col() << "\n(use \"-t decklink:"
670 << SBOLD(
671 "fullhelp") "\" to see full list of device modes "
672 "and available connections)\n\n";
673 }
674
675 decklink_uninitialize(&com_initialized);
676
677 // If no DeckLink cards were found in the system, inform the user
678 if (numDevices == 0)
679 {
680 log_msg(LOG_LEVEL_ERROR, "No Blackmagic Design devices were found.\n");
681 }
682
683 printf("Examples:\n");
684 col() << "\t" << SBOLD(uv_argv[0] << " -t decklink")
685 << " # captures autodetected video from first DeckLink (index 0) "
686 "in system\n";
687 col() << "\t" << SBOLD(uv_argv[0] << " -t decklink:d=b:m=Hp30:c=v210")
688 << " # specify mode for 2nd device which doesn't have "
689 "autodetection\n";
690 col() << "\t"
691 << SBOLD(uv_argv[0]
692 << " -t decklink:d=\"DeckLink 8K Pro (1)\":profile=1dfd")
693 << " # capture from 8K Pro and set profile to 1-subdevice "
694 "full-duplex (useful for 3D capture)\n";
695
696 printf("\n");
697
699
700 printf("\n");
701
702 return 1;
703}
const char * get_codec_name(codec_t codec)
void print_bmd_device_profiles(const char *line_prefix)
string bmd_get_device_name(IDeckLink *decklink)
void decklink_uninitialize(bool *com_initialized)
std::vector< bmd_dev > bmd_get_sorted_devices(bool *com_initialized, bool verbose, bool natural_sort)
void print_decklink_version()
#define BMD_NAT_SORT
static std::vector< std::pair< codec_t, BMDPixelFormat > > uv_to_bmd_codec_map
int color_printf(const char *format,...)
#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
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
const char * get_commandline_param(const char *key)
Definition host.cpp:894
char ** uv_argv
Definition host.cpp:174
@ STR_LEN
"standard" string length placeholder
Definition macros.h:134

References bmd_get_device_name(), bmd_get_sorted_devices(), BMD_NAT_SORT, color_printf(), device_state::deckLink, decklink_uninitialize(), get_codec_name(), get_commandline_param(), LOG_LEVEL_ERROR, log_msg(), print_bmd_device_profiles(), print_decklink_version(), SBOLD, SRED, STR_LEN, TBOLD, TGREEN, uv_argv, uv_to_bmd_codec_map, and vidcap_decklink_print_card_info().

Referenced by vidcap_decklink_init().

Here is the call graph for this function:

◆ detect_format()

static bool detect_format ( struct vidcap_decklink_state * s,
BMDDisplayMode * outDisplayMode,
struct device_state * device )
static

This function is used when device does not support autodetection and user request explicitly to detect the format (:detect-format)

Definition at line 1039 of file decklink.cpp.

1040{
1041 IDeckLinkDisplayMode *displayMode;
1042 HRESULT result;
1043 IDeckLinkDisplayModeIterator* displayModeIterator = NULL;
1044 result = device->deckLinkInput->GetDisplayModeIterator(&displayModeIterator);
1045 if (result != S_OK) {
1046 return false;
1047 }
1048
1049 vector<BMDPixelFormat> pfs = {bmdFormat8BitYUV, bmdFormat8BitBGRA};
1050
1051 while (displayModeIterator->Next(&displayMode) == S_OK) {
1052 for (BMDPixelFormat pf : pfs) {
1053 uint32_t mode = ntohl(displayMode->GetDisplayMode());
1054 log_msg(LOG_LEVEL_NOTICE, "DeckLink: trying mode %.4s, pixel format %.4s\n", (const char *) &mode, (const char *) &pf);
1055 result = device->deckLinkInput->EnableVideoInput(displayMode->GetDisplayMode(), pf, 0);
1056 if (result == S_OK) {
1057 device->deckLinkInput->StartStreams();
1058 unique_lock<mutex> lk(s->lock);
1059 s->boss_cv.wait_for(
1060 lk, milliseconds(1200), [device] {
1061 return device->delegate
1062 ->newFrameReady == 1;
1063 });
1064 lk.unlock();
1065 device->deckLinkInput->StopStreams();
1066 device->deckLinkInput->DisableVideoInput();
1067
1068 if (device->delegate->newFrameReady == 1) {
1069 *outDisplayMode = displayMode->GetDisplayMode();
1070 // set also detected codec (!)
1071 s->set_codec(pf == bmdFormat8BitYUV ? UYVY : RGBA);
1072 displayMode->Release();
1073 displayModeIterator->Release();
1074 return true;
1075 }
1076 }
1077 }
1078
1079 displayMode->Release();
1080 }
1081
1082 displayModeIterator->Release();
1083 return false;
1084}
#define LOG_LEVEL_NOTICE
information that may be interesting
Definition debug.h:61
enum openssl_mode mode
IDeckLinkInput * deckLinkInput
Definition decklink.cpp:171
unique_ptr< VideoDelegate > delegate
Definition decklink.cpp:172
@ UYVY
YCbCr 422 8-bit - Cb Y0 Cr Y1.
Definition types.h:71
@ RGBA
RGBA 8-bit, big-endian.
Definition types.h:70

References vidcap_decklink_state::boss_cv, device_state::deckLinkInput, device_state::delegate, vidcap_decklink_state::lock, LOG_LEVEL_NOTICE, log_msg(), mode, RGBA, vidcap_decklink_state::set_codec(), and UYVY.

Referenced by device_state::init().

Here is the call graph for this function:

◆ get_input_modes()

static list< tuple< int, string, string, string > > get_input_modes ( IDeckLink * deckLink)
static

Definition at line 1771 of file decklink.cpp.

1772{
1773 list<tuple<int, string, string, string>> ret;
1774 IDeckLinkInput* deckLinkInput = NULL;
1775 IDeckLinkDisplayModeIterator* displayModeIterator = NULL;
1776 IDeckLinkDisplayMode* displayMode = NULL;
1777 HRESULT result;
1778 int displayModeNumber = 0;
1779
1780 // Query the DeckLink for its configuration interface
1781 if ((result = deckLink->QueryInterface(IID_IDeckLinkInput, (void**)&deckLinkInput)) != S_OK) {
1782 LOG(LOG_LEVEL_ERROR) << MOD_NAME "Could not obtain the IDeckLinkInput interface: " << bmd_hresult_to_string(result) << "\n";
1783 if (result == E_NOINTERFACE) {
1784 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Device doesn't support video capture.\n");
1785 }
1786 goto bail;
1787 }
1788
1789 // Obtain an IDeckLinkDisplayModeIterator to enumerate the display modes supported on input
1790 if ((result = deckLinkInput->GetDisplayModeIterator(&displayModeIterator)) != S_OK) {
1791 LOG(LOG_LEVEL_ERROR) << MOD_NAME "Could not obtain the video input display mode iterator: " << bmd_hresult_to_string(result) << "\n";
1792 goto bail;
1793 }
1794
1795 // List all supported output display modes
1796 while (displayModeIterator->Next(&displayMode) == S_OK)
1797 {
1798 BMD_STR displayModeString = NULL;
1799
1800 result = displayMode->GetName((BMD_STR *) &displayModeString);
1801
1802 if (result == S_OK)
1803 {
1804 BMDTimeValue frameRateDuration;
1805 BMDTimeScale frameRateScale;
1806
1807 // Obtain the display mode's properties
1808 string flags_str = bmd_get_flags_str(displayMode->GetFlags());
1809 int modeWidth = displayMode->GetWidth();
1810 int modeHeight = displayMode->GetHeight();
1811 displayMode->GetFrameRate(&frameRateDuration, &frameRateScale);
1812 uint32_t mode = ntohl(displayMode->GetDisplayMode());
1813 uint32_t field_dominance_n = ntohl(displayMode->GetFieldDominance());
1814 string fcc{(char *) &mode, 4};
1815 string name{get_str_from_bmd_api_str(displayModeString)};
1816 char buf[1024];
1817 snprintf(buf, sizeof buf, "%d x %d \t %6.2f FPS \t flags: %.4s, %s", modeWidth, modeHeight,
1818 (float) ((double)frameRateScale / (double)frameRateDuration),
1819 (char *) &field_dominance_n, flags_str.c_str());
1820 string details{buf};
1821 ret.push_back(tuple<int, string, string, string> {displayModeNumber, fcc, name, details});
1822
1823 release_bmd_api_str(displayModeString);
1824 }
1825
1826 // Release the IDeckLinkDisplayMode object to prevent a leak
1827 displayMode->Release();
1828
1829 displayModeNumber++;
1830 }
1831
1832bail:
1833 // Ensure that the interfaces we obtained are released to prevent a memory leak
1834 RELEASE_IF_NOT_NULL(displayModeIterator);
1835 RELEASE_IF_NOT_NULL(deckLinkInput);
1836
1837 return ret;
1838}
string bmd_get_flags_str(BMDDisplayModeFlags flags)
void release_bmd_api_str(BMD_STR string)
std::string get_str_from_bmd_api_str(BMD_STR string)
#define BMD_STR

References bmd_get_flags_str(), bmd_hresult_to_string(), BMD_STR, vidcap_decklink_state::frameRateScale, get_str_from_bmd_api_str(), LOG, LOG_LEVEL_ERROR, log_msg(), MOD_NAME, mode, name, release_bmd_api_str(), and RELEASE_IF_NOT_NULL.

Referenced by print_input_modes(), and vidcap_decklink_probe().

Here is the call graph for this function:

◆ nr_frames()

static int nr_frames ( struct vidcap_decklink_state * s)
static

This function basically counts frames from all devices, optionally with respect to timecode (if synchronized).

Lock needs to be hold during the whole function call.

Parameters
sBlackmagic state
Returns
number of captured tiles

Definition at line 1566 of file decklink.cpp.

1566 {
1567 BMDTimecodeBCD max_timecode = 0u;
1568 int tiles_total = 0;
1569 int i;
1570
1571 /* If we use timecode, take maximal timecode value... */
1572 if (s->sync_timecode) {
1573 for (i = 0; i < s->devices_cnt; ++i) {
1574 if(s->state[i].delegate->newFrameReady == 1) {
1575 if (s->state[i].delegate->timecode > max_timecode) {
1576 max_timecode = s->state[i].delegate->timecode;
1577 }
1578 }
1579 }
1580 }
1581
1582 /* count all tiles */
1583 for (i = 0; i < s->devices_cnt; ++i) {
1584 if(s->state[i].delegate->newFrameReady == 1) {
1585 /* if inputs are synchronized, use only up-to-date frames (with same TC)
1586 * as the most recent */
1587 if(s->sync_timecode) {
1588 if(s->state[i].delegate->timecode && s->state[i].delegate->timecode != max_timecode) {
1589 s->state[i].delegate->newFrameReady = 0;
1590 } else {
1591 tiles_total++;
1592 }
1593 }
1594 /* otherwise, simply add up the count */
1595 else {
1596 tiles_total++;
1597 }
1598 }
1599 if (s->state[i].delegate->newFrameReady == -1) {
1600 return -1;
1601 }
1602 }
1603 return tiles_total;
1604}

References vidcap_decklink_state::devices_cnt, vidcap_decklink_state::state, and vidcap_decklink_state::sync_timecode.

Referenced by vidcap_decklink_grab().

◆ parse_devices()

static void parse_devices ( struct vidcap_decklink_state * s,
const char * devs )
static

Definition at line 706 of file decklink.cpp.

707{
708 assert(devs != NULL && strlen(devs) > 0);
709 char *devices = strdup(devs);
710 char *ptr;
711 char *save_ptr_dev;
712 char *tmp = devices;
713
714 s->devices_cnt = 0;
715 while ((ptr = strtok_r(tmp, ",", &save_ptr_dev))) {
716 s->devices_cnt += 1;
717 s->state.resize(s->devices_cnt);
718 s->state[s->devices_cnt - 1].device_id = ptr;
719 tmp = NULL;
720 }
721 free (devices);
722}

References vidcap_decklink_state::devices_cnt, and vidcap_decklink_state::state.

Referenced by parse_option(), and settings_init().

◆ parse_option()

static bool parse_option ( struct vidcap_decklink_state * s,
const char * opt )
static

Definition at line 725 of file decklink.cpp.

726{
727 const char *val = strchr(opt, '=') + 1;
728 if(strcasecmp(opt, "3D") == 0) {
729 s->stereo = true;
730 } else if(strcasecmp(opt, "timecode") == 0) {
731 s->sync_timecode = true;
732 } else if (IS_KEY_PREFIX(opt, "codec")) {
733 const char *codec = strchr(opt, '=') + 1;
735 if(s->codec == VIDEO_CODEC_NONE) {
736 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Wrong config. Unknown color space %s\n", codec);
737 return false;
738 }
739 } else if (IS_KEY_PREFIX(opt, "connection")) {
740 const char *connection = strchr(opt, '=') + 1;
741 for (auto const & it : get_connection_string_map()) {
742 if (strcasecmp(connection, it.second.c_str()) == 0) {
743 s->device_options[bmdDeckLinkConfigVideoInputConnection] = bmd_option((int64_t) it.first);
744 }
745 }
746 if (s->device_options.find(bmdDeckLinkConfigVideoInputConnection) == s->device_options.end()) {
747 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unrecognized connection %s.\n", connection);
748 return false;
749 }
750 } else if(strncasecmp(opt, "audio_level=",
751 strlen("audio_level=")) == 0) {
752 s->device_options[bmdDeckLinkConfigAnalogAudioConsumerLevels] =
754 } else if (IS_KEY_PREFIX(opt, "conversion")) {
755 s->device_options[bmdDeckLinkConfigVideoInputConversionMode].parse(strchr(opt, '='));
756 } else if (IS_KEY_PREFIX(opt, "device")) {
757 parse_devices(s, strchr(opt, '=') + 1);
758 } else if (IS_KEY_PREFIX(opt, "mode")) {
759 s->mode = strchr(opt, '=') + 1;
760 } else if (IS_KEY_PREFIX(opt, "profile")) {
761 s->profile.parse(strchr(opt, '=') + 1);
762 } else if (strcasecmp(opt, "detect-format") == 0) {
763 s->detect_format = true;
764 } else if (strcasecmp(opt, "p_not_i") == 0) {
765 s->p_not_i = true;
766 } else if (strstr(opt, "Use1080PsF") != nullptr) {
767 s->device_options[bmdDeckLinkConfigCapture1080pAsPsF].set_flag(strchr(opt, '=') == nullptr || strcasecmp(strchr(opt, '='), "false") != 0);
768 } else if (strncasecmp(opt, "passthrough", 4) == 0 ||
769 strncasecmp(opt, "nopassthrough", 6) == 0) {
770 if (strstr(opt, "keep")) {
771 s->device_options.erase(bmdDeckLinkConfigCapturePassThroughMode);
772 } else {
773 s->device_options[bmdDeckLinkConfigCapturePassThroughMode] = bmd_option((int64_t) (opt[0] == 'n' ? bmdDeckLinkCapturePassthroughModeDisabled
774 : bmdDeckLinkCapturePassthroughModeCleanSwitch));
775 }
776 } else if (strstr(opt, "full-duplex") == opt) {
777 s->profile.set_int(bmdProfileOneSubDeviceFullDuplex);
778 } else if (strstr(opt, "half-duplex") == opt) {
779 s->profile.set_int(bmdDuplexHalf);
780 } else if (strstr(opt, "simplex") == opt) {
781 s->profile.set_int(bmdProfileOneSubDeviceHalfDuplex);
782 } else if (strcasecmp(opt, "nosig-send") == 0) {
783 s->nosig_send = true;
784 } else if (strstr(opt, "keep-settings") == opt) {
785 s->keep_device_defaults = true;
786 } else if ((strchr(opt, '=') != nullptr && strchr(opt, '=') - opt == 4) || strlen(opt) == 4) {
787 s->device_options[(BMDDeckLinkConfigurationID) bmd_read_fourcc(opt)].parse(strchr(opt, '=') + 1);
788 } else {
789 log_msg(LOG_LEVEL_ERROR, MOD_NAME "unknown option in init string: %s\n", opt);
790 return false;
791 }
792
793 return true;
794}
int void * val
codec_t get_codec_from_name(const char *name)
bool bmd_parse_audio_levels(const char *opt) noexcept(false)
TOREMOVE (implicit "aacl" option is preferred)
const map< BMDVideoConnection, string > & get_connection_string_map()
uint32_t bmd_read_fourcc(const char *str)
#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
void set_int(int64_t val_)
void parse(const char *)
@ VIDEO_CODEC_NONE
dummy color spec
Definition types.h:66

References bmd_parse_audio_levels(), bmd_read_fourcc(), vidcap_decklink_state::codec, vidcap_decklink_state::detect_format, vidcap_decklink_state::device_options, get_codec_from_name(), get_connection_string_map(), IS_KEY_PREFIX, vidcap_decklink_state::keep_device_defaults, LOG_LEVEL_ERROR, log_msg(), MOD_NAME, vidcap_decklink_state::mode, vidcap_decklink_state::nosig_send, vidcap_decklink_state::p_not_i, bmd_option::parse(), parse_devices(), vidcap_decklink_state::profile, vidcap_decklink_state::set_codec(), bmd_option::set_int(), vidcap_decklink_state::stereo, vidcap_decklink_state::sync_timecode, val, and VIDEO_CODEC_NONE.

Referenced by settings_init(), and settings_init_key_val().

Here is the call graph for this function:

◆ postprocess_frame()

static void postprocess_frame ( struct vidcap_decklink_state * s)
static

Definition at line 1644 of file decklink.cpp.

1644 {
1645 if (s->codec == RGBA) {
1646 for (unsigned i = 0; i < s->frame->tile_count; ++i) {
1647 vc_copylineToRGBA_inplace((unsigned char*) s->frame->tiles[i].data,
1648 (unsigned char*)s->frame->tiles[i].data,
1649 s->frame->tiles[i].data_len, 16, 8, 0);
1650 }
1651 }
1652 if (s->codec == R10k && get_commandline_param(R10K_FULL_OPT) == nullptr) {
1653 for (unsigned i = 0; i < s->frame->tile_count; ++i) {
1655 s->frame->tiles[i].data_len);
1656 }
1657 }
1658}
void r10k_limited_to_full(const char *in, char *out, size_t len)
#define R10K_FULL_OPT
decoder_func_t vc_copylineToRGBA_inplace
char * data
Raw tile data. Pointer must be at least 4B aligned.
Definition types.h:287
unsigned int data_len
length of the data
Definition types.h:288
struct tile tiles[FLEXIBLE_ARRAY_MEMBER]
Definition types.h:345
unsigned int tile_count
Definition types.h:344
@ R10k
RGB 10-bit packed - RGBX, big-endian (2 bit padding)
Definition types.h:73

References vidcap_decklink_state::codec, tile::data, tile::data_len, vidcap_decklink_state::frame, get_commandline_param(), R10k, R10K_FULL_OPT, r10k_limited_to_full(), RGBA, video_frame::tile_count, video_frame::tiles, and vc_copylineToRGBA_inplace.

Referenced by vidcap_decklink_grab().

Here is the call graph for this function:

◆ print_input_modes()

static void print_input_modes ( IDeckLink * deckLink)
static

Definition at line 1840 of file decklink.cpp.

1841{
1842 list<tuple<int, string, string, string>> ret = get_input_modes (deckLink);
1843 printf("\tcapture modes:\n");
1844 for (auto &i : ret) {
1845 col() << "\t\t" << right << SBOLD(setw(2) << get<0>(i) << " (" << get<1>(i) << ")") << ") " <<
1846 left << setw(20) << get<2>(i) << internal << " " <<
1847 get<3>(i) << "\n";
1848 }
1849}

References get_input_modes().

Referenced by vidcap_decklink_print_card_info().

Here is the call graph for this function:

◆ process_new_audio_packets()

static audio_frame * process_new_audio_packets ( struct vidcap_decklink_state * s)
static

Definition at line 1606 of file decklink.cpp.

1606 {
1607 if (s->audioPackets.empty()) {
1608 return nullptr;
1609 }
1610 s->audio.data_len = 0;
1611
1612 BMDTimeValue audio_time = 0;
1613 s->audioPackets.front()->GetPacketTime(&audio_time, bmdAudioSampleRate48kHz);
1614 s->audio.timestamp =
1615 ((int64_t)audio_time * 90000 + bmdAudioSampleRate48kHz - 1) / bmdAudioSampleRate48kHz;
1616
1617 while (!s->audioPackets.empty()) {
1618 auto *audioPacket = s->audioPackets.front();
1619 s->audioPackets.pop();
1620
1621 void *audioFrame = nullptr;
1622 audioPacket->GetBytes(&audioFrame);
1623
1624 if (s->audio.ch_count == 1) { // there are actually 2 channels grabbed
1625 if (s->audio.data_len + audioPacket->GetSampleFrameCount() * 1U * s->audio.bps <= static_cast<unsigned>(s->audio.max_size)) {
1626 demux_channel(s->audio.data + s->audio.data_len, static_cast<char *>(audioFrame), s->audio.bps, min<int64_t>(audioPacket->GetSampleFrameCount() * 2 /* channels */ * s->audio.bps, INT_MAX), 2 /* channels (originally) */, 0 /* we want first channel */);
1627 s->audio.data_len = min<int64_t>(s->audio.data_len + audioPacket->GetSampleFrameCount() * 1 * s->audio.bps, INT_MAX);
1628 } else {
1629 MSG(WARNING, "Audio frame too small!\n");
1630 }
1631 } else {
1632 if (s->audio.data_len + audioPacket->GetSampleFrameCount() * s->audio.ch_count * s->audio.bps <= s->audio.max_size) {
1633 memcpy(s->audio.data + s->audio.data_len, audioFrame, audioPacket->GetSampleFrameCount() * s->audio.ch_count * s->audio.bps);
1634 s->audio.data_len = min<int64_t>(s->audio.data_len + audioPacket->GetSampleFrameCount() * s->audio.ch_count * s->audio.bps, INT_MAX);
1635 } else {
1636 MSG(WARNING, "Audio frame too small!\n");
1637 }
1638 }
1639 audioPacket->Release();
1640 }
1641 return &s->audio;
1642}
#define MSG(l, fmt,...)
Definition debug.h:96
#define min(a, b)
Definition rtp.c:99
void demux_channel(char *out, char *in, int bps, int in_len, int in_stream_channels, int pos_in_stream)
Definition utils.cpp:334

References vidcap_decklink_state::audioPackets, demux_channel(), min, and MSG.

Referenced by vidcap_decklink_grab().

Here is the call graph for this function:

◆ REGISTER_MODULE()

REGISTER_MODULE ( decklink ,
& vidcap_decklink_info,
LIBRARY_CLASS_VIDEO_CAPTURE ,
VIDEO_CAPTURE_ABI_VERSION  )

◆ set_display_mode_properties()

static HRESULT set_display_mode_properties ( struct vidcap_decklink_state * s,
struct tile * tile,
IDeckLinkDisplayMode * displayMode,
BMDPixelFormat * pf )
static

Definition at line 964 of file decklink.cpp.

965{
966 BMD_STR displayModeBMDString = nullptr;
967
968 if (HRESULT result = displayMode->GetName(&displayModeBMDString); FAILED(result)) {
969 LOG(LOG_LEVEL_ERROR) << MOD_NAME << "IDeckLinkDisplayMode::GetName failed: " << bmd_hresult_to_string(result) << "\n";
970 }
971 string displayModeString = get_str_from_bmd_api_str(displayModeBMDString);
972 release_bmd_api_str(displayModeBMDString);
973
974 auto it = std::find_if(uv_to_bmd_codec_map.begin(),
976 [&s](const std::pair<codec_t, BMDPixelFormat>& el){ return el.first == s->codec; });
977 if (it == uv_to_bmd_codec_map.end()) {
978 LOG(LOG_LEVEL_ERROR) << "Unsupported codec: " << get_codec_name(s->codec) << "!\n";
979 return E_FAIL;
980 }
981 *pf = it->second;
982
983 // get avarage time between frames
984 BMDTimeValue frameRateDuration = 0;
985
986 tile->width = displayMode->GetWidth();
987 tile->height = displayMode->GetHeight();
988 s->frame->color_spec = s->codec;
989
990 displayMode->GetFrameRate(&frameRateDuration, &s->frameRateScale);
991 s->frame->fps = static_cast<double>(s->frameRateScale) / frameRateDuration;
992 s->next_frame_time = static_cast<int>(std::chrono::microseconds::period::den / s->frame->fps); // in microseconds
993 switch(displayMode->GetFieldDominance()) {
994 case bmdLowerFieldFirst:
996 MOD_NAME "Lower field first format detected, "
997 "fields can be switched! ");
998 // fall through
999 case bmdUpperFieldFirst:
1001 break;
1002 case bmdProgressiveFrame:
1003 case bmdProgressiveSegmentedFrame:
1005 break;
1006 case bmdUnknownFieldDominance:
1007 LOG(LOG_LEVEL_WARNING) << MOD_NAME "Unknown field dominance!\n";
1009 break;
1010 }
1011
1012 if (s->p_not_i) {
1014 }
1015
1016 LOG(LOG_LEVEL_DEBUG) << MOD_NAME << displayModeString << " \t " << tile->width << " x " << tile->height << " \t " <<
1017 s->frame->fps << " FPS \t " << s->next_frame_time << " AVAREGE TIME BETWEEN FRAMES\n";
1018 LOG(LOG_LEVEL_NOTICE) << MOD_NAME "Enable video input: " << displayModeString << ((s->enable_flags & bmdVideoInputDualStream3D) != 0U ? " (stereoscopic 3D)" : "") << "\n";
1019
1020 tile->data_len =
1022
1023 if(s->stereo) {
1024 s->frame->tile_count = 2;
1025 s->frame->tiles[1].width = s->frame->tiles[0].width;
1026 s->frame->tiles[1].height = s->frame->tiles[0].height;
1027 s->frame->tiles[1].data_len = s->frame->tiles[0].data_len;
1028 } else {
1029 s->frame->tile_count = s->devices_cnt;
1030 }
1031
1032 return S_OK;
1033}
int vc_get_linesize(unsigned int width, codec_t codec)
void bug_msg(int level, const char *format,...)
prints the error with the advice to report the bug
Definition debug.cpp:379
#define LOG_LEVEL_DEBUG
Definition kernels.cu:48
Struct tile is an area of video_frame.
Definition types.h:279
unsigned int width
Definition types.h:280
unsigned int height
Definition types.h:281
enum interlacing_t interlacing
Definition types.h:307
double fps
Definition types.h:308
codec_t color_spec
Definition types.h:306
@ PROGRESSIVE
progressive frame
Definition types.h:164
@ INTERLACED_MERGED
Columngs of both fields are interlaced together.
Definition types.h:167

References bmd_hresult_to_string(), BMD_STR, bug_msg(), vidcap_decklink_state::codec, video_frame::color_spec, tile::data_len, vidcap_decklink_state::devices_cnt, vidcap_decklink_state::enable_flags, FAILED, video_frame::fps, vidcap_decklink_state::frame, vidcap_decklink_state::frameRateScale, get_codec_name(), get_str_from_bmd_api_str(), tile::height, INTERLACED_MERGED, video_frame::interlacing, LOG, LOG_LEVEL_DEBUG, LOG_LEVEL_ERROR, LOG_LEVEL_NOTICE, LOG_LEVEL_WARNING, MOD_NAME, vidcap_decklink_state::next_frame_time, vidcap_decklink_state::p_not_i, PROGRESSIVE, release_bmd_api_str(), vidcap_decklink_state::stereo, video_frame::tile_count, video_frame::tiles, uv_to_bmd_codec_map, vc_get_linesize(), and tile::width.

Referenced by device_state::init(), and VideoDelegate::VideoInputFormatChanged().

Here is the call graph for this function:

◆ settings_init()

static bool settings_init ( struct vidcap_decklink_state * s,
char * fmt )
static

Definition at line 810 of file decklink.cpp.

811{
812 char *tmp;
813 char *save_ptr = NULL;
814
815 if (!fmt || (tmp = strtok_r(fmt, ":", &save_ptr)) == NULL) {
816 MSG(INFO, "Auto-choosen device 0.\n");
817 return true;
818 }
819
820 // options are in format <device>:<mode>:<codec>[:other_opts]
821 if (isdigit(tmp[0]) && strcasecmp(tmp, "3D") != 0) {
823 << MOD_NAME "Deprecated syntax used, please use options in "
824 "format \"key=value\"\n";
825 // choose device
826 parse_devices(s, tmp);
827
828 // choose mode
829 tmp = strtok_r(NULL, ":", &save_ptr);
830 if(tmp) {
831 s->mode = tmp;
832
833 tmp = strtok_r(NULL, ":", &save_ptr);
834 if (tmp) {
836 if(s->codec == VIDEO_CODEC_NONE) {
837 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Wrong config. Unknown color space %s\n", tmp);
838 return false;
839 }
840 }
841 if (!settings_init_key_val(s, &save_ptr)) {
842 return false;
843 }
844 }
845 } else { // options are in format key=val
846 if (!parse_option(s, tmp)) {
847 return false;
848 }
849 if (!settings_init_key_val(s, &save_ptr)) {
850 return false;
851 }
852 }
853
854 return true;
855}
const char * fmt

References vidcap_decklink_state::codec, fmt, get_codec_from_name(), LOG, LOG_LEVEL_ERROR, LOG_LEVEL_WARNING, log_msg(), MOD_NAME, vidcap_decklink_state::mode, MSG, parse_devices(), parse_option(), vidcap_decklink_state::set_codec(), settings_init_key_val(), and VIDEO_CODEC_NONE.

Referenced by vidcap_decklink_init().

Here is the call graph for this function:

◆ settings_init_key_val()

static bool settings_init_key_val ( struct vidcap_decklink_state * s,
char ** save_ptr )
static

Definition at line 796 of file decklink.cpp.

797{
798 char *tmp;
799
800 while((tmp = strtok_r(NULL, ":", save_ptr))) {
801 if (!parse_option(s, tmp)) {
802 return false;
803 }
804 }
805
806 return true;
807}

References parse_option().

Referenced by settings_init().

Here is the call graph for this function:

◆ vidcap_decklink_done()

static void vidcap_decklink_done ( void * state)
static

Definition at line 1519 of file decklink.cpp.

1520{
1521 debug_msg("vidcap_decklink_done\n"); /* TOREMOVE */
1522
1523 HRESULT result;
1524
1525 struct vidcap_decklink_state *s = (struct vidcap_decklink_state *) state;
1526
1527 assert (s != NULL);
1528
1529 for (int i = 0; i < s->devices_cnt; ++i)
1530 {
1531 result = s->state[i].deckLinkInput->StopStreams();
1532 if (result != S_OK) {
1534 << MOD_NAME "Could not stop stream: "
1535 << bmd_hresult_to_string(result) << "\n";
1536 }
1537
1538 if (s->state[i].audio) {
1539 result = s->state[i].deckLinkInput->DisableAudioInput();
1540 if (result != S_OK) {
1542 << MOD_NAME "Could disable audio input: "
1543 << bmd_hresult_to_string(result) << "\n";
1544 }
1545 }
1546 result = s->state[i].deckLinkInput->DisableVideoInput();
1547 if (result != S_OK) {
1549 << MOD_NAME "Could disable video input: "
1550 << bmd_hresult_to_string(result) << "\n";
1551 }
1552 }
1553
1554 cleanup_common(s);
1555}
void ** state
#define debug_msg(...)
#define debug_msg(...) log_msg(LOG_LEVEL_DEBUG, "[pid/%d +%d %s] ", getpid(), LINE,...
Definition debug.h:92

References bmd_hresult_to_string(), cleanup_common(), debug_msg, vidcap_decklink_state::devices_cnt, LOG, LOG_LEVEL_ERROR, MOD_NAME, state, and vidcap_decklink_state::state.

Here is the call graph for this function:

◆ vidcap_decklink_grab()

static struct video_frame * vidcap_decklink_grab ( void * state,
struct audio_frame ** audio )
static

Definition at line 1661 of file decklink.cpp.

1662{
1663 struct vidcap_decklink_state *s = (struct vidcap_decklink_state *) state;
1664 int tiles_total = 0;
1665 int i;
1666 bool frame_ready = true;
1667
1668 int timeout = 0;
1669
1670 unique_lock<mutex> lk(s->lock);
1671// LOCK - LOCK - LOCK - LOCK - LOCK - LOCK - LOCK - LOCK - LOCK - LOCK - LOCK //
1672
1673 tiles_total = nr_frames(s);
1674
1675 while(tiles_total != s->devices_cnt) {
1676 //while (!s->state[0].delegate->newFrameReady) {
1677 cv_status rc = cv_status::no_timeout;
1678 steady_clock::time_point t0(steady_clock::now());
1679
1680 while(rc == cv_status::no_timeout
1681 && tiles_total != s->devices_cnt /* not all tiles */
1682 && tiles_total != -1
1683 && !timeout) {
1684 rc = s->boss_cv.wait_for(lk, microseconds(2 * s->next_frame_time));
1685 // recompute tiles count
1686 tiles_total = nr_frames(s);
1687
1688 // this is for the case of multiple tiles (eg. when one tile is persistently
1689 // missing, eg. 01301301. Therefore, pthread_cond_timewait doesn't timeout but
1690 // actual timeout time has reached.
1691 steady_clock::time_point t(steady_clock::now());
1692 if (duration_cast<microseconds>(t - t0).count() > 2 * s->next_frame_time)
1693 timeout = 1;
1694
1695 }
1696
1697 if (rc != cv_status::no_timeout || timeout || tiles_total == -1) { //(rc == ETIMEDOUT) {
1698 log_msg(LOG_LEVEL_VERBOSE, "Waiting for new frame timed out!\n");
1699
1700 // try to restart stream
1701 /*
1702 HRESULT result;
1703 debug_msg("Try to restart DeckLink stream!\n");
1704 result = s->deckLinkInput->StopStreams();
1705 if (result != S_OK)
1706 {
1707 debug_msg("Could not stop stream: %08x\n", result);
1708 }
1709 result = s->deckLinkInput->StartStreams();
1710 if (result != S_OK)
1711 {
1712 debug_msg("Could not start stream: %08x\n", result);
1713 return NULL; // really end ???
1714 }
1715 */
1716
1717 frame_ready = false;
1718 break;
1719 }
1720 }
1721
1722 /* cleanup newframe flag */
1723 for (i = 0; i < s->devices_cnt; ++i) {
1724 if(s->state[i].delegate->newFrameReady == 0) {
1725 frame_ready = false;
1726 }
1727 s->state[i].delegate->newFrameReady = 0;
1728 }
1729
1730 *audio = process_new_audio_packets(s); // return audio even if there is no video to avoid
1731 // hoarding and then dropping of audio packets
1732// UNLOCK - UNLOCK - UNLOCK - UNLOCK - UNLOCK - UNLOCK - UNLOCK - UNLOCK - UN //
1733 lk.unlock();
1734
1735 if(!frame_ready)
1736 return NULL;
1737
1738 /* count returned tiles */
1739 int count = 0;
1740 if(s->stereo) {
1741 if (s->state[0].delegate->pixelFrame != NULL &&
1742 s->state[0].delegate->pixelFrameRight != NULL) {
1743 s->frame->tiles[0].data = (char*)s->state[0].delegate->pixelFrame;
1744 s->frame->tiles[1].data = (char*)s->state[0].delegate->pixelFrameRight;
1745 ++count;
1746 } // else count == 0 -> return NULL
1747 } else {
1748 for (i = 0; i < s->devices_cnt; ++i) {
1749 if (s->state[i].delegate->pixelFrame == NULL) {
1750 break;
1751 }
1752 s->frame->tiles[i].data = (char*)s->state[i].delegate->pixelFrame;
1753 ++count;
1754 }
1755 }
1757 return NULL;
1758 }
1760
1761 s->frames++;
1762 s->frame->timecode = s->state[0].delegate->timecode;
1763 s->frame->timestamp =
1764 ((int64_t)s->state[0].delegate->frameTime * 90000 +
1765 s->frameRateScale - 1) /
1766 s->frameRateScale;
1767 return s->frame;
1768}
struct audio_frame ** audio
#define LOG_LEVEL_VERBOSE
Definition debug.h:63
int count
Definition hd-rum.c:44
int64_t timestamp
Definition types.h:331
uint32_t timecode
BCD timecode (hrs, min, sec, frm num)
Definition types.h:335

References audio, vidcap_decklink_state::boss_cv, count, tile::data, vidcap_decklink_state::devices_cnt, vidcap_decklink_state::frame, vidcap_decklink_state::frameRateScale, vidcap_decklink_state::frames, vidcap_decklink_state::lock, LOG_LEVEL_VERBOSE, log_msg(), vidcap_decklink_state::next_frame_time, nr_frames(), postprocess_frame(), process_new_audio_packets(), state, vidcap_decklink_state::state, vidcap_decklink_state::stereo, video_frame::tiles, video_frame::timecode, and video_frame::timestamp.

Here is the call graph for this function:

◆ vidcap_decklink_init()

static int vidcap_decklink_init ( struct vidcap_params * params,
void ** state )
static

Definition at line 1414 of file decklink.cpp.

1415{
1416 const char *fmt = vidcap_params_get_fmt(params);
1417
1418 if (strcmp(fmt, "help") == 0 || strcmp(fmt, "fullhelp") == 0) {
1419 decklink_help(strcmp(fmt, "fullhelp") == 0);
1420 return VIDCAP_INIT_NOERR;
1421 }
1422 if (IS_KEY_PREFIX(fmt, "query")) {
1423 decklink_help(true, strchr(fmt, '=') + 1);
1424 return VIDCAP_INIT_NOERR;
1425 }
1426
1428 return VIDCAP_INIT_FAIL;
1429 }
1430
1431 struct vidcap_decklink_state *s = nullptr;
1432 try {
1433 if ((s = new vidcap_decklink_state()) == nullptr) {
1434 LOG(LOG_LEVEL_ERROR) << "Unable to allocate DeckLink state\n";
1435 return VIDCAP_INIT_FAIL;
1436 }
1437 } catch(...) {
1438 return VIDCAP_INIT_FAIL;
1439 }
1440
1441 // SET UP device and mode
1442 char *tmp_fmt = strdup(fmt);
1443 bool ret = false;
1444 try {
1445 ret = settings_init(s, tmp_fmt);
1446 } catch (exception &e) {
1447 MSG(ERROR, "%s\n", e.what());
1448 }
1449 free(tmp_fmt);
1450 if (!ret) {
1451 delete s;
1452 return VIDCAP_INIT_FAIL;
1453 }
1454
1455 switch (get_bits_per_component(s->codec)) {
1456 case 0: s->requested_bit_depth = 0; break;
1457 case 8: s->requested_bit_depth = bmdDetectedVideoInput8BitDepth; break;
1458 case 10: s->requested_bit_depth = bmdDetectedVideoInput10BitDepth; break;
1459 case 12: s->requested_bit_depth = bmdDetectedVideoInput12BitDepth; break;
1460 default: abort();
1461 }
1462 if (s->codec == VIDEO_CODEC_NONE) {
1463 s->set_codec(UYVY); // default one
1464 }
1465
1466 BMDAudioConnection audioConnection = bmdAudioConnectionEmbedded;
1468 delete s;
1469 return VIDCAP_INIT_FAIL;
1470 }
1471
1472 if(s->stereo) {
1473 s->enable_flags |= bmdVideoInputDualStream3D;
1474 s->supported_flags = (BMDSupportedVideoModeFlags) (s->supported_flags | bmdSupportedVideoModeDualStream3D);
1475 if (s->devices_cnt > 1) {
1476 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Passed more than one device while setting 3D mode. "
1477 "In this mode, only one device needs to be passed.");
1478 delete s;
1479 return VIDCAP_INIT_FAIL;
1480 }
1481 }
1482 s->frame = vf_alloc(MAX(s->devices_cnt, 2));
1483 s->frame->tile_count = s->stereo ? 2 : s->devices_cnt;
1485
1486 /* TODO: make sure that all devices are have compatible properties */
1487 for (int i = 0; i < s->devices_cnt; ++i) {
1488 if (!s->state[i].init(s, vf_get_tile(s->frame, i), audioConnection)) {
1489 cleanup_common(s);
1490 return VIDCAP_INIT_FAIL;
1491 }
1492 }
1493
1494 *state = s;
1495 return VIDCAP_INIT_OK;
1496}
struct video_frame * vf_alloc(int count)
Allocates blank video frame.
bool blackmagic_api_version_check()
#define VIDCAP_INIT_NOERR
state not initialized, other action performed (typically help)
#define VIDCAP_INIT_OK
initialization successful
#define VIDCAP_INIT_FAIL
error ocured
#define MAX(a, b)
Definition macros.h:65
int flags
Definition types.h:329
const char * vidcap_params_get_fmt(const struct vidcap_params *params)
unsigned int vidcap_params_get_flags(const struct vidcap_params *params)
#define VIDCAP_FLAG_AUDIO_ANY
int get_bits_per_component(codec_t codec)
struct tile * vf_get_tile(struct video_frame *buf, int pos)
Returns pointer to n-th tile from video frame Equivalent to &video_frame::tiles[pos].

References vidcap_decklink_state::vidcap_decklink_state(), blackmagic_api_version_check(), cleanup_common(), vidcap_decklink_state::codec, decklink_cap_configure_audio(), decklink_help(), vidcap_decklink_state::devices_cnt, vidcap_decklink_state::enable_flags, video_frame::flags, fmt, vidcap_decklink_state::frame, get_bits_per_component(), IS_KEY_PREFIX, LOG, LOG_LEVEL_ERROR, log_msg(), MAX, MOD_NAME, MSG, vidcap_decklink_state::requested_bit_depth, vidcap_decklink_state::set_codec(), settings_init(), state, vidcap_decklink_state::state, vidcap_decklink_state::stereo, vidcap_decklink_state::supported_flags, video_frame::tile_count, TIMESTAMP_VALID, UYVY, vf_alloc(), vf_get_tile(), VIDCAP_FLAG_AUDIO_ANY, VIDCAP_INIT_FAIL, VIDCAP_INIT_NOERR, VIDCAP_INIT_OK, vidcap_params_get_flags(), vidcap_params_get_fmt(), and VIDEO_CODEC_NONE.

Here is the call graph for this function:

◆ vidcap_decklink_print_card_info()

static void vidcap_decklink_print_card_info ( IDeckLink * deckLink,
const char * query_prop_fcc )
static
Parameters
query_prop_fccif not NULL, print corresponding BMDDeckLinkAttribute

Definition at line 470 of file decklink.cpp.

471{
472
473 // ** List the video input display modes supported by the card
474 print_input_modes(deckLink);
475
476 IDeckLinkProfileAttributes *deckLinkAttributes = nullptr;
477
478 HRESULT result = deckLink->QueryInterface(IID_IDeckLinkProfileAttributes, (void**)&deckLinkAttributes);
479 if (result != S_OK) {
480 cout << "Could not query device attributes.\n\n";
481 return;
482 }
483
484 IDeckLinkInput *deckLinkInput = nullptr;
485 color_printf("\n\tsupported pixel formats:" TERM_BOLD);
486 if ((deckLink->QueryInterface(IID_IDeckLinkInput,
487 (void **) &deckLinkInput)) == S_OK) {
488 for (auto &c : uv_to_bmd_codec_map) {
489 if (decklink_supports_codec(deckLinkInput, c.second)) {
490 printf(" %s", get_codec_name(c.first));
491 }
492 }
493 RELEASE_IF_NOT_NULL(deckLinkInput);
494 } else {
495 color_printf(TRED("(error)"));
496 }
498
499 int64_t connections = 0;
500 if (deckLinkAttributes->GetInt(BMDDeckLinkVideoInputConnections, &connections) != S_OK) {
501 LOG(LOG_LEVEL_ERROR) << MOD_NAME "Could not get connections.\n";
502 } else {
503 cout << "\n\tConnection can be one of following:\n";
504 for (auto const &it : get_connection_string_map()) {
505 if (connections & it.first) {
506 col() << "\t\t" << SBOLD(it.second) << "\n";
507 }
508 }
509 }
510 cout << "\n";
511
512 if (query_prop_fcc != nullptr) {
513 print_bmd_attribute(deckLinkAttributes, query_prop_fcc);
514 cout << "\n";
515 }
516
517 // Release the IDeckLink instance when we've finished with it to prevent leaks
518 RELEASE_IF_NOT_NULL(deckLinkAttributes);
519}
void print_bmd_attribute(IDeckLinkProfileAttributes *deckLinkAttributes, const char *query_prop_fcc)
bool decklink_supports_codec(T *deckLink, BMDPixelFormat pf)
#define TERM_BOLD
Definition color_out.h:48
#define TERM_RESET
Definition color_out.h:47
#define TRED(x)
Definition color_out.h:75

References color_printf(), device_state::deckLink, decklink_supports_codec(), device_state::deckLinkAttributes, device_state::deckLinkInput, get_codec_name(), get_connection_string_map(), LOG, LOG_LEVEL_ERROR, MOD_NAME, print_bmd_attribute(), print_input_modes(), RELEASE_IF_NOT_NULL, SBOLD, TERM_BOLD, TERM_RESET, TRED, and uv_to_bmd_codec_map.

Referenced by decklink_help().

Here is the call graph for this function:

◆ vidcap_decklink_probe()

static void vidcap_decklink_probe ( device_info ** available_cards,
int * card_count,
void(** deleter )(void *) )
static

Definition at line 859 of file decklink.cpp.

860{
861 device_info *cards = nullptr;
862 *card_count = 0;
863 *deleter = free;
864
865 // Create an IDeckLinkIterator object to enumerate all DeckLink cards in the system
866 bool com_initialized = false;
867
868 // Enumerate all cards in this system
869 for (auto &d : bmd_get_sorted_devices(&com_initialized, false)) {
870 IDeckLink *deckLink = get<0>(d).get();
871 HRESULT result;
872 IDeckLinkProfileAttributes *deckLinkAttributes;
873
874 result = deckLink->QueryInterface(IID_IDeckLinkProfileAttributes, (void**)&deckLinkAttributes);
875 if (result != S_OK) {
876 continue;
877 }
878 int64_t connections_bitmap;
879 if(deckLinkAttributes->GetInt(BMDDeckLinkVideoInputConnections, &connections_bitmap) != S_OK) {
880 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Could not get connections, skipping device.\n");
881 continue;
882 }
883
884 string deviceName = bmd_get_device_name(deckLink);
885 if (deviceName.empty()) {
886 deviceName = "(unknown)";
887 }
888
889 *card_count += 1;
890 cards = (struct device_info *)
891 realloc(cards, *card_count * sizeof(struct device_info));
892 memset(&cards[*card_count - 1], 0, sizeof(struct device_info));
893 snprintf(cards[*card_count - 1].dev, sizeof cards[*card_count - 1].dev,
894 ":device=%6x", get<unsigned>(d));
895 snprintf(cards[*card_count - 1].name, sizeof cards[*card_count - 1].name,
896 "%s", deviceName.c_str());
897 snprintf(cards[*card_count - 1].extra, sizeof cards[*card_count - 1].extra,
898 "\"embeddedAudioAvailable\":\"t\"");
899
900
901 list<string> connections;
902 for (auto const &it : get_connection_string_map()) {
903 if (connections_bitmap & it.first) {
904 connections.push_back(it.second);
905 }
906 }
907 list<tuple<int, string, string, string>> modes = get_input_modes (deckLink);
908
909 int i = 0;
910 const int mode_count = sizeof cards[*card_count - 1].modes /
911 sizeof cards[*card_count - 1].modes[0];
912
913 for (auto &c : connections) {
914 if (i >= mode_count) {
915 break;
916 }
917 snprintf(cards[*card_count - 1].modes[i].id,
918 sizeof cards[*card_count - 1].modes[i].id,
919 R"({"modeOpt":"connection=%s:codec=UYVY"})",
920 c.c_str());
921 snprintf(cards[*card_count - 1].modes[i].name,
922 sizeof cards[*card_count - 1].modes[i].name,
923 "DeckLink Auto (%s)", c.c_str());
924 if (++i >= mode_count) {
925 break;
926 }
927 snprintf(cards[*card_count - 1].modes[i].id,
928 sizeof cards[*card_count - 1].modes[i].id,
929 R"({"modeOpt":"detect-format:connection=%s:codec=UYVY"})",
930 c.c_str());
931 snprintf(cards[*card_count - 1].modes[i].name,
932 sizeof cards[*card_count - 1].modes[i].name,
933 "UltraGrid auto-detect (%s) (SLOW)", c.c_str());
934 i++;
935 }
936
937 for (auto &m : modes) {
938 for (auto &c : connections) {
939 if (i >= mode_count) { // no space
940 break;
941 }
942
943 snprintf(cards[*card_count - 1].modes[i].id,
944 sizeof cards[*card_count - 1].modes[i].id,
945 R"({"modeOpt":"connection=%s:mode=%s:codec=UYVY"})",
946 c.c_str(), get<1>(m).c_str());
947 snprintf(cards[*card_count - 1].modes[i].name,
948 sizeof cards[*card_count - 1].modes[i].name,
949 "%s (%s)", get<2>(m).c_str(), c.c_str());
950 i++;
951 }
952 }
953
954 dev_add_option(&cards[*card_count - 1], "3D", "3D", "3D", ":3D", true);
955 dev_add_option(&cards[*card_count - 1], "Profile", "Duplex profile can be one of: 1dhd, 2dhd, 2dfd, 4dhd, keep", "profile", ":profile=", false);
956
957 RELEASE_IF_NOT_NULL(deckLinkAttributes);
958 }
959
960 decklink_uninitialize(&com_initialized);
961 *available_cards = cards;
962}
int void(** deleter)(void *))
char extra[1024]
Definition types.h:389
struct device_info::mode modes[512]
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(), device_state::deckLink, decklink_uninitialize(), device_state::deckLinkAttributes, deleter, device_info::dev, dev_add_option(), device_info::extra, get_connection_string_map(), get_input_modes(), LOG_LEVEL_WARNING, log_msg(), MOD_NAME, device_info::modes, name, and RELEASE_IF_NOT_NULL.

Here is the call graph for this function:

Variable Documentation

◆ DEFAULT_AUDIO_BPS

const int DEFAULT_AUDIO_BPS = 4
constexpr

Definition at line 89 of file decklink.cpp.

Referenced by decklink_cap_configure_audio().

◆ MAX_AUDIO_PACKETS

const size_t MAX_AUDIO_PACKETS = 10
constexpr

Definition at line 90 of file decklink.cpp.

Referenced by VideoDelegate::VideoInputFrameArrived().

◆ vidcap_decklink_info

const struct video_capture_info vidcap_decklink_info
static
Initial value:
= {
}

Definition at line 1861 of file decklink.cpp.