obs_source_frame到纹理
2024-12-17
5
0
MP4的视频通过解码后为YUV格式的frame数据,其需要通过将该frame的YUV数据复制到纹理(source->async_textures),这样着色器就可以通过GPU将YUV进行采样的值转换成RGB,最终渲染到目标纹理(source->async_texrender )上。
入口函数:update_async_textures
bool update_async_textures(struct obs_source *source,
const struct obs_source_frame *frame,
gs_texture_t *tex[MAX_AV_PLANES],
gs_texrender_t *texrender)
对于YUV需要使用着色器转换成RGB,调用update_async_texrender。
1.使用upload_raw_frame将frame中的YUV数据复制到纹理空间(source->async_textures)
static void upload_raw_frame(gs_texture_t *tex[MAX_AV_PLANES],
const struct obs_source_frame *frame)
{
switch (get_convert_type(frame->format, frame->full_range)) {
case CONVERT_422_PACK:
case CONVERT_800:
case CONVERT_RGB_LIMITED:
case CONVERT_BGR3:
case CONVERT_420:
case CONVERT_422:
case CONVERT_NV12:
case CONVERT_444:
case CONVERT_420_A:
case CONVERT_422_A:
case CONVERT_444_A:
case CONVERT_444_A_PACK:
for (size_t c = 0; c < MAX_AV_PLANES; c++) {
if (tex[c])
gs_texture_set_image(tex[c], frame->data[c], frame->linesize[c], false);
}
break;
case CONVERT_NONE:
assert(false && "No conversion requested");
break;
}
}
2.根据格式获取到合钐的tech,并在gs_texrender_begin设置渲染目标(source->async_texrender )上。
uint32_t cx = source->async_width;
uint32_t cy = source->async_height;
gs_effect_t *conv = obs->video.conversion_effect;
const char *tech_name = select_conversion_technique(frame->format, frame->full_range);
gs_technique_t *tech = gs_effect_get_technique(conv, tech_name);
const bool success = gs_texrender_begin(texrender, cx, cy);
tech_name为I420_Reverse。
注意,这里不出图,是渲染到纹理上,故视图必须为实际图像的大小。
gs_set_viewport(0, 0, texrender->cx, texrender->cy);
3.二次绘制?obs_source_render_async_video
将source->async_texrender 绘制的纹理作为DrawNonlinearAlpha着色器的参数进行二次绘制.这次输出的目标是
struct obs_core_video *video;
tex = &obs->video.render_texture;
其是通过gs_texrender_end设置的。
void gs_texrender_end(gs_texrender_t *texrender)
{
if (!texrender)
return;
//恢复原来的输出目标不视图
gs_set_render_target(texrender->prev_target, texrender->prev_zs);
//device->curProjMatrix
gs_projection_pop();
//视口
gs_viewport_pop();
texrender->rendered = true;
}