| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873 |
- #include <objbase.h>
- #include <obs-module.h>
- #include <obs.hpp>
- #include <util/dstr.hpp>
- #include <util/util.hpp>
- #include <util/platform.h>
- #include "libdshowcapture/dshowcapture.hpp"
- #include <string>
- #include <vector>
- /*
- * TODO:
- * - handle disconnections and reconnections
- * - if device not present, wait for device to be plugged in
- */
- using namespace std;
- using namespace DShow;
- /* settings defines that will cause errors if there are typos */
- #define VIDEO_DEVICE_ID "video_device_id"
- #define RES_TYPE "res_type"
- #define RESOLUTION "resolution"
- #define FRAME_INTERVAL "frame_interval"
- #define VIDEO_FORMAT "video_format"
- #define LAST_VIDEO_DEV_ID "last_video_device_id"
- #define LAST_RESOLUTION "last_resolution"
- #define LAST_RES_TYPE "last_res_type"
- #define LAST_INTERVAL "last_interval"
- enum ResType {
- ResType_Preferred,
- ResType_Custom
- };
- struct DShowInput {
- obs_source_t source;
- Device device;
- bool comInitialized;
- VideoConfig videoConfig;
- AudioConfig audioConfig;
- source_frame frame;
- inline DShowInput(obs_source_t source_)
- : source (source_),
- device (InitGraph::False),
- comInitialized (false)
- {}
- static void OnVideoData(DShowInput *input, unsigned char *data,
- size_t size, long long startTime, long long endTime);
- void Update(obs_data_t settings);
- };
- void encode_dstr(struct dstr *str)
- {
- dstr_replace(str, "#", "#22");
- dstr_replace(str, ":", "#3A");
- }
- void decode_dstr(struct dstr *str)
- {
- dstr_replace(str, "#3A", ":");
- dstr_replace(str, "#22", "#");
- }
- static inline video_format ConvertVideoFormat(VideoFormat format)
- {
- switch (format) {
- case VideoFormat::ARGB: return VIDEO_FORMAT_BGRA;
- case VideoFormat::XRGB: return VIDEO_FORMAT_BGRX;
- case VideoFormat::I420: return VIDEO_FORMAT_I420;
- case VideoFormat::NV12: return VIDEO_FORMAT_NV12;
- case VideoFormat::YVYU: return VIDEO_FORMAT_UYVY;
- case VideoFormat::YUY2: return VIDEO_FORMAT_YUY2;
- case VideoFormat::UYVY: return VIDEO_FORMAT_YVYU;
- case VideoFormat::MJPEG: return VIDEO_FORMAT_YUY2;
- default: return VIDEO_FORMAT_NONE;
- }
- }
- void DShowInput::OnVideoData(DShowInput *input, unsigned char *data,
- size_t size, long long startTime, long long endTime)
- {
- const int cx = input->videoConfig.cx;
- const int cy = input->videoConfig.cy;
- input->frame.timestamp = (uint64_t)startTime * 100;
- if (input->videoConfig.format == VideoFormat::XRGB ||
- input->videoConfig.format == VideoFormat::ARGB) {
- input->frame.data[0] = data;
- input->frame.linesize[0] = cx * 4;
- } else if (input->videoConfig.format == VideoFormat::YVYU ||
- input->videoConfig.format == VideoFormat::YUY2 ||
- input->videoConfig.format == VideoFormat::UYVY) {
- input->frame.data[0] = data;
- input->frame.linesize[0] = cx * 2;
- } else if (input->videoConfig.format == VideoFormat::I420) {
- input->frame.data[0] = data;
- input->frame.data[1] = input->frame.data[0] + (cx * cy);
- input->frame.data[2] = input->frame.data[1] + (cx * cy / 4);
- input->frame.linesize[0] = cx;
- input->frame.linesize[1] = cx / 2;
- input->frame.linesize[2] = cx / 2;
- } else {
- /* TODO: other formats */
- return;
- }
- obs_source_output_video(input->source, &input->frame);
- UNUSED_PARAMETER(endTime); /* it's the enndd tiimmes! */
- UNUSED_PARAMETER(size);
- }
- static bool DecodeDeviceId(DeviceId &out, const char *device_id)
- {
- const char *path_str;
- DStr name, path;
- if (!device_id || !*device_id)
- return false;
- path_str = strchr(device_id, ':');
- if (!path_str)
- return false;
- dstr_copy(path, path_str+1);
- dstr_copy(name, device_id);
- size_t len = path_str - device_id;
- name->array[len] = 0;
- name->len = len;
- decode_dstr(name);
- decode_dstr(path);
- BPtr<wchar_t> wname = dstr_to_wcs(name);
- out.name = wname;
- if (!dstr_isempty(path)) {
- BPtr<wchar_t> wpath = dstr_to_wcs(path);
- out.path = wpath;
- }
- return true;
- }
- static inline bool ConvertRes(int &cx, int &cy, const char *res)
- {
- return sscanf(res, "%dx%d", &cx, &cy) == 2;
- }
- static void ApplyDefaultConfigSettings(obs_data_t settings,
- const VideoConfig &config)
- {
- string res = to_string(config.cx) + string("x") + to_string(config.cy);
- obs_data_setstring(settings, RESOLUTION, res.c_str());
- obs_data_setint(settings, FRAME_INTERVAL, config.frameInterval);
- obs_data_setint(settings, VIDEO_FORMAT, (int)config.internalFormat);
- obs_data_setstring(settings, LAST_RESOLUTION, res.c_str());
- obs_data_setint(settings, LAST_INTERVAL, config.frameInterval);
- obs_data_setint(settings, LAST_RES_TYPE, ResType_Preferred);
- }
- void DShowInput::Update(obs_data_t settings)
- {
- const char *video_device_id, *res;
- DeviceId id;
- video_device_id = obs_data_getstring (settings, VIDEO_DEVICE_ID);
- res = obs_data_getstring (settings, RESOLUTION);
- long long interval = obs_data_getint (settings, FRAME_INTERVAL);
- int resType = (int)obs_data_getint(settings, RES_TYPE);
- VideoFormat format = (VideoFormat)obs_data_getint(settings,
- VIDEO_FORMAT);
- if (!comInitialized) {
- CoInitialize(nullptr);
- comInitialized = true;
- }
- if (!device.ResetGraph())
- return;
- if (!DecodeDeviceId(id, video_device_id))
- return;
- int cx, cy;
- if (!ConvertRes(cx, cy, res)) {
- blog(LOG_WARNING, "DShowInput::Update: Bad resolution '%s'",
- res);
- return;
- }
- videoConfig.name = id.name.c_str();
- videoConfig.path = id.path.c_str();
- videoConfig.callback = CaptureProc(DShowInput::OnVideoData);
- videoConfig.param = this;
- videoConfig.useDefaultConfig = resType == ResType_Preferred;
- videoConfig.cx = cx;
- videoConfig.cy = cy;
- videoConfig.frameInterval = interval;
- videoConfig.internalFormat = format;
- if (videoConfig.internalFormat != VideoFormat::MJPEG)
- videoConfig.format = videoConfig.internalFormat;
- device.SetVideoConfig(&videoConfig);
- if (videoConfig.internalFormat == VideoFormat::MJPEG) {
- videoConfig.format = VideoFormat::XRGB;
- device.SetVideoConfig(&videoConfig);
- }
- if (!device.ConnectFilters())
- return;
- if (device.Start() != Result::Success)
- return;
- if (videoConfig.useDefaultConfig)
- ApplyDefaultConfigSettings(settings, videoConfig);
- frame.width = videoConfig.cx;
- frame.height = videoConfig.cy;
- frame.format = ConvertVideoFormat(videoConfig.format);
- frame.full_range = false;
- frame.flip = (videoConfig.format == VideoFormat::XRGB ||
- videoConfig.format == VideoFormat::ARGB);
- if (!video_format_get_parameters(VIDEO_CS_601, VIDEO_RANGE_PARTIAL,
- frame.color_matrix,
- frame.color_range_min,
- frame.color_range_max)) {
- blog(LOG_ERROR, "Failed to get video format parameters for " \
- "video format %u", VIDEO_CS_601);
- }
- }
- /* ------------------------------------------------------------------------- */
- static const char *GetDShowInputName(const char *locale)
- {
- UNUSED_PARAMETER(locale);
- return "Video Capture Device";
- }
- static void *CreateDShowInput(obs_data_t settings, obs_source_t source)
- {
- DShowInput *dshow = new DShowInput(source);
- /* causes a deferred update in the video thread */
- obs_source_update(source, nullptr);
- UNUSED_PARAMETER(settings);
- return dshow;
- }
- static void DestroyDShowInput(void *data)
- {
- delete reinterpret_cast<DShowInput*>(data);
- }
- static uint32_t GetDShowWidth(void *data)
- {
- return reinterpret_cast<DShowInput*>(data)->videoConfig.cx;
- }
- static uint32_t GetDShowHeight(void *data)
- {
- return reinterpret_cast<DShowInput*>(data)->videoConfig.cy;
- }
- static void UpdateDShowInput(void *data, obs_data_t settings)
- {
- reinterpret_cast<DShowInput*>(data)->Update(settings);
- }
- static void GetDShowDefaults(obs_data_t settings)
- {
- obs_data_set_default_int(settings, RES_TYPE, ResType_Preferred);
- obs_data_set_default_int(settings, VIDEO_FORMAT, (int)VideoFormat::Any);
- }
- struct PropertiesData {
- vector<VideoDevice> devices;
- const bool GetDevice(VideoDevice &device, const char *encoded_id)
- {
- DeviceId deviceId;
- DecodeDeviceId(deviceId, encoded_id);
- for (const VideoDevice &curDevice : devices) {
- if (deviceId.name.compare(curDevice.name) == 0 &&
- deviceId.path.compare(curDevice.path) == 0) {
- device = curDevice;
- return true;
- }
- }
- return false;
- }
- };
- struct Resolution {
- int cx, cy;
- inline Resolution(int cx, int cy) : cx(cx), cy(cy) {}
- };
- static void InsertResolution(vector<Resolution> &resolutions, int cx, int cy)
- {
- int bestCY = 0;
- size_t idx = 0;
- for (; idx < resolutions.size(); idx++) {
- const Resolution &res = resolutions[idx];
- if (res.cx > cx)
- break;
- if (res.cx == cx) {
- if (res.cy == cy)
- return;
- if (!bestCY)
- bestCY = res.cy;
- else if (res.cy > bestCY)
- break;
- }
- }
- resolutions.insert(resolutions.begin() + idx, Resolution(cx, cy));
- }
- static inline void AddCap(vector<Resolution> &resolutions, const VideoInfo &cap)
- {
- InsertResolution(resolutions, cap.minCX, cap.minCY);
- InsertResolution(resolutions, cap.maxCX, cap.maxCY);
- }
- #define MAX_LL 0x7FFFFFFFFFFFFFFFLL
- #define MAKE_DSHOW_FPS(fps) (10000000LL/(fps))
- #define MAKE_DSHOW_FRACTIONAL_FPS(den, num) ((num)*10000000LL/(den))
- struct FPSFormat {
- const char *text;
- long long interval;
- };
- static const FPSFormat validFPSFormats[] = {
- {"60", MAKE_DSHOW_FPS(60)},
- {"59.94 NTSC", MAKE_DSHOW_FRACTIONAL_FPS(60000, 1001)},
- {"50", MAKE_DSHOW_FPS(50)},
- {"48 film", MAKE_DSHOW_FRACTIONAL_FPS(48000, 1001)},
- {"40", MAKE_DSHOW_FPS(40)},
- {"30", MAKE_DSHOW_FPS(30)},
- {"29.97 NTSC", MAKE_DSHOW_FRACTIONAL_FPS(30000, 1001)},
- {"25", MAKE_DSHOW_FPS(25)},
- {"24 film", MAKE_DSHOW_FRACTIONAL_FPS(24000, 1001)},
- {"20", MAKE_DSHOW_FPS(20)},
- {"15", MAKE_DSHOW_FPS(15)},
- {"10", MAKE_DSHOW_FPS(10)},
- {"5", MAKE_DSHOW_FPS(5)},
- {"4", MAKE_DSHOW_FPS(4)},
- {"3", MAKE_DSHOW_FPS(3)},
- {"2", MAKE_DSHOW_FPS(2)},
- {"1", MAKE_DSHOW_FPS(1)},
- };
- #define DEVICE_INTERVAL_DIFF_LIMIT 20
- static bool AddFPSRate(obs_property_t p, const FPSFormat &format,
- const VideoInfo &cap)
- {
- long long interval = format.interval;
- if (format.interval < cap.minInterval ||
- format.interval > cap.maxInterval) {
- /* account for slight inaccuracies in intervals
- * among different devices */
- long long diff = 0;
- if (format.interval < cap.minInterval) {
- interval = cap.minInterval;
- diff = cap.minInterval - format.interval;
- } else if (format.interval > cap.maxInterval) {
- interval = cap.maxInterval;
- diff = format.interval - cap.minInterval;
- }
- if (diff > DEVICE_INTERVAL_DIFF_LIMIT)
- return false;
- }
- obs_property_list_add_int(p, format.text, interval);
- return true;
- }
- static inline bool AddFPSRates(obs_property_t p, const VideoDevice &device,
- int cx, int cy, long long &interval)
- {
- long long bestInterval = MAX_LL;
- bool intervalFound = false;
- for (const FPSFormat &format : validFPSFormats) {
- for (const VideoInfo &cap : device.caps) {
- if (cx >= cap.minCX && cx <= cap.maxCX &&
- cy >= cap.minCY && cy <= cap.maxCY) {
- if (!intervalFound) {
- if (interval >= cap.minInterval &&
- interval <= cap.maxInterval)
- intervalFound = true;
- else if (cap.minInterval < bestInterval)
- bestInterval = cap.minInterval;
- }
- if (AddFPSRate(p, format, cap))
- break;
- }
- }
- }
- if (!intervalFound) {
- interval = bestInterval;
- return false;
- }
- return true;
- }
- static bool DeviceIntervalChanged(obs_properties_t props, obs_property_t p,
- obs_data_t settings);
- static bool DeviceResolutionChanged(obs_properties_t props, obs_property_t p,
- obs_data_t settings)
- {
- PropertiesData *data = (PropertiesData*)obs_properties_get_param(props);
- const char *res, *last_res, *id;
- long long interval;
- VideoDevice device;
- id = obs_data_getstring(settings, VIDEO_DEVICE_ID);
- res = obs_data_getstring(settings, RESOLUTION);
- last_res = obs_data_getstring(settings, LAST_RESOLUTION);
- interval = obs_data_getint (settings, FRAME_INTERVAL);
- if (!data->GetDevice(device, id))
- return true;
- int cx, cy;
- if (!ConvertRes(cx, cy, res))
- return true;
- p = obs_properties_get(props, FRAME_INTERVAL);
- obs_property_list_clear(p);
- if (!AddFPSRates(p, device, cx, cy, interval))
- obs_data_setint(settings, FRAME_INTERVAL, interval);
- if (res && last_res && strcmp(res, last_res) != 0) {
- DeviceIntervalChanged(props, p, settings);
- obs_data_setstring(settings, LAST_RESOLUTION, res);
- }
- return true;
- }
- template<typename T> static inline T GetRating(T desired, T minVal, T maxVal,
- T &bestVal)
- {
- T rating = 0;
- if (desired < minVal) {
- rating = minVal - desired;
- bestVal = minVal;
- } else if (desired > maxVal) {
- rating = desired - maxVal;
- bestVal = maxVal;
- } else {
- bestVal = desired;
- }
- return rating;
- }
- static void SetClosestResFPS(obs_properties_t props, obs_data_t settings)
- {
- PropertiesData *data = (PropertiesData*)obs_properties_get_param(props);
- const char *id = obs_data_getstring(settings, VIDEO_DEVICE_ID);
- VideoDevice device;
- if (!data->GetDevice(device, id))
- return;
- obs_video_info ovi;
- if (!obs_get_video_info(&ovi))
- return;
- long long desiredInterval =
- MAKE_DSHOW_FRACTIONAL_FPS(ovi.fps_num, ovi.fps_den);
- long long bestRating = MAX_LL;
- long long bestInterval = 0;
- int bestCX = 0, bestCY = 0;
- for (const VideoInfo &cap : device.caps) {
- long long rating = 0;
- long long interval = 0;
- int cx = 0, cy = 0;
- rating += GetRating<long long>(desiredInterval,
- cap.minInterval, cap.maxInterval, interval);
- rating += GetRating<int>(ovi.base_width,
- cap.minCX, cap.maxCX, cx);
- rating += GetRating<int>(ovi.base_height,
- cap.minCY, cap.maxCY, cy);
- if (rating < bestRating) {
- bestInterval = interval;
- bestCX = cx;
- bestCY = cy;
- bestRating = rating;
- if (rating == 0)
- break;
- }
- }
- if (bestRating != MAX_LL) {
- string strRes;
- strRes = to_string(bestCX) + string("x") + to_string(bestCY);
- obs_data_setstring(settings, RESOLUTION, strRes.c_str());
- obs_data_setint(settings, FRAME_INTERVAL, bestInterval);
- }
- }
- struct VideoFormatName {
- VideoFormat format;
- const char *name;
- };
- static const VideoFormatName videoFormatNames[] = {
- /* raw formats */
- {VideoFormat::ARGB, "ARGB"},
- {VideoFormat::XRGB, "XRGB"},
- /* planar YUV formats */
- {VideoFormat::I420, "I420"},
- {VideoFormat::NV12, "NV12"},
- /* packed YUV formats */
- {VideoFormat::YVYU, "YVYU"},
- {VideoFormat::YUY2, "YUY2"},
- {VideoFormat::UYVY, "UYVY"},
- {VideoFormat::HDYC, "HDYV"},
- /* encoded formats */
- {VideoFormat::MPEG2, "MPEG2"},
- {VideoFormat::MJPEG, "MJPEG"},
- {VideoFormat::H264, "H264"}
- };
- static bool UpdateVideoFormats(obs_properties_t props, VideoDevice &device,
- long long interval, int cx, int cy, VideoFormat format)
- {
- bool foundFormat = false;
- obs_property_t p = obs_properties_get(props, VIDEO_FORMAT);
- obs_property_list_clear(p);
- obs_property_list_add_int(p, "Any", (int)VideoFormat::Any);
- for (const VideoFormatName &name : videoFormatNames) {
- for (const VideoInfo &cap : device.caps) {
- if (interval >= cap.minInterval &&
- interval <= cap.maxInterval &&
- cx >= cap.minCX && cx <= cap.maxCX &&
- cy >= cap.minCY && cy <= cap.maxCY &&
- cap.format == name.format) {
- if (format == cap.format)
- foundFormat = true;
- obs_property_list_add_int(p, name.name,
- (int)name.format);
- break;
- }
- }
- }
- return foundFormat;
- }
- static bool DeviceSelectionChanged(obs_properties_t props, obs_property_t p,
- obs_data_t settings)
- {
- PropertiesData *data = (PropertiesData*)obs_properties_get_param(props);
- const char *id, *old_id;
- VideoDevice device;
- id = obs_data_getstring(settings, VIDEO_DEVICE_ID);
- old_id = obs_data_getstring(settings, LAST_VIDEO_DEV_ID);
- if (!data->GetDevice(device, id))
- return false;
- vector<Resolution> resolutions;
- for (const VideoInfo &cap : device.caps)
- AddCap(resolutions, cap);
- p = obs_properties_get(props, RESOLUTION);
- obs_property_list_clear(p);
- for (size_t idx = resolutions.size(); idx > 0; idx--) {
- const Resolution &res = resolutions[idx-1];
- string strRes;
- strRes += to_string(res.cx);
- strRes += "x";
- strRes += to_string(res.cy);
- obs_property_list_add_string(p, strRes.c_str(), strRes.c_str());
- }
- /* only reset resolution if device legitimately changed */
- if (old_id && id && strcmp(id, old_id) != 0) {
- SetClosestResFPS(props, settings);
- DeviceResolutionChanged(props, p, settings);
- obs_data_setint(settings, VIDEO_FORMAT, (int)VideoFormat::Any);
- obs_data_setstring(settings, LAST_VIDEO_DEV_ID, id);
- }
- return true;
- }
- static bool VideoConfigClicked(obs_properties_t props, obs_property_t p,
- void *data)
- {
- DShowInput *input = reinterpret_cast<DShowInput*>(data);
- input->device.OpenDialog(nullptr, DialogType::ConfigVideo);
- UNUSED_PARAMETER(props);
- UNUSED_PARAMETER(p);
- return false;
- }
- static bool AudioConfigClicked(obs_properties_t props, obs_property_t p,
- void *data)
- {
- DShowInput *input = reinterpret_cast<DShowInput*>(data);
- input->device.OpenDialog(nullptr, DialogType::ConfigAudio);
- UNUSED_PARAMETER(props);
- UNUSED_PARAMETER(p);
- return false;
- }
- static bool CrossbarConfigClicked(obs_properties_t props, obs_property_t p,
- void *data)
- {
- DShowInput *input = reinterpret_cast<DShowInput*>(data);
- input->device.OpenDialog(nullptr, DialogType::ConfigCrossbar);
- UNUSED_PARAMETER(props);
- UNUSED_PARAMETER(p);
- return false;
- }
- static bool Crossbar2ConfigClicked(obs_properties_t props, obs_property_t p,
- void *data)
- {
- DShowInput *input = reinterpret_cast<DShowInput*>(data);
- input->device.OpenDialog(nullptr, DialogType::ConfigCrossbar2);
- UNUSED_PARAMETER(props);
- UNUSED_PARAMETER(p);
- return false;
- }
- static bool AddDevice(obs_property_t device_list, const VideoDevice &device)
- {
- DStr name, path, device_id;
- dstr_from_wcs(name, device.name.c_str());
- dstr_from_wcs(path, device.path.c_str());
- encode_dstr(path);
- dstr_copy_dstr(device_id, name);
- encode_dstr(device_id);
- dstr_cat(device_id, ":");
- dstr_cat_dstr(device_id, path);
- obs_property_list_add_string(device_list, name, device_id);
- return true;
- }
- static void PropertiesDataDestroy(void *data)
- {
- delete reinterpret_cast<PropertiesData*>(data);
- }
- static bool ResTypeChanged(obs_properties_t props, obs_property_t p,
- obs_data_t settings)
- {
- int val = (int)obs_data_getint(settings, RES_TYPE);
- int lastVal = (int)obs_data_getint(settings, LAST_RES_TYPE);
- bool enabled = (val != ResType_Preferred);
- p = obs_properties_get(props, RESOLUTION);
- obs_property_set_enabled(p, enabled);
- p = obs_properties_get(props, FRAME_INTERVAL);
- obs_property_set_enabled(p, enabled);
- p = obs_properties_get(props, VIDEO_FORMAT);
- obs_property_set_enabled(p, enabled);
- if (val == ResType_Custom && lastVal != val) {
- SetClosestResFPS(props, settings);
- obs_data_setint(settings, LAST_RES_TYPE, val);
- }
- return true;
- }
- static bool DeviceIntervalChanged(obs_properties_t props, obs_property_t p,
- obs_data_t settings)
- {
- int val = (int)obs_data_getint(settings, FRAME_INTERVAL);
- int lastVal = (int)obs_data_getint(settings, LAST_INTERVAL);
- PropertiesData *data = (PropertiesData*)obs_properties_get_param(props);
- const char *id = obs_data_getstring(settings, VIDEO_DEVICE_ID);
- VideoDevice device;
- if (!data->GetDevice(device, id))
- return false;
- int cx, cy;
- const char *res = obs_data_getstring(settings, RESOLUTION);
- if (!ConvertRes(cx, cy, res))
- return true;
- VideoFormat curFormat =
- (VideoFormat)obs_data_getint(settings, VIDEO_FORMAT);
- bool foundFormat =
- UpdateVideoFormats(props, device, val, cx, cy, curFormat);
- if (val != lastVal) {
- if (!foundFormat)
- obs_data_setint(settings, VIDEO_FORMAT,
- (int)VideoFormat::Any);
- obs_data_setint(settings, LAST_INTERVAL, val);
- }
- UNUSED_PARAMETER(p);
- return true;
- }
- static obs_properties_t GetDShowProperties(const char *locale)
- {
- obs_properties_t ppts = obs_properties_create(locale);
- PropertiesData *data = new PropertiesData;
- obs_properties_set_param(ppts, data, PropertiesDataDestroy);
- /* TODO: locale */
- obs_property_t p = obs_properties_add_list(ppts,
- VIDEO_DEVICE_ID, "Device",
- OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
- obs_property_set_modified_callback(p, DeviceSelectionChanged);
- Device::EnumVideoDevices(data->devices);
- for (const VideoDevice &device : data->devices)
- AddDevice(p, device);
- obs_properties_add_button(ppts, "video_config", "Configure Video",
- VideoConfigClicked);
- obs_properties_add_button(ppts, "xbar_config", "Configure Crossbar",
- CrossbarConfigClicked);
- /* ------------------------------------- */
- p = obs_properties_add_list(ppts, RES_TYPE, "Resolution/FPS Type",
- OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
- obs_property_set_modified_callback(p, ResTypeChanged);
- obs_property_list_add_int(p, "Device Preferred", ResType_Preferred);
- obs_property_list_add_int(p, "Custom", ResType_Custom);
- p = obs_properties_add_list(ppts, RESOLUTION, "Resolution",
- OBS_COMBO_TYPE_EDITABLE, OBS_COMBO_FORMAT_STRING);
- obs_property_set_modified_callback(p, DeviceResolutionChanged);
- p = obs_properties_add_list(ppts, FRAME_INTERVAL, "FPS",
- OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
- obs_property_set_modified_callback(p, DeviceIntervalChanged);
- obs_properties_add_list(ppts, VIDEO_FORMAT, "Video Format",
- OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
- return ppts;
- }
- OBS_DECLARE_MODULE()
- void DShowModuleLogCallback(LogType type, const wchar_t *msg, void *param)
- {
- int obs_type = LOG_DEBUG;
- switch (type) {
- case LogType::Error: obs_type = LOG_ERROR; break;
- case LogType::Warning: obs_type = LOG_WARNING; break;
- case LogType::Info: obs_type = LOG_INFO; break;
- case LogType::Debug: obs_type = LOG_DEBUG; break;
- }
- DStr dmsg;
- dstr_from_wcs(dmsg, msg);
- blog(obs_type, "DShow: %s", dmsg->array);
- UNUSED_PARAMETER(param);
- }
- bool obs_module_load(uint32_t libobs_ver)
- {
- UNUSED_PARAMETER(libobs_ver);
- SetLogCallback(DShowModuleLogCallback, nullptr);
- obs_source_info info = {};
- info.id = "dshow_input";
- info.type = OBS_SOURCE_TYPE_INPUT;
- info.output_flags = OBS_SOURCE_VIDEO |
- OBS_SOURCE_ASYNC;
- info.getname = GetDShowInputName;
- info.create = CreateDShowInput;
- info.destroy = DestroyDShowInput;
- info.getwidth = GetDShowWidth;
- info.getheight = GetDShowHeight;
- info.update = UpdateDShowInput;
- info.defaults = GetDShowDefaults;
- info.properties = GetDShowProperties;
- obs_register_source(&info);
- return true;
- }
|