obs_source与渲染互联
2024-06-24
10
0
使用obs_source_create_internal新创建的输入源,调用了create回调函数后,最后会调用obs_source_init_finalize函数。
static void obs_source_init_finalize(struct obs_source *source)
{
if (is_audio_source(source))
{
pthread_mutex_lock(&obs->data.audio_sources_mutex);
source->next_audio_source = obs->data.first_audio_source;
source->prev_next_audio_source = &obs->data.first_audio_source;
if (obs->data.first_audio_source)
obs->data.first_audio_source->prev_next_audio_source =&source->next_audio_source;
obs->data.first_audio_source = source;
pthread_mutex_unlock(&obs->data.audio_sources_mutex);
}
if (!source->context.private) {
obs_context_data_insert_name(&source->context,
&obs->data.sources_mutex,
&obs->data.public_sources);
}
//插入obs->data.sources中。
obs_context_data_insert_uuid(&source->context, &obs->data.sources_mutex, &obs->data.sources);
}
可以看到,这里与全局变量obs的成员data相关,即将新创建的源使用obs_context_data_insert_uuid插入链表obs->data.sources中。
struct obs_core {
...
struct obs_core_video video;
struct obs_core_audio audio;
struct obs_core_data data;
...
};
struct obs_core_data中应是一些通过模块创建的对象。
/* user sources, output channels, and displays */
struct obs_core_data {
/* Hash tables (uthash) */
struct obs_source *sources; /* Lookup by UUID (hh_uuid) */
struct obs_source *public_sources; /* Lookup by name (hh) */
/* Linked lists */
struct obs_source *first_audio_source;
struct obs_display *first_display;
struct obs_output *first_output;
struct obs_encoder *first_encoder;
struct obs_service *first_service;
pthread_mutex_t sources_mutex;
pthread_mutex_t displays_mutex;
pthread_mutex_t outputs_mutex;
pthread_mutex_t encoders_mutex;
pthread_mutex_t services_mutex;
pthread_mutex_t audio_sources_mutex;
pthread_mutex_t draw_callbacks_mutex;
DARRAY(struct draw_callback) draw_callbacks;
DARRAY(struct rendered_callback) rendered_callbacks;
DARRAY(struct tick_callback) tick_callbacks;
struct obs_view main_view;
long long unnamed_index;
obs_data_t *private_data;
volatile bool valid;
DARRAY(char *) protocols;
DARRAY(obs_source_t *) sources_to_tick;
};
在视频线程obs_graphics_thread中,循环调用obs_graphics_thread_loop。
bool obs_graphics_thread_loop(struct obs_graphics_context *context)
{
...
context->last_time = tick_sources(obs->video.video_time, context->last_time);
...
//内容输出
profile_start(output_frame_name);
output_frames();
profile_end(output_frame_name);
//render_displays是显示渲染的结果,可以有多个,与窗口HWND绑定
profile_start(render_displays_name);
render_displays();
profile_end(render_displays_name);
...
}
tick_sources中对所有增加的源进行渲染
atic uint64_t tick_sources(uint64_t cur_time, uint64_t last_time)
{
struct obs_core_data *data = &obs->data;
struct obs_source *source;
uint64_t delta_time;
float seconds;
if (!last_time)
last_time = cur_time - obs->video.video_frame_interval_ns;
//delta_time实际上就是obs->video.video_frame_interval_ns帧率的时间间隔
delta_time = cur_time - last_time;
//将它转成秒级
seconds = (float)((double)delta_time / 1000000000.0);
/* ------------------------------------- */
/* call tick callbacks */
pthread_mutex_lock(&data->draw_callbacks_mutex);
for (size_t i = data->tick_callbacks.num; i > 0; i--)
{
struct tick_callback *callback = data->tick_callbacks.array + (i - 1);
callback->tick(callback->param, seconds);
}
pthread_mutex_unlock(&data->draw_callbacks_mutex);
/* ------------------------------------- */
/* get an array of all sources to tick */
da_clear(data->sources_to_tick);
pthread_mutex_lock(&data->sources_mutex);
//对加入的源于进行引数计数,后面调用obs_source_video_tick渲染。
source = data->sources;
while (source)
{
//增加引用计数
obs_source_t *s = obs_source_get_ref(source);
if (s)
{
da_push_back(data->sources_to_tick, &s);
}
source = (struct obs_source *)source->context.hh_uuid.next;
}
pthread_mutex_unlock(&data->sources_mutex);
/* ------------------------------------- */
/* call the tick function of each source */
for (size_t i = 0; i < data->sources_to_tick.num; i++)
{
obs_source_t *s = data->sources_to_tick.array[i];
//秒级调用???
obs_source_video_tick(s, seconds);
//减少引用计数,如果为0销毁,模块了COM的接引用
obs_source_release(s);
}
return cur_time;
}
最终调用obs_source_video_tick进行渲染。
obs_source_video_tick其实应只是针对的是采样数据用的,采格到的数据放在source->context.data中,数据读取到后进行渲染。