Skip to content

Commit 5f67a06

Browse files
committed
bmd_status: print some generally useful info
- refactorized - added API check (hint to re-check changes) - implement ST_BIT_FIELD (for busy status)
1 parent 1bfae7b commit 5f67a06

File tree

1 file changed

+160
-58
lines changed

1 file changed

+160
-58
lines changed

src/blackmagic_common.cpp

Lines changed: 160 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@
6868
#include "utils/windows.h"
6969
#include "utils/worker.h"
7070

71+
#if BLACKMAGIC_DECKLINK_API_VERSION > 0x0c080000
72+
#warning \
73+
"Increased BMD API - enum diffs recheck recommends (or just increase the compared API version)"
74+
#endif
75+
7176
#define MOD_NAME "[DeckLink] "
7277

7378
using std::clamp;
@@ -1273,87 +1278,187 @@ bmd_get_sorted_devices(bool *com_initialized, bool verbose, bool natural_sort)
12731278
return out;
12741279
}
12751280

1276-
static const struct {
1277-
uint32_t fourcc;
1281+
/* ____ _ _ _ _ ____ _ _
1282+
* | _ \ ___ ___| | _| | (_)_ __ | | __/ ___|| |_ __ _| |_ _ _ ___
1283+
* | | | |/ _ \/ __| |/ / | | | '_ \| |/ /\___ \| __/ _` | __| | | / __|
1284+
* | |_| | __/ (__| <| |___| | | | | < ___) | || (_| | |_| |_| \__ \
1285+
* |____/ \___|\___|_|\_\_____|_|_| |_|_|\_\|____/ \__\__,_|\__|\__,_|___/
1286+
*/
1287+
1288+
/// value map, needs to be zero-terminated
1289+
/// if status_type == ST_BIT_FIELD, val==0 must be set
1290+
struct bmd_status_val_map {
1291+
uint32_t val;
12781292
const char *name;
1279-
} status_val_map[] = {
1293+
};
1294+
/// FourCC based values (can be all in one array)
1295+
static const struct bmd_status_val_map status_val_map_dfl[] = {
12801296
{ bmdEthernetLinkStateDisconnected, "disconnected" },
12811297
{ bmdEthernetLinkStateConnectedUnbound, "connected (unbound)" },
12821298
{ bmdEthernetLinkStateConnectedBound, "connected (bound)" },
1299+
{ 0, nullptr },
1300+
};
1301+
static const struct bmd_status_val_map bmd_busy_state_bit_field_map[] = {
1302+
{ 0, "inactive" }, // default val if no bit set
1303+
{ bmdDeviceCaptureBusy, "capture" },
1304+
{ bmdDevicePlaybackBusy, "playback" },
1305+
{ bmdDeviceSerialPortBusy, "serial-port" },
1306+
{ 0, nullptr },
1307+
};
1308+
static const struct bmd_status_val_map bmd_dyn_range_map[] = {
1309+
{ bmdDynamicRangeSDR, "SDR" },
1310+
{ bmdDynamicRangeHDRStaticPQ, "HDR PQ" },
1311+
{ bmdDynamicRangeHDRStaticHLG, "HDR HLG" },
1312+
{ 0, nullptr}
1313+
};
1314+
static const struct bmd_status_val_map bmd_cs_map[] = {
1315+
{ bmdColorspaceRec601, "Rec.601" },
1316+
{ bmdColorspaceRec709, "Rec.709" },
1317+
{ bmdColorspaceRec2020, "Rec.2020" },
1318+
{ 0, nullptr }
12831319
};
12841320
enum status_type {
1285-
ST_FCC,
1286-
ST_INT,
1321+
ST_ENUM, // set type_data.map
1322+
ST_BIT_FIELD, // set type_data.map
1323+
ST_INT, // set type_data.int_fmt_str
12871324
ST_STRING,
12881325
};
1289-
static const struct {
1326+
static const struct status_property {
12901327
BMDDeckLinkStatusID prop;
12911328
const char *prop_name;
12921329
enum status_type type;
1293-
const char *int_units;
1294-
bool playback_only; ///< relevant only for playback;
1330+
union type_data {
1331+
const char *int_fmt_str;
1332+
const struct bmd_status_val_map *map;
1333+
} type_data;
1334+
bool playback_only; ///< relevant only for playback;
1335+
int req_log_level;
12951336
} status_map[] = {
1296-
{ bmdDeckLinkStatusEthernetLink, "Ethernet state", ST_FCC, nullptr,
1297-
false },
1298-
{ bmdDeckLinkStatusEthernetLinkMbps, "Ethernet link speed", ST_INT,
1299-
"Mbps", false },
1300-
{ bmdDeckLinkStatusEthernetLocalIPAddress, "Ethernet IP address",
1301-
ST_STRING, nullptr, false },
1302-
{ bmdDeckLinkStatusEthernetSubnetMask, "Ethernet subnet mask",
1303-
ST_STRING, nullptr, false },
1304-
{ bmdDeckLinkStatusEthernetGatewayIPAddress, "Ethernet gateway IP",
1305-
ST_STRING, nullptr, false },
1337+
{ bmdDeckLinkStatusBusy,
1338+
"Busy", ST_BIT_FIELD,
1339+
{ .map = bmd_busy_state_bit_field_map },
1340+
false, LOG_LEVEL_VERBOSE },
1341+
{ bmdDeckLinkStatusPCIExpressLinkWidth,
1342+
"PCIe Link Width", ST_INT,
1343+
{ .int_fmt_str = "%" PRIu64 "x" },
1344+
false, LOG_LEVEL_VERBOSE },
1345+
{ bmdDeckLinkStatusPCIExpressLinkSpeed,
1346+
"PCIe Link Speed", ST_INT,
1347+
{ .int_fmt_str = "Gen. %" PRIu64 },
1348+
false, LOG_LEVEL_VERBOSE },
1349+
{ bmdDeckLinkStatusDetectedVideoInputColorspace,
1350+
"Video Colorspace", ST_ENUM,
1351+
{ .map = bmd_cs_map },
1352+
false, LOG_LEVEL_INFO },
1353+
{ bmdDeckLinkStatusDetectedVideoInputDynamicRange,
1354+
"Video Dynamic Range", ST_ENUM,
1355+
{ .map = bmd_dyn_range_map },
1356+
false, LOG_LEVEL_INFO },
1357+
{ bmdDeckLinkStatusEthernetLink,
1358+
"Ethernet state", ST_ENUM,
1359+
{ .map = status_val_map_dfl },
1360+
false, LOG_LEVEL_INFO },
1361+
{ bmdDeckLinkStatusEthernetLinkMbps,
1362+
"Ethernet link speed", ST_INT,
1363+
{ .int_fmt_str = "%" PRIu64 " Mbps" },
1364+
false, LOG_LEVEL_INFO },
1365+
{ bmdDeckLinkStatusEthernetLocalIPAddress,
1366+
"Ethernet IP address", ST_STRING,
1367+
{},
1368+
false, LOG_LEVEL_INFO },
1369+
{ bmdDeckLinkStatusEthernetSubnetMask,
1370+
"Ethernet subnet mask", ST_STRING,
1371+
{},
1372+
false, LOG_LEVEL_INFO },
1373+
{ bmdDeckLinkStatusEthernetGatewayIPAddress,
1374+
"Ethernet gateway IP", ST_STRING,
1375+
{},
1376+
false, LOG_LEVEL_INFO },
13061377
{ bmdDeckLinkStatusEthernetVideoOutputAddress,
1307-
"Ethernet video output address", ST_STRING, nullptr, true },
1378+
"Ethernet video output address", ST_STRING,
1379+
{},
1380+
true, LOG_LEVEL_INFO },
13081381
{ bmdDeckLinkStatusEthernetAudioOutputAddress,
1309-
"Ethernet audio output address", ST_STRING, nullptr, true },
1382+
"Ethernet audio output address", ST_STRING,
1383+
{},
1384+
true, LOG_LEVEL_INFO },
13101385
};
13111386
static void
13121387
print_status_item(IDeckLinkStatus *deckLinkStatus, BMDDeckLinkStatusID prop)
13131388
{
1389+
const struct status_property *s_prop = nullptr;
1390+
1391+
for (unsigned i = 0; i < ARR_COUNT(status_map); ++i) {
1392+
if (status_map[i].prop == prop) {
1393+
s_prop = &status_map[i];
1394+
break;
1395+
}
1396+
}
1397+
if (s_prop == nullptr) { // not found
1398+
return;
1399+
}
1400+
if (log_level < s_prop->req_log_level) {
1401+
return;
1402+
}
1403+
13141404
int64_t int_val = 0;
13151405
BMD_STR string_val{};
1316-
for (unsigned u = 0; u < ARR_COUNT(status_map); ++u) {
1317-
if (status_map[u].prop != prop) {
1318-
continue;
1406+
HRESULT rc = s_prop->type == ST_STRING
1407+
? deckLinkStatus->GetString(s_prop->prop, &string_val)
1408+
: deckLinkStatus->GetInt(s_prop->prop, &int_val);
1409+
if (!SUCCEEDED(rc)) {
1410+
if (FAILED(rc) && rc != E_NOTIMPL) {
1411+
MSG(WARNING, "Obtain property 0x%08x value: %s\n",
1412+
(unsigned) prop, bmd_hresult_to_string(rc).c_str());
13191413
}
1320-
switch (status_map[u].type) {
1321-
case ST_STRING: {
1322-
if (FAILED(deckLinkStatus->GetString(status_map[u].prop,
1323-
&string_val))) {
1324-
break;
1414+
return;
1415+
}
1416+
1417+
switch (s_prop->type) {
1418+
case ST_STRING: {
1419+
string str = get_str_from_bmd_api_str(string_val);
1420+
release_bmd_api_str(string_val);
1421+
MSG(INFO, "%s: %s\n", s_prop->prop_name, str.c_str());
1422+
break;
1423+
}
1424+
case ST_INT: {
1425+
char buf[STR_LEN];
1426+
snprintf_ch(buf, s_prop->type_data.int_fmt_str, int_val);
1427+
MSG(INFO, "%s: %s\n", s_prop->prop_name, buf);
1428+
break;
1429+
}
1430+
case ST_BIT_FIELD: {
1431+
char val[STR_LEN];
1432+
val[0] = '\0';
1433+
for (unsigned j = 0; s_prop->type_data.map[j].name != nullptr;
1434+
++j) {
1435+
if ((int_val & s_prop->type_data.map[j].val) == 0) {
1436+
continue;
13251437
}
1326-
string str = get_str_from_bmd_api_str(string_val);
1327-
release_bmd_api_str(string_val);
1328-
MSG(INFO, "%s: %s\n", status_map[u].prop_name,
1329-
str.c_str());
1330-
break;
1438+
snprintf(val + strlen(val), sizeof val - strlen(val),
1439+
"%s%s", val[0] != '\0' ? ", " : "",
1440+
s_prop->type_data.map[j].name);
13311441
}
1332-
case ST_INT:
1333-
if (FAILED(deckLinkStatus->GetInt(status_map[u].prop,
1334-
&int_val))) {
1335-
break;
1336-
}
1337-
MSG(INFO, "%s: %" PRId64 " %s\n",
1338-
status_map[u].prop_name, int_val, status_map[u].int_units);
1339-
break;
1340-
case ST_FCC: {
1341-
const char *val = "unknown";
1342-
if (FAILED(deckLinkStatus->GetInt(status_map[u].prop,
1343-
&int_val))) {
1442+
if (val[0] == '\0') {
1443+
snprintf_ch(val, "%s", s_prop->type_data.map[0].name);
1444+
}
1445+
1446+
MSG(INFO, "%s: %s\n", s_prop->prop_name, val);
1447+
break;
1448+
}
1449+
case ST_ENUM: {
1450+
const char *val = "unknown";
1451+
for (unsigned j = 0; s_prop->type_data.map[j].name != nullptr;
1452+
++j) {
1453+
if (s_prop->type_data.map[j].val == int_val) {
1454+
val = s_prop->type_data.map[j].name;
13441455
break;
13451456
}
1346-
for (unsigned u = 0; u < ARR_COUNT(status_val_map);
1347-
++u) {
1348-
if (status_val_map[u].fourcc == int_val) {
1349-
val = status_val_map[u].name;
1350-
break;
1351-
}
1352-
}
1353-
1354-
MSG(INFO, "%s: %s\n", status_map[u].prop_name, val);
1355-
}
13561457
}
1458+
1459+
MSG(INFO, "%s: %s\n", s_prop->prop_name, val);
1460+
break;
1461+
}
13571462
}
13581463
}
13591464

@@ -1440,9 +1545,6 @@ class BMDNotificationCallback : public IDeckLinkNotificationCallback
14401545
*
14411546
* @returns a pointer representing the notification callback, must be passed to
14421547
* destroy with bmd_unsubscribe_notify()
1443-
*
1444-
* @todo
1445-
* Print some useful information also normally (non-IP devices).
14461548
*/
14471549
BMDNotificationCallback *
14481550
bmd_print_status_subscribe_notify(IDeckLink *deckLink, bool capture)

0 commit comments

Comments
 (0)