static int obs_init_graphics(struct obs_video_info *ovi) { struct obs_core_video *video = &obs->video; struct gs_init_data graphics_data; bool success = true; int errorcode; make_gs_init_data(&graphics_data, ovi); errorcode = gs_create(&video->graphics, ovi->graphics_module, &graphics_data); if (errorcode != GS_SUCCESS) { switch (errorcode) { case GS_ERROR_MODULE_NOT_FOUND: return OBS_VIDEO_MODULE_NOT_FOUND; case GS_ERROR_NOT_SUPPORTED: return OBS_VIDEO_NOT_SUPPORTED; default: return OBS_VIDEO_FAIL; } } gs_enter_context(video->graphics); char *filename = find_libobs_data_file("default.effect"); video->default_effect = gs_effect_create_from_file(filename, NULL); bfree(filename); if (gs_get_device_type() == GS_DEVICE_OPENGL) { filename = find_libobs_data_file("default_rect.effect"); video->default_rect_effect = gs_effect_create_from_file( filename, NULL); bfree(filename); } filename = find_libobs_data_file("solid.effect"); video->solid_effect = gs_effect_create_from_file(filename, NULL); bfree(filename); filename = find_libobs_data_file("format_conversion.effect"); video->conversion_effect = gs_effect_create_from_file(filename, NULL); bfree(filename); if (!video->default_effect) success = false; if (gs_get_device_type() == GS_DEVICE_OPENGL) { if (!video->default_rect_effect) success = false; } if (!video->solid_effect) success = false; if (!video->conversion_effect) success = false; gs_leave_context(); return success ? OBS_VIDEO_SUCCESS : OBS_VIDEO_FAIL; }
static inline void render_displays(void) { struct obs_display *display; if (!obs->data.valid) return; gs_enter_context(obs->video.graphics); /* render extra displays/swaps */ pthread_mutex_lock(&obs->data.displays_mutex); display = obs->data.first_display; while (display) { render_display(display); display = display->next; } pthread_mutex_unlock(&obs->data.displays_mutex); /* render main display */ render_display(&obs->video.main_display); gs_leave_context(); }
static inline void output_frame(uint64_t *cur_time, uint64_t interval) { struct obs_core_video *video = &obs->video; int cur_texture = video->cur_texture; int prev_texture = cur_texture == 0 ? NUM_TEXTURES-1 : cur_texture-1; struct video_data frame; bool frame_ready; memset(&frame, 0, sizeof(struct video_data)); gs_enter_context(video->graphics); render_video(video, cur_texture, prev_texture); frame_ready = download_frame(video, prev_texture, &frame); gs_flush(); gs_leave_context(); if (frame_ready) { struct obs_vframe_info vframe_info; circlebuf_pop_front(&video->vframe_info_buffer, &vframe_info, sizeof(vframe_info)); frame.timestamp = vframe_info.timestamp; output_video_data(video, &frame, vframe_info.count); } if (++video->cur_texture == NUM_TEXTURES) video->cur_texture = 0; video_sleep(video, cur_time, interval); }
void obs_transition_free(obs_source_t *transition) { pthread_mutex_destroy(&transition->transition_mutex); pthread_mutex_destroy(&transition->transition_tex_mutex); gs_enter_context(obs->video.graphics); gs_texrender_destroy(transition->transition_texrender[0]); gs_texrender_destroy(transition->transition_texrender[1]); gs_leave_context(); }
static int obs_init_video(struct obs_video_info *ovi) { struct obs_core_video *video = &obs->video; struct video_output_info vi; int errorcode; make_video_info(&vi, ovi); video->base_width = ovi->base_width; video->base_height = ovi->base_height; video->output_width = ovi->output_width; video->output_height = ovi->output_height; video->gpu_conversion = ovi->gpu_conversion; errorcode = video_output_open(&video->video, &vi); if (errorcode != VIDEO_OUTPUT_SUCCESS) { if (errorcode == VIDEO_OUTPUT_INVALIDPARAM) { blog(LOG_ERROR, "Invalid video parameters specified"); return OBS_VIDEO_INVALID_PARAM; } else { blog(LOG_ERROR, "Could not open video output"); } return OBS_VIDEO_FAIL; } if (!obs_display_init(&video->main_display, NULL)) return OBS_VIDEO_FAIL; video->main_display.cx = ovi->window_width; video->main_display.cy = ovi->window_height; gs_enter_context(video->graphics); if (ovi->gpu_conversion && !obs_init_gpu_conversion(ovi)) return OBS_VIDEO_FAIL; if (!obs_init_textures(ovi)) return OBS_VIDEO_FAIL; gs_leave_context(); errorcode = pthread_create(&video->video_thread, NULL, obs_video_thread, obs); if (errorcode != 0) return OBS_VIDEO_FAIL; video->thread_initialized = true; return OBS_VIDEO_SUCCESS; }
static inline void output_frame(bool raw_active, const bool gpu_active) { struct obs_core_video *video = &obs->video; int cur_texture = video->cur_texture; int prev_texture = cur_texture == 0 ? NUM_TEXTURES-1 : cur_texture-1; struct video_data frame; bool active = raw_active || gpu_active; bool frame_ready; memset(&frame, 0, sizeof(struct video_data)); profile_start(output_frame_gs_context_name); gs_enter_context(video->graphics); profile_start(output_frame_render_video_name); render_video(video, raw_active, gpu_active, cur_texture, prev_texture); profile_end(output_frame_render_video_name); if (raw_active) { profile_start(output_frame_download_frame_name); frame_ready = download_frame(video, prev_texture, &frame); profile_end(output_frame_download_frame_name); } profile_start(output_frame_gs_flush_name); gs_flush(); profile_end(output_frame_gs_flush_name); gs_leave_context(); profile_end(output_frame_gs_context_name); if (raw_active && frame_ready) { struct obs_vframe_info vframe_info; circlebuf_pop_front(&video->vframe_info_buffer, &vframe_info, sizeof(vframe_info)); frame.timestamp = vframe_info.timestamp; profile_start(output_frame_output_video_data_name); output_video_data(video, &frame, vframe_info.count); profile_end(output_frame_output_video_data_name); } if (++video->cur_texture == NUM_TEXTURES) video->cur_texture = 0; }
static void obs_free_graphics(void) { struct obs_core_video *video = &obs->video; if (video->graphics) { gs_enter_context(video->graphics); gs_effect_destroy(video->default_effect); gs_effect_destroy(video->default_rect_effect); gs_effect_destroy(video->solid_effect); gs_effect_destroy(video->conversion_effect); video->default_effect = NULL; gs_leave_context(); gs_destroy(video->graphics); video->graphics = NULL; } }
static void obs_free_video(void) { struct obs_core_video *video = &obs->video; if (video->video) { obs_display_free(&video->main_display); video_output_close(video->video); video->video = NULL; if (!video->graphics) return; gs_enter_context(video->graphics); if (video->mapped_surface) { gs_stagesurface_unmap(video->mapped_surface); video->mapped_surface = NULL; } for (size_t i = 0; i < NUM_TEXTURES; i++) { gs_stagesurface_destroy(video->copy_surfaces[i]); gs_texture_destroy(video->render_textures[i]); gs_texture_destroy(video->convert_textures[i]); gs_texture_destroy(video->output_textures[i]); obs_source_frame_free(&video->convert_frames[i]); video->copy_surfaces[i] = NULL; video->render_textures[i] = NULL; video->convert_textures[i] = NULL; video->output_textures[i] = NULL; } gs_leave_context(); circlebuf_free(&video->timestamp_buffer); video->cur_texture = 0; } }
obs_display_t *obs_display_create(const struct gs_init_data *graphics_data) { struct obs_display *display = bzalloc(sizeof(struct obs_display)); gs_enter_context(obs->video.graphics); if (!obs_display_init(display, graphics_data)) { obs_display_destroy(display); display = NULL; } else { pthread_mutex_lock(&obs->data.displays_mutex); display->prev_next = &obs->data.first_display; display->next = obs->data.first_display; obs->data.first_display = display; if (display->next) display->next->prev_next = &display->next; pthread_mutex_unlock(&obs->data.displays_mutex); } gs_leave_context(); return display; }
void obs_leave_graphics(void) { if (obs && obs->video.graphics) gs_leave_context(); }