obs_core_video_mix创建
2024-07-01
9
0
obs_core_video_mix创建使用函数obs_create_video_mix创建,不过对外使用的其实是obs_view_add2和obs_view_add。
在OBS中,创建obs_core_video_mix有两处,分别为:
static int obs_init_video(struct obs_video_info *ovi)
{
...
//main_view增加至MIX,并设置为main
if (!obs_view_add2(&obs->data.main_view, ovi))
return OBS_VIDEO_FAIL;
...
}
和
bool BasicOutputHandler::StartVirtualCam()
{
...
if (!virtualCamVideo)
{
virtualCamVideo = typeIsProgram ? obs_get_video(): obs_view_add(virtualCamView);
if (!virtualCamVideo)
return false;
}
...
}
而obs_view_add与obs_view_add2的关系如下:
video_t *obs_view_add(obs_view_t *view)
{
if (!obs->video.main_mix)
return NULL;
return obs_view_add2(view, &obs->video.main_mix->ovi);
}
而其入口的参数view的成员就是obs_view。
struct obs_view {
pthread_mutex_t channels_mutex;
obs_source_t *channels[MAX_CHANNELS];
};
obs_view_add2
obs_view_add2函数如下:
video_t *obs_view_add2(obs_view_t *view, struct obs_video_info *ovi)
{
if (!view || !ovi)
return NULL;
struct obs_core_video_mix *mix = obs_create_video_mix(ovi);
if (!mix) {
return NULL;
}
mix->view = view;
pthread_mutex_lock(&obs->video.mixes_mutex);
da_push_back(obs->video.mixes, &mix);
set_main_mix();
pthread_mutex_unlock(&obs->video.mixes_mutex);
return mix->video;
}
其首先通过obs_create_video_mix创建该结构体内存,当然在其内部需要进行必要的初始化。
然后赋值view成员。
最后将创建的obs_core_video_mix对象存储在obs->video.mixes数组中。
obs_create_video_mix
obs_create_video_mix函数为:
struct obs_core_video_mix *obs_create_video_mix(struct obs_video_info *ovi)
{
//申请结构体内存空间
struct obs_core_video_mix *video = bzalloc(sizeof(struct obs_core_video_mix));
//初始化
if (obs_init_video_mix(ovi, video) != OBS_VIDEO_SUCCESS)
{
bfree(video);
video = NULL;
}
return video;
}
obs_init_video_mix
obs_init_video_mix源码如下:
static int obs_init_video_mix(struct obs_video_info *ovi, struct obs_core_video_mix *video)
{
struct video_output_info vi;
pthread_mutex_init_value(&video->gpu_encoder_mutex);
make_video_info(&vi, ovi);
video->ovi = *ovi;
/* main view graphics thread drives all frame output,
* so share FPS settings for aux views */
pthread_mutex_lock(&obs->video.mixes_mutex);
size_t num = obs->video.mixes.num;
if (num && obs->video.main_mix)
{
struct obs_video_info main_ovi = obs->video.main_mix->ovi;
video->ovi.fps_num = main_ovi.fps_num;
video->ovi.fps_den = main_ovi.fps_den;
}
pthread_mutex_unlock(&obs->video.mixes_mutex);
video->gpu_conversion = ovi->gpu_conversion;
video->gpu_was_active = false;
video->raw_was_active = false;
video->was_active = false;
set_video_matrix(video, &vi);
int 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 (pthread_mutex_init(&video->gpu_encoder_mutex, NULL) < 0)
return OBS_VIDEO_FAIL;
gs_enter_context(obs->video.graphics);
if (video->gpu_conversion && !obs_init_gpu_conversion(video))
return OBS_VIDEO_FAIL;
if (!obs_init_textures(video))
return OBS_VIDEO_FAIL;
gs_leave_context();
return OBS_VIDEO_SUCCESS;
}
这里比较重要的的是obs_init_textures函数。
obs_init_textures
- 对于NV12或P010格式,提供了编码格式函数。
- 如果支持CPU转换,提供其surfaces
获取颜色空间,创建render_texture和output_texture纹理。
static bool obs_init_textures(struct obs_core_video_mix *video) { const struct video_output_info *info = video_output_get_info(video->video); bool success = true; enum gs_color_format format = GS_BGRA; switch (info->format) { case VIDEO_FORMAT_I010: case VIDEO_FORMAT_P010: case VIDEO_FORMAT_I210: case VIDEO_FORMAT_I412: case VIDEO_FORMAT_YA2L: case VIDEO_FORMAT_P216: case VIDEO_FORMAT_P416: format = GS_RGBA16F; break; default: break; } for (size_t i = 0; i < NUM_TEXTURES/*2*/; i++) { #ifdef _WIN32 if (video->using_nv12_tex) { video->copy_surfaces_encode[i] =gs_stagesurface_create_nv12(info->width, info->height); if (!video->copy_surfaces_encode[i]) { success = false; break; } } else if (video->using_p010_tex) { video->copy_surfaces_encode[i] =gs_stagesurface_create_p010(info->width, info->height); if (!video->copy_surfaces_encode[i]) { success = false; break; } } #endif if (video->gpu_conversion) { if (!obs_init_gpu_copy_surfaces(video, i)) { success = false; break; } } else { video->copy_surfaces[i][0] = gs_stagesurface_create(info->width, info->height, format); if (!video->copy_surfaces[i][0]) { success = false; break; } } } enum gs_color_space space = GS_CS_SRGB; switch (info->colorspace) { case VIDEO_CS_2100_PQ: case VIDEO_CS_2100_HLG: space = GS_CS_709_EXTENDED; break; default: switch (info->format) { case VIDEO_FORMAT_I010: case VIDEO_FORMAT_P010: case VIDEO_FORMAT_P216: case VIDEO_FORMAT_P416: space = GS_CS_SRGB_16F; break; default: space = GS_CS_SRGB; break; } break; } //源渲染纹理 video->render_texture = gs_texture_create(video->ovi.base_width, video->ovi.base_height, format, 1, NULL, GS_RENDER_TARGET); if (!video->render_texture) success = false; //转换后的纹理 video->output_texture = gs_texture_create(info->width, info->height, format, 1, NULL, GS_RENDER_TARGET); if (!video->output_texture) success = false; if (success) { video->render_space = space; } else { //创建texture失败,销毁 } return success; }