From 08abdf7605d937784dbc0b22284b3aafe72191da Mon Sep 17 00:00:00 2001 From: Martin Pulec Date: Tue, 9 Apr 2024 15:50:13 +0200 Subject: [PATCH] vcap/dshow probe fixes - if skipped, the mediaType was not deallocated - use own mode variable instead of 'i', because otherwise there would be holes + print the id, not the ordinal numeber of the mode (now it doesn't match) - last mode must be zero (the show_help expects zero-termination) even if there are not enough space --- src/utils/macros.h | 12 +++++ src/video_capture/DirectShowGrabber.cpp | 61 ++++++++++++++++++------- 2 files changed, 56 insertions(+), 17 deletions(-) diff --git a/src/utils/macros.h b/src/utils/macros.h index 9d452d970..2e064fc7f 100644 --- a/src/utils/macros.h +++ b/src/utils/macros.h @@ -83,6 +83,18 @@ } \ } while (0) +/// soft version of @ref UG_ASSERT_SOFT - only exit if user requested exit on +/// failures +#define UG_ASSERT_NO_FATAL(cond) \ + do { /* NOLINT(cppcoreguidelines-avoid-do-while) */ \ + if (!(cond)) { \ + fprintf(stderr, \ + "%s:%d: %s: Assertion `" #cond "' failed.\n", \ + __FILE__, __LINE__, __func__); \ + handle_error(EXIT_FAILURE); \ + } \ + } while (0) + /// shortcut for `snprintf(var, sizeof var...)`, `var` must be a char array #define snprintf_ch(str, ...) snprintf(str, sizeof str, __VA_ARGS__) #define starts_with(str, token) !strncmp(str, token, strlen(token)) diff --git a/src/video_capture/DirectShowGrabber.cpp b/src/video_capture/DirectShowGrabber.cpp index 39170ef12..c2afce917 100644 --- a/src/video_capture/DirectShowGrabber.cpp +++ b/src/video_capture/DirectShowGrabber.cpp @@ -44,7 +44,9 @@ static const CHAR * GetSubtypeName(const GUID *pSubtype); static codec_t get_ug_codec(const GUID *pSubtype); static convert_t get_conversion(const GUID *pSubtype); static codec_t get_ug_from_subtype_name(const char *subtype_name); -static void vidcap_dshow_probe(device_info **available_cards, int *count, void (**deleter)(void *)); +static void vidcap_dshow_probe_internal(device_info **available_cards, + int *count, void (**deleter)(void *), + bool include_unsupported); static void ErrorDescription(HRESULT hr) { @@ -339,8 +341,9 @@ static struct video_desc vidcap_dshow_get_video_desc(AM_MEDIA_TYPE *mediaType) return desc; } -static void show_help(struct vidcap_dshow_state *s) { +static void show_help(struct vidcap_dshow_state *s, bool full) { printf("dshow grabber options:\n"); + col() << SBOLD("\t-t dshow:[full]help") << "\n"; col() << SBOLD(SRED("\t-t dshow") << "[:device=|][:mode=][:RGB]") "\n"; col() << "\t Flag " << SBOLD("RGB") << " forces use of RGB codec, otherwise native is used if possible.\n"; printf("\tor\n"); @@ -352,7 +355,7 @@ static void show_help(struct vidcap_dshow_state *s) { device_info *cards = nullptr; int count = 0; void (*deleter)(void *) = NULL; - vidcap_dshow_probe(&cards, &count, &deleter); + vidcap_dshow_probe_internal(&cards, &count, &deleter, full); // Enumerate all capture devices for (int n = 0; n < count; ++n) { @@ -361,7 +364,10 @@ static void show_help(struct vidcap_dshow_state *s) { int i = 0; // iterate over all capabilities while (strlen(cards[n].modes[i].id) > 0) { - printf(" Mode %2d: %s", i, cards[n].modes[i].name); + int mode_idx = -1; + sscanf(cards[n].modes[i].id, "{\"mode\":\"%d", &mode_idx); + UG_ASSERT_NO_FATAL(mode_idx != -1); + printf(" Mode %2d: %s", mode_idx, cards[n].modes[i].name); putchar(i % 2 == 1 ? '\n' : '\t'); ++i; } @@ -372,8 +378,10 @@ static void show_help(struct vidcap_dshow_state *s) { deleter(cards); printf("Mode flags:\n"); - printf("C - codec not natively supported by UG; F - video format is " - "not supported\n\n"); + printf("C - codec not natively supported by UG%s\n\n", + full ? "; F - video format is " + "not supported" + : "\n(use ':fullhelp' to see also unsupported modes)"); } static string @@ -405,7 +413,9 @@ get_friendly_name(IMoniker *moniker, int idx = -1) #undef HANDLE_ERR } -static void vidcap_dshow_probe(device_info **available_cards, int *count, void (**deleter)(void *)) +static void +vidcap_dshow_probe_internal(device_info **available_cards, int *count, + void (**deleter)(void *), bool include_unsupported) { *deleter = free; struct vidcap_dshow_state *s = (struct vidcap_dshow_state *) calloc(1, sizeof(struct vidcap_dshow_state)); @@ -464,12 +474,15 @@ static void vidcap_dshow_probe(device_info **available_cards, int *count, void ( continue; } + int mode_idx = 0; // iterate over all capabilities for (int i = 0; i < capCount; i++) { - if (i >= (int) (sizeof cards[card_count - 1].modes / - sizeof cards[card_count - 1].modes[0])) { // no space - break; - } + if (mode_idx >= + (int) (sizeof cards[card_count - 1].modes / + sizeof cards[card_count - 1].modes[0]) - + 1) { // no space + break; + } AM_MEDIA_TYPE *mediaType; VIDEO_STREAM_CONFIG_CAPS streamCaps; @@ -479,18 +492,24 @@ static void vidcap_dshow_probe(device_info **available_cards, int *count, void ( struct video_desc desc = vidcap_dshow_get_video_desc(mediaType); if (desc.width == 0) { + DeleteMediaType(mediaType); + continue; + } + if (mediaType->formattype != FORMAT_VideoInfo && !include_unsupported) { + DeleteMediaType(mediaType); continue; } - snprintf(cards[card_count - 1].modes[i].id, - sizeof cards[card_count - 1].modes[i].id, + snprintf(cards[card_count - 1].modes[mode_idx].id, + sizeof cards[card_count - 1].modes[mode_idx].id, "{\"mode\":\"%d\"}", i); - snprintf(cards[card_count - 1].modes[i].name, - sizeof cards[card_count - 1].modes[i].name, + snprintf(cards[card_count - 1].modes[mode_idx].name, + sizeof cards[card_count - 1].modes[mode_idx].name, "%s %ux%u @%0.2lf%s %s%s", GetSubtypeName(&mediaType->subtype), desc.width, desc.height, desc.fps * (desc.interlacing == INTERLACED_MERGED ? 2 : 1), get_interlacing_suffix(desc.interlacing), desc.color_spec ? "" : "C", mediaType->formattype == FORMAT_VideoInfo ? "" : "F"); + mode_idx += 1; DeleteMediaType(mediaType); } @@ -507,6 +526,12 @@ static void vidcap_dshow_probe(device_info **available_cards, int *count, void ( #undef HANDLE_ERR } +static void +vidcap_dshow_probe(device_info **available_cards, int *count, + void (**deleter)(void *)) { + vidcap_dshow_probe_internal(available_cards, count, deleter, false); +} + static bool process_args(struct vidcap_dshow_state *s, char *init_fmt) { char *token; char *strtok_context; @@ -795,8 +820,10 @@ static int vidcap_dshow_init(struct vidcap_params *params, void **state) { InitializeConditionVariable(&s->grabWaitCV); InitializeCriticalSection(&s->returnBufferCS); - if (vidcap_params_get_fmt(params) && strcmp(vidcap_params_get_fmt(params), "help") == 0) { - show_help(s); + if (strcmp(vidcap_params_get_fmt(params), "help") == 0 || + strcmp(vidcap_params_get_fmt(params), "fullhelp") == 0) { + show_help( + s, strcmp(vidcap_params_get_fmt(params), "fullhelp") == 0); cleanup(s); return VIDCAP_INIT_NOERR; }