obs-scene场景
2024-06-04
34
0
scene
OBS至少需要一个场景。
每个scene使用结构体obs_scene来表示:
struct obs_scene {
struct obs_source *source;
bool is_group;
bool custom_size;
uint32_t cx;
uint32_t cy;
int64_t id_counter;
pthread_mutex_t video_mutex;
pthread_mutex_t audio_mutex;
struct obs_scene_item *first_item;
};
obs_scene对象其实和color_source属性同性质类的。其都是对通用obs_source_t的封装。obs扬景中的所有子对象加由链表first_item相连。
每个obs_scene下可以有多个obs_scene_item,这些item可以是group,也可以是视频,图片,文字等。
struct obs_scene_item {
volatile long ref;
volatile bool removed;
bool is_group;
bool update_transform;
bool update_group_resize;
int64_t id;
struct obs_scene *parent;
struct obs_source *source;
volatile long active_refs;
volatile long defer_update;
volatile long defer_group_resize;
bool user_visible;
bool visible;
bool selected;
bool locked;
gs_texrender_t *item_render;
struct obs_sceneitem_crop crop;
struct vec2 pos;
struct vec2 scale;
float rot;
uint32_t align;
/* last width/height of the source, this is used to check whether
* the transform needs updating */
uint32_t last_width;
uint32_t last_height;
struct vec2 output_scale;
enum obs_scale_type scale_filter;
enum obs_blending_method blend_method;
enum obs_blending_type blend_type;
struct matrix4 box_transform;
struct vec2 box_scale;
struct matrix4 draw_transform;
enum obs_bounds_type bounds_type;
uint32_t bounds_align;
struct vec2 bounds;
bool crop_to_bounds;
struct obs_sceneitem_crop bounds_crop;
obs_hotkey_pair_id toggle_visibility;
obs_data_t *private_settings;
pthread_mutex_t actions_mutex;
DARRAY(struct item_action) audio_actions;
struct obs_source *show_transition;
struct obs_source *hide_transition;
uint32_t show_transition_duration;
uint32_t hide_transition_duration;
/* would do **prev_next, but not really great for reordering */
struct obs_scene_item *prev;
struct obs_scene_item *next;
};
关于obs-scener的关回函数如下:
const struct obs_source_info scene_info = {
.id = "scene",
.type = OBS_SOURCE_TYPE_SCENE,
.output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_CUSTOM_DRAW |
OBS_SOURCE_COMPOSITE | OBS_SOURCE_DO_NOT_DUPLICATE |
OBS_SOURCE_SRGB,
.get_name = scene_getname,
.create = scene_create,
.destroy = scene_destroy,
.video_tick = scene_video_tick,
.video_render = scene_video_render,//图像渲染
.audio_render = scene_audio_render,
.get_width = scene_getwidth,
.get_height = scene_getheight,
.load = scene_load,
.save = scene_save,
.enum_active_sources = scene_enum_active_sources,
.enum_all_sources = scene_enum_all_sources,
.video_get_color_space = scene_video_get_color_space,
};
obs-scene场景创建
默认的第一个场景是在void OBSBasic::OBSInit()函数中使用OBSBasic::Load(savePath),然后调用CreateDefaultScene(true)来实现的。
void OBSBasic::CreateDefaultScene(bool firstStart)
{
disableSaving++;
ClearSceneData();
InitDefaultTransitions();
CreateDefaultQuickTransitions();
ui->transitionDuration->setValue(300);
SetTransition(fadeTransition);
//创建默认的第一个场景
OBSSceneAutoRelease scene = obs_scene_create(Str("Basic.Scene"));
//将其设置为第一个场景
if (firstStart)
CreateFirstRunSources();
//当设置为当前扬景
SetCurrentScene(scene, true);
disableSaving--;
}
在OBS中,使用一个公共的结构体obs_source来描述所有的源信息。其结构体的成员context.data用来指向具体的那种源结构体。具体可见:create_private_id函数
obs_scene_t *obs_scene_create(const char *name)
{
return create_id("scene", name);
}
static inline obs_scene_t *create_private_id(const char *id, const char *name)
{
struct obs_source *source = obs_source_create_private(id, name, NULL);
return source->context.data;
}
obs_source_create调用obs_source_create_internal:
obs_source_t *obs_source_create(const char *id, const char *name,
obs_data_t *settings, obs_data_t *hotkey_data)
{
return obs_source_create_internal(id, name, NULL, settings, hotkey_data,
false, LIBOBS_API_VER);
}
最终创建场景
static obs_source_t *
obs_source_create_internal(const char *id, const char *name, const char *uuid,
obs_data_t *settings, obs_data_t *hotkey_data,
bool private, uint32_t last_obs_ver)
{
//创建源通用结构体
struct obs_source *source = bzalloc(sizeof(struct obs_source));
//根据ID中找到const struct obs_source_info scene_info回调函数集
const struct obs_source_info *info = get_source_info(id);
if (!info) {
blog(LOG_ERROR, "Source ID '%s' not found", id);
source->info.id = bstrdup(id);
source->owns_info_id = true;
source->info.unversioned_id = bstrdup(source->info.id);
} else {
source->info = *info;
/* Always mark filters as private so they aren't found by
* source enum/search functions.
*
* XXX: Fix design flaws with filters */
if (info->type == OBS_SOURCE_TYPE_FILTER)
private = true;
}
source->mute_unmute_key = OBS_INVALID_HOTKEY_PAIR_ID;
source->push_to_mute_key = OBS_INVALID_HOTKEY_ID;
source->push_to_talk_key = OBS_INVALID_HOTKEY_ID;
source->last_obs_ver = last_obs_ver;
//加入全局obs结构体data.first_audio_source的链表。
if (!obs_source_init_context(source, settings, name, uuid, hotkey_data,private))
goto fail;
if (info) {
if (info->get_defaults) {
info->get_defaults(source->context.settings);
}
if (info->get_defaults2) {
info->get_defaults2(info->type_data,
source->context.settings);
}
}
if (!obs_source_init(source))
goto fail;
if (!private)
obs_source_init_audio_hotkeys(source);
/* allow the source to be created even if creation fails so that the
* user's data doesn't become lost */
//调用回调函数create即scene_create创建特定源的上下文信息
if (info && info->create)
source->context.data = info->create(source->context.settings, source);
if ((!info || info->create) && !source->context.data)
blog(LOG_ERROR, "Failed to create source '%s'!", name);
blog(LOG_DEBUG, "%ssource '%s' (%s) created", private ? "private " : "",
name, id);
source->flags = source->default_flags;
source->enabled = true;
obs_source_init_finalize(source);
if (!private) {
obs_source_dosignal(source, "source_create", NULL);
}
return source;
fail:
blog(LOG_ERROR, "obs_source_create failed");
obs_source_destroy(source);
return NULL;
}