static void *audio_thread(void *param) { struct audio_output *audio = param; uint64_t buffer_time = audio->info.buffer_ms * 1000000; uint64_t prev_time = os_gettime_ns() - buffer_time; uint64_t audio_time; os_set_thread_name("audio-io: audio thread"); const char *audio_thread_name = profile_store_name(obs_get_profiler_name_store(), "audio_thread(%s)", audio->info.name); while (os_event_try(audio->stop_event) == EAGAIN) { os_sleep_ms(AUDIO_WAIT_TIME); profile_start(audio_thread_name); pthread_mutex_lock(&audio->line_mutex); audio_time = os_gettime_ns() - buffer_time; audio_time = mix_and_output(audio, audio_time, prev_time); prev_time = audio_time; pthread_mutex_unlock(&audio->line_mutex); profile_end(audio_thread_name); profile_reenable_thread(); } return NULL; }
static void *video_thread(void *param) { struct video_output *video = param; os_set_thread_name("video-io: video thread"); const char *video_thread_name = profile_store_name(obs_get_profiler_name_store(), "video_thread(%s)", video->info.name); while (os_sem_wait(video->update_semaphore) == 0) { if (video->stop) break; profile_start(video_thread_name); while (!video->stop && !video_output_cur_frame(video)) { video->total_frames++; } video->total_frames++; profile_end(video_thread_name); profile_reenable_thread(); } return NULL; }
static void *audio_thread(void *param) { struct audio_output *audio = param; size_t rate = audio->info.samples_per_sec; uint64_t samples = 0; uint64_t start_time = os_gettime_ns(); uint64_t prev_time = start_time; uint64_t audio_time = prev_time; uint32_t audio_wait_time = (uint32_t)(audio_frames_to_ns(rate, AUDIO_OUTPUT_FRAMES) / 1000000); os_set_thread_name("audio-io: audio thread"); const char *audio_thread_name = profile_store_name(obs_get_profiler_name_store(), "audio_thread(%s)", audio->info.name); while (os_event_try(audio->stop_event) == EAGAIN) { uint64_t cur_time; os_sleep_ms(audio_wait_time); profile_start(audio_thread_name); cur_time = os_gettime_ns(); while (audio_time <= cur_time) { samples += AUDIO_OUTPUT_FRAMES; audio_time = start_time + audio_frames_to_ns(rate, samples); input_and_output(audio, audio_time, prev_time); prev_time = audio_time; } profile_end(audio_thread_name); profile_reenable_thread(); } return NULL; }
void *obs_video_thread(void *param) { uint64_t last_time = 0; uint64_t interval = video_output_get_frame_time(obs->video.video); obs->video.video_time = os_gettime_ns(); os_set_thread_name("libobs: graphics thread"); const char *video_thread_name = profile_store_name(obs_get_profiler_name_store(), "obs_video_thread(%g ms)", interval / 1000000.); profile_register_root(video_thread_name, interval); while (!video_output_stopped(obs->video.video)) { profile_start(video_thread_name); profile_start(tick_sources_name); last_time = tick_sources(obs->video.video_time, last_time); profile_end(tick_sources_name); profile_start(render_displays_name); render_displays(); profile_end(render_displays_name); profile_start(output_frame_name); output_frame(); profile_end(output_frame_name); profile_end(video_thread_name); profile_reenable_thread(); video_sleep(&obs->video, &obs->video.video_time, interval); } UNUSED_PARAMETER(param); return NULL; }
void *obs_hotkey_thread(void *arg) { UNUSED_PARAMETER(arg); const char *hotkey_thread_name = profile_store_name(obs_get_profiler_name_store(), "obs_hotkey_thread(%g"NBSP"ms)", 25.); profile_register_root(hotkey_thread_name, (uint64_t)25000000); while (os_event_timedwait(obs->hotkeys.stop_event, 25) == ETIMEDOUT) { if (!lock()) continue; profile_start(hotkey_thread_name); query_hotkeys(); profile_end(hotkey_thread_name); unlock(); profile_reenable_thread(); } return NULL; }
void *obs_graphics_thread(void *param) { uint64_t last_time = 0; uint64_t interval = video_output_get_frame_time(obs->video.video); uint64_t frame_time_total_ns = 0; uint64_t fps_total_ns = 0; uint32_t fps_total_frames = 0; obs->video.video_time = os_gettime_ns(); os_set_thread_name("libobs: graphics thread"); const char *video_thread_name = profile_store_name(obs_get_profiler_name_store(), "obs_graphics_thread(%g"NBSP"ms)", interval / 1000000.); profile_register_root(video_thread_name, interval); srand((unsigned int)time(NULL)); while (!video_output_stopped(obs->video.video)) { uint64_t frame_start = os_gettime_ns(); uint64_t frame_time_ns; profile_start(video_thread_name); profile_start(tick_sources_name); last_time = tick_sources(obs->video.video_time, last_time); profile_end(tick_sources_name); profile_start(render_displays_name); render_displays(); profile_end(render_displays_name); profile_start(output_frame_name); output_frame(); profile_end(output_frame_name); frame_time_ns = os_gettime_ns() - frame_start; profile_end(video_thread_name); profile_reenable_thread(); video_sleep(&obs->video, &obs->video.video_time, interval); frame_time_total_ns += frame_time_ns; fps_total_ns += (obs->video.video_time - last_time); fps_total_frames++; if (fps_total_ns >= 1000000000ULL) { obs->video.video_fps = (double)fps_total_frames / ((double)fps_total_ns / 1000000000.0); obs->video.video_avg_frame_time_ns = frame_time_total_ns / (uint64_t)fps_total_frames; frame_time_total_ns = 0; fps_total_ns = 0; fps_total_frames = 0; } } UNUSED_PARAMETER(param); return NULL; }
void *obs_graphics_thread(void *param) { uint64_t last_time = 0; uint64_t interval = video_output_get_frame_time(obs->video.video); uint64_t frame_time_total_ns = 0; uint64_t fps_total_ns = 0; uint32_t fps_total_frames = 0; bool gpu_was_active = false; bool raw_was_active = false; bool was_active = false; obs->video.video_time = os_gettime_ns(); os_set_thread_name("libobs: graphics thread"); const char *video_thread_name = profile_store_name(obs_get_profiler_name_store(), "obs_graphics_thread(%g"NBSP"ms)", interval / 1000000.); profile_register_root(video_thread_name, interval); srand((unsigned int)time(NULL)); while (!video_output_stopped(obs->video.video)) { uint64_t frame_start = os_gettime_ns(); uint64_t frame_time_ns; bool raw_active = obs->video.raw_active > 0; #ifdef _WIN32 bool gpu_active = obs->video.gpu_encoder_active > 0; #else const bool gpu_active = 0; #endif bool active = raw_active || gpu_active; if (!was_active && active) clear_base_frame_data(); if (!raw_was_active && raw_active) clear_raw_frame_data(); #ifdef _WIN32 if (!gpu_was_active && gpu_active) clear_gpu_frame_data(); #endif raw_was_active = raw_active; gpu_was_active = gpu_active; was_active = active; profile_start(video_thread_name); profile_start(tick_sources_name); last_time = tick_sources(obs->video.video_time, last_time); profile_end(tick_sources_name); profile_start(output_frame_name); output_frame(raw_active, gpu_active); profile_end(output_frame_name); profile_start(render_displays_name); render_displays(); profile_end(render_displays_name); frame_time_ns = os_gettime_ns() - frame_start; profile_end(video_thread_name); profile_reenable_thread(); video_sleep(&obs->video, raw_active, gpu_active, &obs->video.video_time, interval); frame_time_total_ns += frame_time_ns; fps_total_ns += (obs->video.video_time - last_time); fps_total_frames++; if (fps_total_ns >= 1000000000ULL) { obs->video.video_fps = (double)fps_total_frames / ((double)fps_total_ns / 1000000000.0); obs->video.video_avg_frame_time_ns = frame_time_total_ns / (uint64_t)fps_total_frames; frame_time_total_ns = 0; fps_total_ns = 0; fps_total_frames = 0; } } UNUSED_PARAMETER(param); return NULL; }