提交 12cc06b5 编写于 作者: P Palana

Add GPU based frame decompression for async video sources

上级 b0becea1
......@@ -267,6 +267,8 @@ struct obs_source {
/* async video data */
texture_t async_texture;
texrender_t async_convert_texrender;
bool async_gpu_conversion;
enum video_format async_format;
float async_color_matrix[16];
bool async_full_range;
......@@ -277,6 +279,8 @@ struct obs_source {
pthread_mutex_t video_mutex;
uint32_t async_width;
uint32_t async_height;
uint32_t async_convert_width;
uint32_t async_convert_height;
/* filters */
struct obs_source *filter_parent;
......
......@@ -564,27 +564,6 @@ static void source_output_audio_line(obs_source_t source,
audio_line_output(source->audio_line, &in);
}
static inline bool set_async_texture_size(struct obs_source *source,
struct source_frame *frame)
{
if (source->async_texture) {
if (source->async_width == frame->width &&
source->async_height == frame->height)
return true;
}
texture_destroy(source->async_texture);
source->async_texture = gs_create_texture(frame->width, frame->height,
GS_RGBA, 1, NULL, GS_DYNAMIC);
if (!source->async_texture)
return false;
source->async_width = frame->width;
source->async_height = frame->height;
return true;
}
enum convert_type {
CONVERT_NONE,
CONVERT_NV12,
......@@ -617,11 +596,185 @@ static inline enum convert_type get_convert_type(enum video_format format)
return CONVERT_NONE;
}
static inline bool set_packed422_sizes(struct obs_source *source,
struct source_frame *frame)
{
source->async_convert_height = frame->height;
source->async_convert_width = frame->width / 2;
return true;
}
static inline bool init_gpu_conversion(struct obs_source *source,
struct source_frame *frame)
{
switch (get_convert_type(frame->format)) {
case CONVERT_422_Y:
case CONVERT_422_U:
return set_packed422_sizes(source, frame);
case CONVERT_NV12:
case CONVERT_420:
/* TODO: implement conversion */
break;
case CONVERT_NONE:
assert(false && "No conversion requested");
break;
}
return false;
}
static inline bool set_async_texture_size(struct obs_source *source,
struct source_frame *frame)
{
enum convert_type prev, cur;
prev = get_convert_type(source->async_format);
cur = get_convert_type(frame->format);
if (source->async_texture) {
if (source->async_width == frame->width &&
source->async_height == frame->height &&
prev == cur)
return true;
}
texture_destroy(source->async_texture);
texrender_destroy(source->async_convert_texrender);
source->async_convert_texrender = NULL;
if (cur != CONVERT_NONE && init_gpu_conversion(source, frame)) {
source->async_gpu_conversion = true;
source->async_convert_texrender =
texrender_create(GS_RGBA, GS_ZS_NONE);
source->async_texture = gs_create_texture(
source->async_convert_width,
source->async_convert_height,
GS_RGBA, 1, NULL, GS_DYNAMIC);
} else {
source->async_gpu_conversion = false;
source->async_texture = gs_create_texture(
frame->width, frame->height,
GS_RGBA, 1, NULL, GS_DYNAMIC);
}
if (!source->async_texture)
return false;
source->async_width = frame->width;
source->async_height = frame->height;
return true;
}
static void upload_raw_frame(texture_t tex, const struct source_frame *frame)
{
switch (get_convert_type(frame->format)) {
case CONVERT_422_U:
case CONVERT_422_Y:
texture_setimage(tex, frame->data[0],
frame->linesize[0], false);
break;
case CONVERT_NV12:
case CONVERT_420:
assert(false && "Conversion not yet implemented");
break;
case CONVERT_NONE:
assert(false && "No conversion requested");
break;
}
}
static const char *select_conversion_technique(enum video_format format)
{
switch (format) {
case VIDEO_FORMAT_UYVY:
return "UYUV_Reverse";
case VIDEO_FORMAT_YUY2:
return "YUY2_Reverse";
case VIDEO_FORMAT_YVYU:
return "YVYU_Reverse";
case VIDEO_FORMAT_NV12:
case VIDEO_FORMAT_I420:
assert(false && "Conversion not yet implemented");
break;
case VIDEO_FORMAT_BGRA:
case VIDEO_FORMAT_BGRX:
case VIDEO_FORMAT_RGBA:
case VIDEO_FORMAT_NONE:
assert(false && "No conversion requested");
break;
}
return NULL;
}
static inline void set_eparam(effect_t effect, const char *name, float val)
{
eparam_t param = effect_getparambyname(effect, name);
effect_setfloat(effect, param, val);
}
static bool update_async_texrender(struct obs_source *source,
const struct source_frame *frame)
{
texture_t tex = source->async_texture;
texrender_t texrender = source->async_convert_texrender;
texrender_reset(texrender);
upload_raw_frame(tex, frame);
uint32_t cx = source->async_width;
uint32_t cy = source->async_height;
effect_t conv = obs->video.conversion_effect;
technique_t tech = effect_gettechnique(conv,
select_conversion_technique(frame->format));
if (!texrender_begin(texrender, cx, cy))
return false;
technique_begin(tech);
technique_beginpass(tech, 0);
effect_settexture(conv, effect_getparambyname(conv, "image"),
tex);
set_eparam(conv, "width", (float)cx);
set_eparam(conv, "height", (float)cy);
set_eparam(conv, "width_i", 1.0f / cx);
set_eparam(conv, "height_i", 1.0f / cy);
set_eparam(conv, "width_d2", cx * 0.5f);
set_eparam(conv, "height_d2", cy * 0.5f);
set_eparam(conv, "width_d2_i", 1.0f / (cx * 0.5f));
set_eparam(conv, "height_d2_i", 1.0f / (cy * 0.5f));
set_eparam(conv, "input_height", (float)cy);
gs_ortho(0.f, (float)cx, 0.f, (float)cy, -100.f, 100.f);
gs_draw_sprite(tex, 0, cx, cy);
technique_endpass(tech);
technique_end(tech);
texrender_end(texrender);
return true;
}
static bool update_async_texture(struct obs_source *source,
const struct source_frame *frame)
{
texture_t tex = source->async_texture;
enum convert_type type = get_convert_type(frame->format);
texture_t tex = source->async_texture;
texrender_t texrender = source->async_convert_texrender;
enum convert_type type = get_convert_type(frame->format);
void *ptr;
uint32_t linesize;
......@@ -635,6 +788,9 @@ static bool update_async_texture(struct obs_source *source,
memcpy(source->async_color_range_max, frame->color_range_max,
sizeof frame->color_range_max);
if (source->async_gpu_conversion && texrender)
return update_async_texrender(source, frame);
if (type == CONVERT_NONE) {
texture_setimage(tex, frame->data[0], frame->linesize[0],
false);
......@@ -676,6 +832,9 @@ static inline void obs_source_draw_texture(struct obs_source *source,
texture_t tex = source->async_texture;
eparam_t param;
if (source->async_convert_texrender)
tex = texrender_gettexture(source->async_convert_texrender);
if (color_matrix) {
size_t const size = sizeof(float) * 3;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册