diff --git a/plugins/win-dshow/win-dshow.cpp b/plugins/win-dshow/win-dshow.cpp index b63610428..530e3cde8 100644 --- a/plugins/win-dshow/win-dshow.cpp +++ b/plugins/win-dshow/win-dshow.cpp @@ -7,6 +7,7 @@ #include #include "libdshowcapture/dshowcapture.hpp" +#include #include #include #include @@ -82,6 +83,14 @@ static bool FrameRateAvailable(const VideoInfo &cap, long long interval) cap.maxInterval + DEVICE_INTERVAL_DIFF_LIMIT); } +static long long FrameRateInterval(const VideoInfo &cap, + long long desired_interval) +{ + return desired_interval < cap.minInterval ? + cap.minInterval : + min(desired_interval, cap.maxInterval); +} + void encode_dstr(struct dstr *str) { dstr_replace(str, "#", "#22"); @@ -191,6 +200,125 @@ static bool FormatMatches(VideoFormat left, VideoFormat right) left == right; } +static bool ResolutionValid(string res, int &cx, int &cy) +{ + if (!res.size()) + return false; + + return ConvertRes(cx, cy, res.c_str()); +} + +template +static bool CapsMatch(const VideoInfo &info, F&& f, Fs ... fs) +{ + return f(info) && CapsMatch(info, fs ...); +} + +static bool CapsMatch(const VideoInfo&) +{ + return true; +} + +template +static bool CapsMatch(const VideoDevice &dev, F ... fs) +{ + auto matcher = [&](const VideoInfo &info) + { + return CapsMatch(info, fs ...); + }; + + return any_of(begin(dev.caps), end(dev.caps), matcher); +} + +bool MatcherMatchVideoFormat(VideoFormat format, bool &did_match, + const VideoInfo &info) +{ + bool match = FormatMatches(format, info.format); + did_match = did_match || match; + return match; +} + +bool MatcherClosestFrameRateSelector(long long interval, long long &best_match, + const VideoInfo &info) +{ + long long current = FrameRateInterval(info, interval); + if (llabs(interval - best_match) > llabs(interval - current)) + best_match = current; + return true; +} + +#if 0 +auto ResolutionMatcher = [](int cx, int cy) +{ + return [cx, cy](const VideoInfo &info) + { + return ResolutionAvailable(info, cx, cy); + }; +}; + +auto FrameRateMatcher = [](long long interval) +{ + return [interval](const VideoInfo &info) + { + return FrameRateAvailable(info, interval); + }; +}; + +auto VideoFormatMatcher = [](VideoFormat format, bool &did_match) +{ + return [format, &did_match](const VideoInfo &info) + { + return MatcherMatchVideoFormat(format, did_match, info); + }; +}; + +auto ClosestFrameRateSelector = [](long long interval, long long &best_match) +{ + return [interval, &best_match](const VideoInfo &info) mutable -> bool + { + MatcherClosestFrameRateSelector(interval, best_match, info); + }; +} +#else +#define ResolutionMatcher(cx, cy) \ + [cx, cy](const VideoInfo &info) -> bool \ + { return ResolutionAvailable(info, cx, cy); } +#define FrameRateMatcher(interval) \ + [interval](const VideoInfo &info) -> bool \ + { return FrameRateAvailable(info, interval); } +#define VideoFormatMatcher(format, did_match) \ + [format, &did_match](const VideoInfo &info) mutable -> bool \ + { return MatcherMatchVideoFormat(format, did_match, info); } +#define ClosestFrameRateSelector(interval, best_match) \ + [interval, &best_match](const VideoInfo &info) mutable -> bool \ + { return MatcherClosestFrameRateSelector(interval, best_match, info); } +#endif + +static bool ResolutionAvailable(const VideoDevice &dev, int cx, int cy) +{ + return CapsMatch(dev, ResolutionMatcher(cx, cy)); +} + +static bool DetermineResolution(int &cx, int &cy, obs_data_t settings, + VideoDevice dev) +{ + const char *res = obs_data_get_autoselect_string(settings, RESOLUTION); + if (obs_data_has_autoselect(settings, RESOLUTION) && + ConvertRes(cx, cy, res) && + ResolutionAvailable(dev, cx, cy)) + return true; + + res = obs_data_getstring(settings, RESOLUTION); + if (ConvertRes(cx, cy, res) && ResolutionAvailable(dev, cx, cy)) + return true; + + res = obs_data_getstring(settings, LAST_RESOLUTION); + if (ConvertRes(cx, cy, res) && ResolutionAvailable(dev, cx, cy)) + return true; + + return false; +} + void DShowInput::Update(obs_data_t settings) { const char *video_device_id, *res;