obs 属性窗口 及 属性获得
以摄像头属性窗口为例进行介绍:
几个常用的宏
属性名字
#define VIDEO_DEVICE_ID "video_device_id" //设备ID
#define RESOLUTION "resolution" //分辨率
#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 BUFFERING_VAL "buffering"
#define FLIP_IMAGE "flip_vertically"
#define AUDIO_OUTPUT_MODE "audio_output_mode"
#define USE_CUSTOM_AUDIO "use_custom_audio_device"
#define AUDIO_DEVICE_ID "audio_device_id"
#define COLOR_SPACE "color_space"
#define COLOR_RANGE "color_range"
#define DEACTIVATE_WNS "deactivate_when_not_showing"
属性描述
#define TEXT_RESOLUTION obs_module_text("Resolution") //分辨率
#define TEXT_INPUT_NAME obs_module_text("VideoCaptureDevice")
#define TEXT_DEVICE obs_module_text("Device")
#define TEXT_CONFIG_VIDEO obs_module_text("ConfigureVideo")
#define TEXT_CONFIG_XBAR obs_module_text("ConfigureCrossbar")
#define TEXT_RES_FPS_TYPE obs_module_text("ResFPSType")
#define TEXT_CUSTOM_RES obs_module_text("ResFPSType.Custom")
#define TEXT_PREFERRED_RES obs_module_text("ResFPSType.DevPreferred")
#define TEXT_FPS_MATCHING obs_module_text("FPS.Matching")
#define TEXT_FPS_HIGHEST obs_module_text("FPS.Highest")
#define TEXT_RESOLUTION obs_module_text("Resolution") //分辨率
#define TEXT_VIDEO_FORMAT obs_module_text("VideoFormat")
#define TEXT_FORMAT_UNKNOWN obs_module_text("VideoFormat.Unknown")
#define TEXT_BUFFERING obs_module_text("Buffering")
#define TEXT_BUFFERING_AUTO obs_module_text("Buffering.AutoDetect")
#define TEXT_BUFFERING_ON obs_module_text("Buffering.Enable")
#define TEXT_BUFFERING_OFF obs_module_text("Buffering.Disable")
#define TEXT_FLIP_IMAGE obs_module_text("FlipVertically")
#define TEXT_AUDIO_MODE obs_module_text("AudioOutputMode")
#define TEXT_MODE_CAPTURE obs_module_text("AudioOutputMode.Capture")
#define TEXT_MODE_DSOUND obs_module_text("AudioOutputMode.DirectSound")
#define TEXT_MODE_WAVEOUT obs_module_text("AudioOutputMode.WaveOut")
#define TEXT_CUSTOM_AUDIO obs_module_text("UseCustomAudioDevice")
#define TEXT_AUDIO_DEVICE obs_module_text("AudioDevice")
#define TEXT_ACTIVATE obs_module_text("Activate")
#define TEXT_DEACTIVATE obs_module_text("Deactivate")
#define TEXT_COLOR_SPACE obs_module_text("ColorSpace")
#define TEXT_COLOR_DEFAULT obs_module_text("ColorSpace.Default")
#define TEXT_COLOR_RANGE obs_module_text("ColorRange")
#define TEXT_RANGE_PARTIAL obs_module_text("ColorRange.Partial")
#define TEXT_RANGE_FULL obs_module_text("ColorRange.Full")
#define TEXT_DWNS obs_module_text("DeactivateWhenNotShowing")
1 属性窗口 通过CreatePropertiesWindow 创建,
void OBSBasic::CreatePropertiesWindow(obs_source_t *source, bool bShow)
{
if (properties)
properties->close();
properties = new OBSBasicProperties(this, source);
if (bShow)
properties->Init();
properties->setAttribute(Qt::WA_DeleteOnClose, true);
}
属性VIEW
view = new OBSPropertiesView(settings, source,
(PropertiesReloadCallback)obs_source_properties,
(PropertiesUpdateCallback)obs_source_update);
view->setMinimumHeight(150);
obs_properties_t *obs_source_properties(const obs_source_t *source)
{
if (!data_valid(source, "obs_source_properties"))
return NULL;
if (source->info.get_properties) {
obs_properties_t *props;
props = source->info.get_properties(source->context.data);
obs_properties_apply_settings(props, source->context.settings);
return props;
}
return NULL;
}
我们来看看win-dshow接口
void RegisterDShowSource()
{
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_AUDIO |
OBS_SOURCE_ASYNC |
OBS_SOURCE_DO_NOT_DUPLICATE;
info.show = ShowDShowInput;
info.hide = HideDShowInput;
info.get_name = GetDShowInputName;
info.create = CreateDShowInput;
info.destroy = DestroyDShowInput;
info.update = UpdateDShowInput;
info.get_defaults = GetDShowDefaults;
info.get_properties = GetDShowProperties;
obs_register_source(&info);
}
win-dshow属性设置
static obs_properties_t *GetDShowProperties(void *obj)
{
DShowInput *input = reinterpret_cast<DShowInput*>(obj);
obs_properties_t *ppts = obs_properties_create();
PropertiesData *data = new PropertiesData;
data->input = input;
obs_properties_set_param(ppts, data, PropertiesDataDestroy);
//#define VIDEO_DEVICE_ID "video_device_id"
//#define TEXT_DEVICE obs_module_text("Device")
obs_property_t *p = obs_properties_add_list(ppts, //设备列表
VIDEO_DEVICE_ID, TEXT_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);
const char *activateText = TEXT_ACTIVATE;
if (input) {
if (input->active)
activateText = TEXT_DEACTIVATE;
}
obs_properties_add_button(ppts, "activate", activateText,
ActivateClicked);
obs_properties_add_button(ppts, "video_config", TEXT_CONFIG_VIDEO, //ConfigureVideo
VideoConfigClicked);
obs_properties_add_button(ppts, "xbar_config", TEXT_CONFIG_XBAR, //ConfigureCrossbar
CrossbarConfigClicked);
obs_properties_add_bool(ppts, DEACTIVATE_WNS, TEXT_DWNS); //deactivate_when_not_showing
/* ------------------------------------- */
/* video settings */
//name res_type
//des: ResFPSType="分辨率/帧率 类型" //默认 设备默认
p = obs_properties_add_list(ppts, RES_TYPE, TEXT_RES_FPS_TYPE,
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_set_modified_callback(p, ResTypeChanged);
//ResFPSType.DevPreferred="设备默认"
obs_property_list_add_int(p, TEXT_PREFERRED_RES, ResType_Preferred);
//ResFPSType.Custom="自定义"
obs_property_list_add_int(p, TEXT_CUSTOM_RES, ResType_Custom);
//Resolution = "分辨率"
p = obs_properties_add_list(ppts, RESOLUTION, TEXT_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);
//VideoFormat="视频格式"
p = obs_properties_add_list(ppts, VIDEO_FORMAT, TEXT_VIDEO_FORMAT,
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_set_modified_callback(p, VideoFormatChanged);
//ColorSpace="YUV 颜色空间"
p = obs_properties_add_list(ppts, COLOR_SPACE, TEXT_COLOR_SPACE,
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
obs_property_list_add_string(p, TEXT_COLOR_DEFAULT, "default");
obs_property_list_add_string(p, "709", "709");
obs_property_list_add_string(p, "601", "601");
p = obs_properties_add_list(ppts, COLOR_RANGE, TEXT_COLOR_RANGE,
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
obs_property_list_add_string(p, TEXT_RANGE_PARTIAL, "partial");
obs_property_list_add_string(p, TEXT_RANGE_FULL, "full");
p = obs_properties_add_list(ppts, BUFFERING_VAL, TEXT_BUFFERING,
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, TEXT_BUFFERING_AUTO,
(int64_t)BufferingType::Auto);
obs_property_list_add_int(p, TEXT_BUFFERING_ON,
(int64_t)BufferingType::On);
obs_property_list_add_int(p, TEXT_BUFFERING_OFF,
(int64_t)BufferingType::Off);
obs_property_set_long_description(p,
obs_module_text("Buffering.ToolTip"));
obs_properties_add_bool(ppts, FLIP_IMAGE, TEXT_FLIP_IMAGE);
/* ------------------------------------- */
/* audio settings */
Device::EnumAudioDevices(data->audioDevices);
p = obs_properties_add_list(ppts, AUDIO_OUTPUT_MODE, TEXT_AUDIO_MODE,
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(p, TEXT_MODE_CAPTURE,
(int64_t)AudioMode::Capture);
obs_property_list_add_int(p, TEXT_MODE_DSOUND,
(int64_t)AudioMode::DirectSound);
obs_property_list_add_int(p, TEXT_MODE_WAVEOUT,
(int64_t)AudioMode::WaveOut);
if (!data->audioDevices.size())
return ppts;
p = obs_properties_add_bool(ppts, USE_CUSTOM_AUDIO, TEXT_CUSTOM_AUDIO);
obs_property_set_modified_callback(p, CustomAudioClicked);
p = obs_properties_add_list(ppts, AUDIO_DEVICE_ID, TEXT_AUDIO_DEVICE,
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
for (const AudioDevice &device : data->audioDevices)
AddAudioDevice(p, device);
return ppts;
}
2 属性分析
#define VIDEO_DEVICE_ID "video_device_id"
#define TEXT_DEVICE obs_module_text("Device")
对应着
不过,只是添加了这个列表项,但列表中还没有添加子项
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;
}
EXPORT size_t obs_property_list_add_string(obs_property_t *p,
const char *name, const char *val);
往这个列表项中,添加元素,其中元素的名字为name, 值为val
size_t obs_property_list_add_string(obs_property_t *p,
const char *name, const char *val)
{
struct list_data *data = get_list_data(p);
if (data && data->format == OBS_COMBO_FORMAT_STRING)
return add_item(data, name, val);
return 0;
}
static size_t add_item(struct list_data *data, const char *name,
const void *val)
{
struct list_item item = { NULL };
item.name = bstrdup(name);
if (data->format == OBS_COMBO_FORMAT_INT)
item.ll = *(const long long*)val;
else if (data->format == OBS_COMBO_FORMAT_FLOAT)
item.d = *(const double*)val;
else
item.str = bstrdup(val);
return da_push_back(data->items, &item);
}
比如
再看添加几个按钮属性
对应的是
再看以下几个属性列表
其它类似 ,不再介绍
3 获得相关属性
如果我们能获得到 属性值,就可以获得设备的很多信息
比如,获得显示器数量,摄像头数量等
int OBSBasic::GetCameraNum(){
obs_properties_t *props = obs_get_source_properties("dshow_input");
size_t count = 0;
if (!props)
return count;
obs_property_t *cams = obs_properties_get(props, "video_device_id");
if (cams)
count = obs_property_list_item_count(cams);
//QString name = obs_property_list_item_name(cams, 0);
//QString devicePath = obs_property_list_item_string(cams, 0);
return count;
}
int OBSBasic::GetMonitorNum(){
obs_properties_t *props = obs_get_source_properties("monitor_capture");
size_t count = 0;
if (!props)
return count;
obs_property_t *monitors = obs_properties_get(props, "monitor");
if (monitors)
count = obs_property_list_item_count(monitors);
/*QString name = obs_property_list_item_name(cams, 0);*/
return count;
}
获得源或id属性的方法
/** Returns the property list, if any. Free with obs_properties_destroy */
EXPORT obs_properties_t *obs_get_source_properties(const char *id);
/**
* Returns the properties list for a specific existing source. Free with
* obs_properties_destroy
*/
EXPORT obs_properties_t
*obs_source_properties(const obs_source_t *source);
//.....................................................................................
/** Returns the property list, if any. Free with obs_properties_destroy */
EXPORT obs_properties_t *obs_get_output_properties(const char *id);
/**
* Returns the property list of an existing output, if any. Free with
* obs_properties_destroy
*/
EXPORT obs_properties_t *obs_output_properties(const obs_output_t *output);
比如说:
获得显示器分辨率
//获得属性
obs_property_t *monitors = obs_properties_get(props, "monitor");
if (monitors)
count = obs_property_list_item_count(monitors);
assert(nMonitor < count);
//获得显示器 分辨率
QString name = obs_property_list_item_name(monitors, nMonitor); //显示器 1: 1920x1080 @ 1366,9
QRegExp rx("(\\d{2,})"); // 匹配数字 至少两个数字
int pos = 0;
int nIndex = 0;
while ((pos = rx.indexIn(name, pos)) != -1) {
if (nIndex == 0)
monitorW = rx.cap(0).toInt();
if (nIndex == 1)
monitorH = rx.cap(0).toInt();
pos += rx.matchedLength();
nIndex++;
}
比如说 获得摄像头name path
obs_properties_t *props = obs_get_source_properties(id);
size_t count = 0;
if (!props)
return;
obs_property_t *cams = obs_properties_get(props, "video_device_id");
if (cams)
count = obs_property_list_item_count(cams);
std::string name = obs_property_list_item_name(cams, 0);
////获得属性
int nDeviceCount = 0;
std::string video_device_id = obs_property_list_item_string(cams, 0);
比如,添加新视频源的时候,可以直接从属性中获得设备ID,然后传入到这个视频源的setting中, 从而直接为该视频源选择了某个摄像头设备
obs_property_t *cams = obs_properties_get(props, "video_device_id");
if (cams)
nDeviceCount = obs_property_list_item_count(cams);
if (nCam >= nDeviceCount)
return;
std::string video_device_name = obs_property_list_item_name(cams, nCam);
std::string video_device_id = obs_property_list_item_string(cams, nCam);
//更新setting 选择显示器,传递参数
obs_data_t * settings;
settings = obs_source_get_settings(sourceSelect.newSource); //获得settings
obs_data_set_string(settings, "video_device_id", video_device_id.c_str());
obs_data_set_bool(settings, "active", true);
obs_source_update(sourceSelect.newSource, settings); //更新settings
4 添加新源时,选择设备,更新设置,调整位置
1) 添加新源时,希望新源为自己指定的某个摄像头 指定的某个显示器
如果是摄像头,此时需要获得摄像头的device_id,
比如,获得设备列表中第1个摄像头的device_id
obs_properties_t *props = obs_get_source_properties(id);
int nDeviceCount = 0;
if (!props)
return;
obs_property_t *cams = obs_properties_get(props, "video_device_id");
if (cams)
nDeviceCount = obs_property_list_item_count(cams); // 获得设备数量
if (nCam >= nDeviceCount)
return;
std::string video_device_name = obs_property_list_item_name(cams, nCam); //设备名称
std::string video_device_id = obs_property_list_item_string(cams, nCam); //设备ID
2) 将设备信息传入setting ,更新新源的setting
比如摄像头源的 获取更新setting方式
//更新setting 选择显示器,传递参数
obs_data_t * settings;
settings = obs_source_get_settings(sourceSelect.newSource); //获得settings
//设置setting
obs_data_set_string(settings, "video_device_id", video_device_id.c_str());
obs_data_set_bool(settings, "active", true);
//更新setting
obs_source_update(sourceSelect.newSource, settings); //更新settings
比如显示器源的 设置更新setting方式
//更新setting 选择显示器,传递参数
obs_data_t * settings;
settings = obs_source_get_settings(sourceSelect.newSource); //获得settings
obs_data_set_int(settings, "monitor", nMonitor);
obs_data_set_int(settings, "nCursor", 111);
obs_data_set_bool(settings, "capture_cursor", false);
obs_source_update(sourceSelect.newSource, settings); //更新settings
3)更新项目位置
新添加的源,为场景的当前项,要更新项目位置,首先要获得此项
OBSSceneItem item = GetCurrentSceneItem();
if (!item)
return;
更换位置,使用变换方法
obs_sceneitem_defer_update_begin(item);
obs_transform_info info;
if (bMainScreen)
vec2_set(&info.pos, 30.0f, 30.0f);
else{
vec2_set(&info.pos, 930.0f, 30.0f);
}
vec2_set(&info.scale, 1.0f, 1.0f);
info.rot = 0.0f;
info.alignment = OBS_ALIGN_TOP | OBS_ALIGN_LEFT;
info.bounds_type = OBS_BOUNDS_SCALE_INNER;
info.bounds_alignment = OBS_ALIGN_CENTER;
if (bMainScreen)
vec2_set(&info.bounds, mainbound_w, mainbound_h);
else
vec2_set(&info.bounds, secbound_w, secbound_h);
obs_sceneitem_set_info(item, &info);
if (bFullCut)
{
obs_sceneitem_crop crop = { cropLeft, cropTop, cropRight, cropBottom };
obs_sceneitem_set_crop(item, &crop);
}
obs_sceneitem_defer_update_end(item);