0
0
mirror of https://github.com/obsproject/obs-studio.git synced 2024-09-20 04:42:18 +02:00

libobs: Format changes for multiple video mixes

This commit is contained in:
Chip Bradford 2022-06-15 10:07:50 -07:00
parent 7e39ee291c
commit 0a87797a21
3 changed files with 131 additions and 132 deletions

View File

@ -150,7 +150,8 @@ static void *gpu_encode_thread(struct obs_core_video_mix *video)
bool init_gpu_encoding(struct obs_core_video_mix *video) bool init_gpu_encoding(struct obs_core_video_mix *video)
{ {
#ifdef _WIN32 #ifdef _WIN32
const struct video_output_info *info = video_output_get_info(video->video); const struct video_output_info *info =
video_output_get_info(video->video);
video->gpu_encode_stop = false; video->gpu_encode_stop = false;
@ -160,15 +161,13 @@ bool init_gpu_encoding(struct obs_core_video_mix *video)
gs_texture_t *tex_uv; gs_texture_t *tex_uv;
if (info->format == VIDEO_FORMAT_P010) { if (info->format == VIDEO_FORMAT_P010) {
gs_texture_create_p010(&tex, &tex_uv, info->width, gs_texture_create_p010(
info->height, &tex, &tex_uv, info->width, info->height,
GS_RENDER_TARGET | GS_RENDER_TARGET | GS_SHARED_KM_TEX);
GS_SHARED_KM_TEX);
} else { } else {
gs_texture_create_nv12(&tex, &tex_uv, info->width, gs_texture_create_nv12(
info->height, &tex, &tex_uv, info->width, info->height,
GS_RENDER_TARGET | GS_RENDER_TARGET | GS_SHARED_KM_TEX);
GS_SHARED_KM_TEX);
} }
if (!tex) { if (!tex) {
return false; return false;

View File

@ -37,8 +37,7 @@ static uint64_t tick_sources(uint64_t cur_time, uint64_t last_time)
float seconds; float seconds;
if (!last_time) if (!last_time)
last_time = cur_time - last_time = cur_time - obs->video.video_frame_interval_ns;
obs->video.video_frame_interval_ns;
delta_time = cur_time - last_time; delta_time = cur_time - last_time;
seconds = (float)((double)delta_time / 1000000000.0); seconds = (float)((double)delta_time / 1000000000.0);
@ -148,8 +147,7 @@ static inline void render_main_texture(struct obs_core_video_mix *video)
struct draw_callback *callback; struct draw_callback *callback;
callback = obs->data.draw_callbacks.array + (i - 1); callback = obs->data.draw_callbacks.array + (i - 1);
callback->draw(callback->param, base_width, callback->draw(callback->param, base_width, base_height);
base_height);
} }
pthread_mutex_unlock(&obs->data.draw_callbacks_mutex); pthread_mutex_unlock(&obs->data.draw_callbacks_mutex);
@ -166,7 +164,8 @@ static inline gs_effect_t *
get_scale_effect_internal(struct obs_core_video_mix *mix) get_scale_effect_internal(struct obs_core_video_mix *mix)
{ {
struct obs_core_video *video = &obs->video; struct obs_core_video *video = &obs->video;
const struct video_output_info *info = video_output_get_info(mix->video); const struct video_output_info *info =
video_output_get_info(mix->video);
/* if the dimension is under half the size of the original image, /* if the dimension is under half the size of the original image,
* bicubic/lanczos can't sample enough pixels to create an accurate * bicubic/lanczos can't sample enough pixels to create an accurate
@ -219,7 +218,8 @@ static inline gs_effect_t *get_scale_effect(struct obs_core_video_mix *mix,
} }
static const char *render_output_texture_name = "render_output_texture"; static const char *render_output_texture_name = "render_output_texture";
static inline gs_texture_t *render_output_texture(struct obs_core_video_mix *mix) static inline gs_texture_t *
render_output_texture(struct obs_core_video_mix *mix)
{ {
struct obs_core_video *video = &obs->video; struct obs_core_video *video = &obs->video;
gs_texture_t *texture = mix->render_texture; gs_texture_t *texture = mix->render_texture;
@ -427,7 +427,8 @@ stage_output_texture(struct obs_core_video_mix *video, int cur_texture,
} }
#ifdef _WIN32 #ifdef _WIN32
static inline bool queue_frame(struct obs_core_video_mix *video, bool raw_active, static inline bool queue_frame(struct obs_core_video_mix *video,
bool raw_active,
struct obs_vframe_info *vframe_info) struct obs_vframe_info *vframe_info)
{ {
bool duplicate = bool duplicate =
@ -497,7 +498,8 @@ static inline void encode_gpu(struct obs_core_video_mix *video, bool raw_active,
} }
static const char *output_gpu_encoders_name = "output_gpu_encoders"; static const char *output_gpu_encoders_name = "output_gpu_encoders";
static void output_gpu_encoders(struct obs_core_video_mix *video, bool raw_active) static void output_gpu_encoders(struct obs_core_video_mix *video,
bool raw_active)
{ {
profile_start(output_gpu_encoders_name); profile_start(output_gpu_encoders_name);
@ -519,8 +521,9 @@ end:
} }
#endif #endif
static inline void render_video(struct obs_core_video_mix *video, bool raw_active, static inline void render_video(struct obs_core_video_mix *video,
const bool gpu_active, int cur_texture) bool raw_active, const bool gpu_active,
int cur_texture)
{ {
gs_begin_scene(); gs_begin_scene();
@ -795,8 +798,7 @@ static inline void output_video_data(struct obs_core_video_mix *video,
} }
} }
static inline void video_sleep(struct obs_core_video *video, static inline void video_sleep(struct obs_core_video *video, uint64_t *p_time,
uint64_t *p_time,
uint64_t interval_ns) uint64_t interval_ns)
{ {
struct obs_vframe_info vframe_info; struct obs_vframe_info vframe_info;
@ -830,12 +832,12 @@ static inline void video_sleep(struct obs_core_video *video,
bool raw_active = video->raw_was_active; bool raw_active = video->raw_was_active;
bool gpu_active = video->gpu_was_active; bool gpu_active = video->gpu_was_active;
if (raw_active) if (raw_active)
circlebuf_push_back(&video->vframe_info_buffer, &vframe_info, circlebuf_push_back(&video->vframe_info_buffer,
sizeof(vframe_info)); &vframe_info, sizeof(vframe_info));
if (gpu_active) if (gpu_active)
circlebuf_push_back(&video->vframe_info_buffer_gpu, circlebuf_push_back(&video->vframe_info_buffer_gpu,
&vframe_info, sizeof(vframe_info)); &vframe_info, sizeof(vframe_info));
} }
pthread_mutex_unlock(&obs->video.mixes_mutex); pthread_mutex_unlock(&obs->video.mixes_mutex);
} }
@ -1132,8 +1134,7 @@ bool obs_graphics_thread_loop(struct obs_graphics_context *context)
profile_reenable_thread(); profile_reenable_thread();
video_sleep(&obs->video, &obs->video.video_time, video_sleep(&obs->video, &obs->video.video_time, context->interval);
context->interval);
context->frame_time_total_ns += frame_time_ns; context->frame_time_total_ns += frame_time_ns;
context->fps_total_ns += (obs->video.video_time - context->last_time); context->fps_total_ns += (obs->video.video_time - context->last_time);

View File

@ -46,7 +46,8 @@ static inline void make_video_info(struct video_output_info *vi,
static inline void calc_gpu_conversion_sizes(struct obs_core_video_mix *video) static inline void calc_gpu_conversion_sizes(struct obs_core_video_mix *video)
{ {
const struct video_output_info *info = video_output_get_info(video->video); const struct video_output_info *info =
video_output_get_info(video->video);
video->conversion_needed = false; video->conversion_needed = false;
video->conversion_techs[0] = NULL; video->conversion_techs[0] = NULL;
@ -117,12 +118,10 @@ static bool obs_init_gpu_conversion(struct obs_core_video_mix *video)
calc_gpu_conversion_sizes(video); calc_gpu_conversion_sizes(video);
video->using_nv12_tex = info->format == VIDEO_FORMAT_NV12 video->using_nv12_tex =
? gs_nv12_available() info->format == VIDEO_FORMAT_NV12 ? gs_nv12_available() : false;
: false; video->using_p010_tex =
video->using_p010_tex = info->format == VIDEO_FORMAT_P010 info->format == VIDEO_FORMAT_P010 ? gs_p010_available() : false;
? gs_p010_available()
: false;
if (!video->conversion_needed) { if (!video->conversion_needed) {
blog(LOG_INFO, "GPU conversion not available for format: %u", blog(LOG_INFO, "GPU conversion not available for format: %u",
@ -152,19 +151,19 @@ static bool obs_init_gpu_conversion(struct obs_core_video_mix *video)
video->convert_textures_encode[1] = NULL; video->convert_textures_encode[1] = NULL;
video->convert_textures_encode[2] = NULL; video->convert_textures_encode[2] = NULL;
if (video->using_nv12_tex) { if (video->using_nv12_tex) {
if (!gs_texture_create_nv12( if (!gs_texture_create_nv12(&video->convert_textures_encode[0],
&video->convert_textures_encode[0], &video->convert_textures_encode[1],
&video->convert_textures_encode[1], info->width, info->height,
info->width, info->height, GS_RENDER_TARGET |
GS_RENDER_TARGET | GS_SHARED_KM_TEX)) { GS_SHARED_KM_TEX)) {
return false; return false;
} }
} else if (video->using_p010_tex) { } else if (video->using_p010_tex) {
if (!gs_texture_create_p010( if (!gs_texture_create_p010(&video->convert_textures_encode[0],
&video->convert_textures_encode[0], &video->convert_textures_encode[1],
&video->convert_textures_encode[1], info->width, info->height,
info->width, info->height, GS_RENDER_TARGET |
GS_RENDER_TARGET | GS_SHARED_KM_TEX)) { GS_SHARED_KM_TEX)) {
return false; return false;
} }
} }
@ -175,63 +174,63 @@ static bool obs_init_gpu_conversion(struct obs_core_video_mix *video)
switch (info->format) { switch (info->format) {
case VIDEO_FORMAT_I420: case VIDEO_FORMAT_I420:
video->convert_textures[0] = video->convert_textures[0] =
gs_texture_create(info->width, info->height, gs_texture_create(info->width, info->height, GS_R8, 1,
NULL, GS_RENDER_TARGET);
video->convert_textures[1] =
gs_texture_create(info->width / 2, info->height / 2,
GS_R8, 1, NULL, GS_RENDER_TARGET);
video->convert_textures[2] =
gs_texture_create(info->width / 2, info->height / 2,
GS_R8, 1, NULL, GS_RENDER_TARGET); GS_R8, 1, NULL, GS_RENDER_TARGET);
video->convert_textures[1] = gs_texture_create(
info->width / 2, info->height / 2, GS_R8, 1,
NULL, GS_RENDER_TARGET);
video->convert_textures[2] = gs_texture_create(
info->width / 2, info->height / 2, GS_R8, 1,
NULL, GS_RENDER_TARGET);
if (!video->convert_textures[0] || if (!video->convert_textures[0] ||
!video->convert_textures[1] || !video->convert_textures[2]) !video->convert_textures[1] || !video->convert_textures[2])
success = false; success = false;
break; break;
case VIDEO_FORMAT_NV12: case VIDEO_FORMAT_NV12:
video->convert_textures[0] = video->convert_textures[0] =
gs_texture_create(info->width, info->height, gs_texture_create(info->width, info->height, GS_R8, 1,
GS_R8, 1, NULL, GS_RENDER_TARGET); NULL, GS_RENDER_TARGET);
video->convert_textures[1] = gs_texture_create( video->convert_textures[1] =
info->width / 2, info->height / 2, GS_R8G8, gs_texture_create(info->width / 2, info->height / 2,
1, NULL, GS_RENDER_TARGET); GS_R8G8, 1, NULL, GS_RENDER_TARGET);
if (!video->convert_textures[0] || !video->convert_textures[1]) if (!video->convert_textures[0] || !video->convert_textures[1])
success = false; success = false;
break; break;
case VIDEO_FORMAT_I444: case VIDEO_FORMAT_I444:
video->convert_textures[0] = video->convert_textures[0] =
gs_texture_create(info->width, info->height, gs_texture_create(info->width, info->height, GS_R8, 1,
GS_R8, 1, NULL, GS_RENDER_TARGET); NULL, GS_RENDER_TARGET);
video->convert_textures[1] = video->convert_textures[1] =
gs_texture_create(info->width, info->height, gs_texture_create(info->width, info->height, GS_R8, 1,
GS_R8, 1, NULL, GS_RENDER_TARGET); NULL, GS_RENDER_TARGET);
video->convert_textures[2] = video->convert_textures[2] =
gs_texture_create(info->width, info->height, gs_texture_create(info->width, info->height, GS_R8, 1,
GS_R8, 1, NULL, GS_RENDER_TARGET); NULL, GS_RENDER_TARGET);
if (!video->convert_textures[0] || if (!video->convert_textures[0] ||
!video->convert_textures[1] || !video->convert_textures[2]) !video->convert_textures[1] || !video->convert_textures[2])
success = false; success = false;
break; break;
case VIDEO_FORMAT_I010: case VIDEO_FORMAT_I010:
video->convert_textures[0] = video->convert_textures[0] =
gs_texture_create(info->width, info->height, gs_texture_create(info->width, info->height, GS_R16, 1,
NULL, GS_RENDER_TARGET);
video->convert_textures[1] =
gs_texture_create(info->width / 2, info->height / 2,
GS_R16, 1, NULL, GS_RENDER_TARGET);
video->convert_textures[2] =
gs_texture_create(info->width / 2, info->height / 2,
GS_R16, 1, NULL, GS_RENDER_TARGET); GS_R16, 1, NULL, GS_RENDER_TARGET);
video->convert_textures[1] = gs_texture_create(
info->width / 2, info->height / 2, GS_R16,
1, NULL, GS_RENDER_TARGET);
video->convert_textures[2] = gs_texture_create(
info->width / 2, info->height / 2, GS_R16,
1, NULL, GS_RENDER_TARGET);
if (!video->convert_textures[0] || if (!video->convert_textures[0] ||
!video->convert_textures[1] || !video->convert_textures[2]) !video->convert_textures[1] || !video->convert_textures[2])
success = false; success = false;
break; break;
case VIDEO_FORMAT_P010: case VIDEO_FORMAT_P010:
video->convert_textures[0] = video->convert_textures[0] =
gs_texture_create(info->width, info->height, gs_texture_create(info->width, info->height, GS_R16, 1,
GS_R16, 1, NULL, GS_RENDER_TARGET); NULL, GS_RENDER_TARGET);
video->convert_textures[1] = gs_texture_create( video->convert_textures[1] =
info->width / 2, info->height / 2, GS_RG16, gs_texture_create(info->width / 2, info->height / 2,
1, NULL, GS_RENDER_TARGET); GS_RG16, 1, NULL, GS_RENDER_TARGET);
if (!video->convert_textures[0] || !video->convert_textures[1]) if (!video->convert_textures[0] || !video->convert_textures[1])
success = false; success = false;
break; break;
@ -256,7 +255,8 @@ static bool obs_init_gpu_conversion(struct obs_core_video_mix *video)
return success; return success;
} }
static bool obs_init_gpu_copy_surfaces(struct obs_core_video_mix *video, size_t i) static bool obs_init_gpu_copy_surfaces(struct obs_core_video_mix *video,
size_t i)
{ {
const struct video_output_info *info = const struct video_output_info *info =
video_output_get_info(video->video); video_output_get_info(video->video);
@ -332,7 +332,8 @@ static bool obs_init_gpu_copy_surfaces(struct obs_core_video_mix *video, size_t
static bool obs_init_textures(struct obs_core_video_mix *video) static bool obs_init_textures(struct obs_core_video_mix *video)
{ {
const struct video_output_info *info = video_output_get_info(video->video); const struct video_output_info *info =
video_output_get_info(video->video);
bool success = true; bool success = true;
@ -396,15 +397,14 @@ static bool obs_init_textures(struct obs_core_video_mix *video)
} }
} }
video->render_texture = gs_texture_create(obs->video.base_width, video->render_texture =
obs->video.base_height, format, 1, gs_texture_create(obs->video.base_width, obs->video.base_height,
NULL, GS_RENDER_TARGET); format, 1, NULL, GS_RENDER_TARGET);
if (!video->render_texture) if (!video->render_texture)
success = false; success = false;
video->output_texture = gs_texture_create(info->width, video->output_texture = gs_texture_create(
info->height, format, 1, info->width, info->height, format, 1, NULL, GS_RENDER_TARGET);
NULL, GS_RENDER_TARGET);
if (!video->output_texture) if (!video->output_texture)
success = false; success = false;
@ -625,8 +625,10 @@ static int obs_init_video(struct obs_video_info *ovi)
struct obs_core_video *video = &obs->video; struct obs_core_video *video = &obs->video;
video->base_width = ovi->base_width; video->base_width = ovi->base_width;
video->base_height = ovi->base_height; video->base_height = ovi->base_height;
video->video_frame_interval_ns = util_mul_div64(1000000000ULL, ovi->fps_den, ovi->fps_num); video->video_frame_interval_ns =
video->video_half_frame_interval_ns = util_mul_div64(500000000ULL, ovi->fps_den, ovi->fps_num); util_mul_div64(1000000000ULL, ovi->fps_den, ovi->fps_num);
video->video_half_frame_interval_ns =
util_mul_div64(500000000ULL, ovi->fps_den, ovi->fps_num);
if (pthread_mutex_init(&video->task_mutex, NULL) < 0) if (pthread_mutex_init(&video->task_mutex, NULL) < 0)
return OBS_VIDEO_FAIL; return OBS_VIDEO_FAIL;
@ -663,67 +665,64 @@ static void stop_video(void)
struct obs_core_video *video = &obs->video; struct obs_core_video *video = &obs->video;
void *thread_retval; void *thread_retval;
if (video->thread_initialized) { if (video->thread_initialized) {
pthread_join(video->video_thread, &thread_retval); pthread_join(video->video_thread, &thread_retval);
video->thread_initialized = false; video->thread_initialized = false;
} }
} }
static void obs_free_render_textures(struct obs_core_video_mix *video) static void obs_free_render_textures(struct obs_core_video_mix *video)
{ {
if (!obs->video.graphics) if (!obs->video.graphics)
return; return;
gs_enter_context(obs->video.graphics); gs_enter_context(obs->video.graphics);
for (size_t c = 0; c < NUM_CHANNELS; c++) { for (size_t c = 0; c < NUM_CHANNELS; c++) {
if (video->mapped_surfaces[c]) { if (video->mapped_surfaces[c]) {
gs_stagesurface_unmap( gs_stagesurface_unmap(video->mapped_surfaces[c]);
video->mapped_surfaces[c]); video->mapped_surfaces[c] = NULL;
video->mapped_surfaces[c] = NULL;
}
} }
}
for (size_t i = 0; i < NUM_TEXTURES; i++) { for (size_t i = 0; i < NUM_TEXTURES; i++) {
for (size_t c = 0; c < NUM_CHANNELS; c++) { for (size_t c = 0; c < NUM_CHANNELS; c++) {
if (video->copy_surfaces[i][c]) { if (video->copy_surfaces[i][c]) {
gs_stagesurface_destroy(
video->copy_surfaces[i][c]);
video->copy_surfaces[i][c] = NULL;
}
video->active_copy_surfaces[i][c] = NULL;
}
#ifdef _WIN32
if (video->copy_surfaces_encode[i]) {
gs_stagesurface_destroy( gs_stagesurface_destroy(
video->copy_surfaces_encode[i]); video->copy_surfaces[i][c]);
video->copy_surfaces_encode[i] = NULL; video->copy_surfaces[i][c] = NULL;
} }
#endif
video->active_copy_surfaces[i][c] = NULL;
} }
gs_texture_destroy(video->render_texture);
for (size_t c = 0; c < NUM_CHANNELS; c++) {
if (video->convert_textures[c]) {
gs_texture_destroy(video->convert_textures[c]);
video->convert_textures[c] = NULL;
}
#ifdef _WIN32 #ifdef _WIN32
if (video->convert_textures_encode[c]) { if (video->copy_surfaces_encode[i]) {
gs_texture_destroy( gs_stagesurface_destroy(video->copy_surfaces_encode[i]);
video->convert_textures_encode[c]); video->copy_surfaces_encode[i] = NULL;
video->convert_textures_encode[c] = NULL;
}
#endif
} }
#endif
}
gs_texture_destroy(video->output_texture); gs_texture_destroy(video->render_texture);
video->render_texture = NULL;
video->output_texture = NULL;
gs_leave_context(); for (size_t c = 0; c < NUM_CHANNELS; c++) {
if (video->convert_textures[c]) {
gs_texture_destroy(video->convert_textures[c]);
video->convert_textures[c] = NULL;
}
#ifdef _WIN32
if (video->convert_textures_encode[c]) {
gs_texture_destroy(video->convert_textures_encode[c]);
video->convert_textures_encode[c] = NULL;
}
#endif
}
gs_texture_destroy(video->output_texture);
video->render_texture = NULL;
video->output_texture = NULL;
gs_leave_context();
} }
void obs_free_video_mix(struct obs_core_video_mix *video) void obs_free_video_mix(struct obs_core_video_mix *video)