obs-scene场景添加元素item
2024-06-04
18
0
场景中的资源是通过函数AddNew实现的。具体可详见:https://www.pnpon.com/article/detail-636.html
bool AddNew(QWidget *parent, const char *id, const char *name,
const bool visible, OBSSource &newSource)
{
OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
OBSScene scene = main->GetCurrentScene();
bool success = false;
if (!scene)
return false;
OBSSourceAutoRelease source = obs_get_source_by_name(name);
if (source && parent) {
OBSMessageBox::information(parent, QTStr("NameExists.Title"),
QTStr("NameExists.Text"));
} else {
const char *v_id = obs_get_latest_input_type_id(id);
source = obs_source_create(v_id, name, NULL, nullptr);
if (source) {
//入参
AddSourceData data;
data.source = source;
data.visible = visible;
obs_enter_graphics();
//调用AddSource创建源
obs_scene_atomic_update(scene, AddSource, &data);
obs_leave_graphics();
newSource = source;
/* set monitoring if source monitors by default */
uint32_t flags = obs_source_get_output_flags(source);
if ((flags & OBS_SOURCE_MONITOR_BY_DEFAULT) != 0) {
obs_source_set_monitoring_type(
source,
OBS_MONITORING_TYPE_MONITOR_ONLY);
}
success = true;
}
}
return success;
}
AddNew中使用obs_source_create获取obs_source_t并和visible组合成结构体AddSourceData,并调用AddSource。
AddSource函数中根据类型id使用函数obs_scene_add来创建资源item
static void AddSource(void *_data, obs_scene_t *scene)
{
AddSourceData *data = (AddSourceData *)_data;
obs_sceneitem_t *sceneitem;
sceneitem = obs_scene_add(scene, data->source);
if (data->transform != nullptr)
obs_sceneitem_set_info2(sceneitem, data->transform);
if (data->crop != nullptr)
obs_sceneitem_set_crop(sceneitem, data->crop);
if (data->blend_method != nullptr)
obs_sceneitem_set_blending_method(sceneitem,
*data->blend_method);
if (data->blend_mode != nullptr)
obs_sceneitem_set_blending_mode(sceneitem, *data->blend_mode);
obs_sceneitem_set_visible(sceneitem, data->visible);
}
obs_sceneitem_t *obs_scene_add(obs_scene_t *scene, obs_source_t *source)
{
obs_sceneitem_t *item = obs_scene_add_internal(scene, source, NULL, 0);
struct calldata params;
uint8_t stack[128];
if (!item)
return NULL;
calldata_init_fixed(¶ms, stack, sizeof(stack));
calldata_set_ptr(¶ms, "scene", scene);
calldata_set_ptr(¶ms, "item", item);
signal_handler_signal(scene->source->context.signals, "item_add",
¶ms);
return item;
}
最终调用obs_scene_add_internal
static obs_sceneitem_t *obs_scene_add_internal(obs_scene_t *scene,
obs_source_t *source,
obs_sceneitem_t *insert_after,
int64_t id)
{
struct obs_scene_item *last;
struct obs_scene_item *item;
pthread_mutex_t mutex;
struct item_action action = {.visible = true,
.timestamp = os_gettime_ns()};
if (!scene)
return NULL;
//增加引用计数
source = obs_source_get_ref(source);
if (!source) {
blog(LOG_ERROR, "Tried to add a NULL source to a scene");
return NULL;
}
if (source->removed) {
blog(LOG_WARNING, "Tried to add a removed source to a scene");
goto release_source_and_fail;
}
if (pthread_mutex_init(&mutex, NULL) != 0) {
blog(LOG_WARNING, "Failed to create scene item mutex");
goto release_source_and_fail;
}
if (!obs_source_add_active_child(scene->source, source)) {
blog(LOG_WARNING, "Failed to add source to scene due to "
"infinite source recursion");
pthread_mutex_destroy(&mutex);
goto release_source_and_fail;
}
//申请obs_scene_item空间结构体
item = bzalloc(sizeof(struct obs_scene_item));
item->source = source;
item->id = id ? id : ++scene->id_counter;
item->parent = scene;
item->ref = 1;
item->align = OBS_ALIGN_TOP | OBS_ALIGN_LEFT;
item->actions_mutex = mutex;
item->user_visible = true;
item->locked = false;
item->is_group = strcmp(source->info.id, group_info.id) == 0;
item->private_settings = obs_data_create();
item->toggle_visibility = OBS_INVALID_HOTKEY_PAIR_ID;
os_atomic_set_long(&item->active_refs, 1);
vec2_set(&item->scale, 1.0f, 1.0f);
matrix4_identity(&item->draw_transform);
matrix4_identity(&item->box_transform);
if (source_has_audio(source)) {
item->visible = false;
da_push_back(item->audio_actions, &action);
} else {
item->visible = true;
}
full_lock(scene);
//加入scene的链表
if (insert_after) {
obs_sceneitem_t *next = insert_after->next;
if (next)
next->prev = item;
item->next = insert_after->next;
item->prev = insert_after;
insert_after->next = item;
} else {
last = scene->first_item;
if (!last) {
scene->first_item = item;
} else {
while (last->next)
last = last->next;
last->next = item;
item->prev = last;
}
}
full_unlock(scene);
if (!scene->source->context.private)
init_hotkeys(scene, item, obs_source_get_name(source));
signal_handler_connect(obs_source_get_signal_handler(source), "rename",
sceneitem_renamed, item);
return item;
release_source_and_fail:
obs_source_release(source);
return NULL;
}