فهرست منبع

libobs: Use NV12 textures when available

jp9000 7 سال پیش
والد
کامیت
28d0cc8b97
5فایلهای تغییر یافته به همراه170 افزوده شده و 13 حذف شده
  1. 28 0
      libobs/data/format_conversion.effect
  2. 2 0
      libobs/obs-internal.h
  3. 79 2
      libobs/obs-video.c
  4. 59 11
      libobs/obs.c
  5. 2 0
      libobs/obs.h

+ 28 - 0
libobs/data/format_conversion.effect

@@ -126,6 +126,16 @@ float4 PSNV12(VertInOut vert_in) : TARGET
 	}
 }
 
+float PSNV12_Y(VertInOut vert_in) : TARGET
+{
+	return image.Sample(def_sampler, vert_in.uv.xy).y;
+}
+
+float2 PSNV12_UV(VertInOut vert_in) : TARGET
+{
+	return image.Sample(def_sampler, vert_in.uv.xy).xz;
+}
+
 float4 PSPlanar420(VertInOut vert_in) : TARGET
 {
 	float v_mul = floor(vert_in.uv.y * input_height);
@@ -339,6 +349,24 @@ technique NV12
 	}
 }
 
+technique NV12_Y
+{
+	pass
+	{
+		vertex_shader = VSDefault(vert_in);
+		pixel_shader  = PSNV12_Y(vert_in);
+	}
+}
+
+technique NV12_UV
+{
+	pass
+	{
+		vertex_shader = VSDefault(vert_in);
+		pixel_shader  = PSNV12_UV(vert_in);
+	}
+}
+
 technique UYVY_Reverse
 {
 	pass

+ 2 - 0
libobs/obs-internal.h

@@ -231,10 +231,12 @@ struct obs_core_video {
 	gs_texture_t                    *render_textures[NUM_TEXTURES];
 	gs_texture_t                    *output_textures[NUM_TEXTURES];
 	gs_texture_t                    *convert_textures[NUM_TEXTURES];
+	gs_texture_t                    *convert_uv_textures[NUM_TEXTURES];
 	bool                            textures_rendered[NUM_TEXTURES];
 	bool                            textures_output[NUM_TEXTURES];
 	bool                            textures_copied[NUM_TEXTURES];
 	bool                            textures_converted[NUM_TEXTURES];
+	bool                            using_nv12_tex;
 	struct circlebuf                vframe_info_buffer;
 	gs_effect_t                     *default_effect;
 	gs_effect_t                     *default_rect_effect;

+ 79 - 2
libobs/obs-video.c

@@ -310,6 +310,55 @@ end:
 	profile_end(render_convert_texture_name);
 }
 
+static void render_nv12(struct obs_core_video *video, gs_texture_t *target,
+		int cur_texture, int prev_texture, const char *tech_name,
+		uint32_t width, uint32_t height)
+{
+	gs_texture_t *texture = video->output_textures[prev_texture];
+
+	gs_effect_t    *effect  = video->conversion_effect;
+	gs_eparam_t    *image   = gs_effect_get_param_by_name(effect, "image");
+	gs_technique_t *tech    = gs_effect_get_technique(effect, tech_name);
+	size_t         passes, i;
+
+	gs_effect_set_texture(image, texture);
+
+	gs_set_render_target(target, NULL);
+	set_render_size(width, height);
+
+	gs_enable_blending(false);
+	passes = gs_technique_begin(tech);
+	for (i = 0; i < passes; i++) {
+		gs_technique_begin_pass(tech, i);
+		gs_draw_sprite(texture, 0, width, height);
+		gs_technique_end_pass(tech);
+	}
+	gs_technique_end(tech);
+	gs_enable_blending(true);
+}
+
+static const char *render_convert_nv12_name = "render_convert_texture_nv12";
+static void render_convert_texture_nv12(struct obs_core_video *video,
+		int cur_texture, int prev_texture)
+{
+	profile_start(render_convert_nv12_name);
+
+	if (!video->textures_output[prev_texture])
+		goto end;
+
+	render_nv12(video, video->convert_textures[cur_texture],
+			cur_texture, prev_texture, "NV12_Y",
+			video->output_width, video->output_height);
+	render_nv12(video, video->convert_uv_textures[cur_texture],
+			cur_texture, prev_texture, "NV12_UV",
+			video->output_width / 2, video->output_height / 2);
+
+	video->textures_converted[cur_texture] = true;
+
+end:
+	profile_end(render_convert_nv12_name);
+}
+
 static const char *stage_output_texture_name = "stage_output_texture";
 static inline void stage_output_texture(struct obs_core_video *video,
 		int cur_texture, int prev_texture)
@@ -353,8 +402,15 @@ static inline void render_video(struct obs_core_video *video, bool raw_active,
 
 	if (raw_active) {
 		render_output_texture(video, cur_texture, prev_texture);
-		if (video->gpu_conversion)
-			render_convert_texture(video, cur_texture, prev_texture);
+
+		if (video->gpu_conversion) {
+			if (video->using_nv12_tex)
+				render_convert_texture_nv12(video,
+						cur_texture, prev_texture);
+			else
+				render_convert_texture(video,
+						cur_texture, prev_texture);
+		}
 
 		stage_output_texture(video, cur_texture, prev_texture);
 	}
@@ -455,6 +511,27 @@ static void set_gpu_converted_data(struct obs_core_video *video,
 
 		video_frame_copy(output, &frame, info->format, info->height);
 
+	} else if (video->using_nv12_tex) {
+		int width = (int)info->width;
+		int height = (int)info->height;
+		int width_d2 = width / 2;
+		int height_d2 = height / 2;
+		int height_d4 = height_d2 / 2;
+		uint8_t *out_y = output->data[0];
+		uint8_t *out_uv = output->data[1];
+		uint8_t *in = input->data[0];
+
+		for (size_t y = 0; y < height; y++) {
+			memcpy(out_y, in, width);
+			out_y += output->linesize[0];
+			in += input->linesize[0];
+		}
+		for (size_t y = 0; y < height_d2; y++) {
+			memcpy(out_uv, in, width);
+			out_uv += output->linesize[0];
+			in += input->linesize[0];
+		}
+
 	} else {
 		fix_gpu_converted_alignment(video, output, input);
 	}

+ 59 - 11
libobs/obs.c

@@ -164,17 +164,42 @@ static bool obs_init_gpu_conversion(struct obs_video_info *ovi)
 
 	calc_gpu_conversion_sizes(ovi);
 
+	video->using_nv12_tex = ovi->output_format == VIDEO_FORMAT_NV12
+		? gs_nv12_available() : false;
+
 	if (!video->conversion_height) {
 		blog(LOG_INFO, "GPU conversion not available for format: %u",
 				(unsigned int)ovi->output_format);
 		video->gpu_conversion = false;
+		video->using_nv12_tex = false;
+		blog(LOG_INFO, "NV12 texture support not available");
 		return true;
 	}
 
+	if (video->using_nv12_tex)
+		blog(LOG_INFO, "NV12 texture support enabled");
+	else
+		blog(LOG_INFO, "NV12 texture support not available");
+
 	for (size_t i = 0; i < NUM_TEXTURES; i++) {
-		video->convert_textures[i] = gs_texture_create(
-				ovi->output_width, video->conversion_height,
-				GS_RGBA, 1, NULL, GS_RENDER_TARGET);
+#ifdef _WIN32
+		if (video->using_nv12_tex) {
+			gs_texture_create_nv12(
+					&video->convert_textures[i],
+					&video->convert_uv_textures[i],
+					ovi->output_width, ovi->output_height,
+					GS_RENDER_TARGET | GS_SHARED_KM_TEX);
+			if (!video->convert_uv_textures[i])
+				return false;
+		} else {
+#endif
+			video->convert_textures[i] = gs_texture_create(
+					ovi->output_width,
+					video->conversion_height,
+					GS_RGBA, 1, NULL, GS_RENDER_TARGET);
+#ifdef _WIN32
+		}
+#endif
 
 		if (!video->convert_textures[i])
 			return false;
@@ -191,11 +216,23 @@ static bool obs_init_textures(struct obs_video_info *ovi)
 	size_t i;
 
 	for (i = 0; i < NUM_TEXTURES; i++) {
-		video->copy_surfaces[i] = gs_stagesurface_create(
-				ovi->output_width, output_height, GS_RGBA);
+#ifdef _WIN32
+		if (video->using_nv12_tex) {
+			video->copy_surfaces[i] = gs_stagesurface_create_nv12(
+					ovi->output_width, ovi->output_height);
+			if (!video->copy_surfaces[i])
+				return false;
 
-		if (!video->copy_surfaces[i])
-			return false;
+		} else {
+#endif
+			video->copy_surfaces[i] = gs_stagesurface_create(
+					ovi->output_width, output_height,
+					GS_RGBA);
+			if (!video->copy_surfaces[i])
+				return false;
+#ifdef _WIN32
+		}
+#endif
 
 		video->render_textures[i] = gs_texture_create(
 				ovi->base_width, ovi->base_height,
@@ -431,12 +468,14 @@ static void obs_free_video(void)
 			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->convert_uv_textures[i]);
 			gs_texture_destroy(video->output_textures[i]);
 
-			video->copy_surfaces[i]    = NULL;
-			video->render_textures[i]  = NULL;
-			video->convert_textures[i] = NULL;
-			video->output_textures[i]  = NULL;
+			video->copy_surfaces[i]       = NULL;
+			video->render_textures[i]     = NULL;
+			video->convert_textures[i]    = NULL;
+			video->convert_uv_textures[i] = NULL;
+			video->output_textures[i]     = NULL;
 		}
 
 		gs_leave_context();
@@ -2267,3 +2306,12 @@ bool obs_video_active(void)
 
 	return os_atomic_load_long(&video->raw_active) > 0;
 }
+
+bool obs_nv12_tex_active(void)
+{
+	struct obs_core_video *video = &obs->video;
+	if (!obs)
+		return false;
+
+	return video->using_nv12_tex;
+}

+ 2 - 0
libobs/obs.h

@@ -713,6 +713,8 @@ EXPORT uint64_t obs_get_average_frame_time_ns(void);
 EXPORT uint32_t obs_get_total_frames(void);
 EXPORT uint32_t obs_get_lagged_frames(void);
 
+EXPORT bool obs_nv12_tex_active(void);
+
 EXPORT void obs_apply_private_data(obs_data_t *settings);
 EXPORT void obs_set_private_data(obs_data_t *settings);
 EXPORT obs_data_t *obs_get_private_data(void);