Browse Source

Merge pull request #1846 from jpark37/rgb-limited

Support limited color range for RGB/Y800 sources
Jim 6 years ago
parent
commit
6f23c1ca4f

+ 2 - 2
UI/data/locale/en-US.ini

@@ -802,8 +802,8 @@ Basic.Settings.Advanced.General.ProcessPriority.Idle="Idle"
 Basic.Settings.Advanced.FormatWarning="Warning: Color formats other than NV12 are primarily intended for recording, and are not recommended when streaming. Streaming may incur increased CPU usage due to color format conversion."
 Basic.Settings.Advanced.Audio.BufferingTime="Audio Buffering Time"
 Basic.Settings.Advanced.Video.ColorFormat="Color Format"
-Basic.Settings.Advanced.Video.ColorSpace="YUV Color Space"
-Basic.Settings.Advanced.Video.ColorRange="YUV Color Range"
+Basic.Settings.Advanced.Video.ColorSpace="Color Space"
+Basic.Settings.Advanced.Video.ColorRange="Color Range"
 Basic.Settings.Advanced.Video.ColorRange.Partial="Partial"
 Basic.Settings.Advanced.Video.ColorRange.Full="Full"
 Basic.Settings.Advanced.Audio.MonitoringDevice="Monitoring Device"

+ 56 - 0
libobs/data/format_conversion.effect

@@ -349,6 +349,35 @@ float4 PSNV12_Reverse(VertInOut vert_in) : TARGET
 	return saturate(mul(float4(yuv, 1.0), color_matrix));
 }
 
+float4 PSY800_Limited(VertInOut vert_in) : TARGET
+{
+	int x = int(vert_in.uv.x * width  + PRECISION_OFFSET);
+	int y = int(vert_in.uv.y * height + PRECISION_OFFSET);
+
+	float limited = image.Load(int3(x, y, 0)).x;
+	float full = saturate((limited - (16.0 / 255.0)) * (255.0 / 219.0));
+	return float4(full, full, full, 1.0);
+}
+
+float4 PSY800_Full(VertInOut vert_in) : TARGET
+{
+	int x = int(vert_in.uv.x * width  + PRECISION_OFFSET);
+	int y = int(vert_in.uv.y * height + PRECISION_OFFSET);
+
+	float3 full = image.Load(int3(x, y, 0)).xxx;
+	return float4(full, 1.0);
+}
+
+float4 PSRGB_Limited(VertInOut vert_in) : TARGET
+{
+	int x = int(vert_in.uv.x * width  + PRECISION_OFFSET);
+	int y = int(vert_in.uv.y * height + PRECISION_OFFSET);
+
+	float4 rgba = image.Load(int3(x, y, 0));
+	rgba.rgb = saturate((rgba.rgb - (16.0 / 255.0)) * (255.0 / 219.0));
+	return rgba;
+}
+
 technique Planar420
 {
 	pass
@@ -447,3 +476,30 @@ technique NV12_Reverse
 		pixel_shader  = PSNV12_Reverse(vert_in);
 	}
 }
+
+technique Y800_Limited
+{
+	pass
+	{
+		vertex_shader = VSDefault(vert_in);
+		pixel_shader  = PSY800_Limited(vert_in);
+	}
+}
+
+technique Y800_Full
+{
+	pass
+	{
+		vertex_shader = VSDefault(vert_in);
+		pixel_shader  = PSY800_Full(vert_in);
+	}
+}
+
+technique RGB_Limited
+{
+	pass
+	{
+		vertex_shader = VSDefault(vert_in);
+		pixel_shader  = PSRGB_Limited(vert_in);
+	}
+}

+ 14 - 6
libobs/media-io/video-io.h

@@ -135,15 +135,23 @@ static inline const char *get_video_colorspace_name(enum video_colorspace cs)
 	return "601";
 }
 
-static inline const char *get_video_range_name(enum video_range_type range)
+static inline enum video_range_type resolve_video_range(
+		enum video_format format, enum video_range_type range)
 {
-	switch (range) {
-	case VIDEO_RANGE_FULL: return "Full";
-	case VIDEO_RANGE_PARTIAL:
-	case VIDEO_RANGE_DEFAULT:;
+	if (range == VIDEO_RANGE_DEFAULT) {
+		range = format_is_yuv(format)
+			? VIDEO_RANGE_PARTIAL
+			: VIDEO_RANGE_FULL;
 	}
 
-	return "Partial";
+	return range;
+}
+
+static inline const char *get_video_range_name(enum video_format format,
+		enum video_range_type range)
+{
+	range = resolve_video_range(format, range);
+	return range == VIDEO_RANGE_FULL ? "Full" : "Partial";
 }
 
 enum video_scale_type {

+ 2 - 0
libobs/obs-internal.h

@@ -643,7 +643,9 @@ struct obs_source {
 	struct obs_source_frame         *cur_async_frame;
 	bool                            async_gpu_conversion;
 	enum video_format               async_format;
+	bool                            async_full_range;
 	enum video_format               async_cache_format;
+	bool                            async_cache_full_range;
 	enum gs_color_format            async_texture_format;
 	int                             async_plane_offset[2];
 	bool                            async_flip;

+ 171 - 74
libobs/obs-source.c

@@ -1330,9 +1330,12 @@ enum convert_type {
 	CONVERT_422_U,
 	CONVERT_422_Y,
 	CONVERT_444,
+	CONVERT_800,
+	CONVERT_RGB_LIMITED,
 };
 
-static inline enum convert_type get_convert_type(enum video_format format)
+static inline enum convert_type get_convert_type(enum video_format format,
+		bool full_range)
 {
 	switch (format) {
 	case VIDEO_FORMAT_I420:
@@ -1349,11 +1352,13 @@ static inline enum convert_type get_convert_type(enum video_format format)
 		return CONVERT_422_U;
 
 	case VIDEO_FORMAT_Y800:
+		return CONVERT_800;
+
 	case VIDEO_FORMAT_NONE:
 	case VIDEO_FORMAT_RGBA:
 	case VIDEO_FORMAT_BGRA:
 	case VIDEO_FORMAT_BGRX:
-		return CONVERT_NONE;
+		return full_range ? CONVERT_NONE : CONVERT_RGB_LIMITED;
 	}
 
 	return CONVERT_NONE;
@@ -1406,10 +1411,28 @@ static inline bool set_nv12_sizes(struct obs_source *source,
 	return true;
 }
 
+static inline bool set_y800_sizes(struct obs_source *source,
+	const struct obs_source_frame *frame)
+{
+	source->async_convert_width   = frame->width;
+	source->async_convert_height  = frame->height;
+	source->async_texture_format  = GS_R8;
+	return true;
+}
+
+static inline bool set_rgb_limited_sizes(struct obs_source *source,
+	const struct obs_source_frame *frame)
+{
+	source->async_convert_width   = frame->width;
+	source->async_convert_height  = frame->height;
+	source->async_texture_format  = convert_video_format(frame->format);
+	return true;
+}
+
 static inline bool init_gpu_conversion(struct obs_source *source,
 		const struct obs_source_frame *frame)
 {
-	switch (get_convert_type(frame->format)) {
+	switch (get_convert_type(frame->format, frame->full_range)) {
 		case CONVERT_422_Y:
 		case CONVERT_422_U:
 			return set_packed422_sizes(source, frame);
@@ -1423,6 +1446,12 @@ static inline bool init_gpu_conversion(struct obs_source *source,
 		case CONVERT_444:
 			return set_planar444_sizes(source, frame);
 
+		case CONVERT_800:
+			return set_y800_sizes(source, frame);
+
+		case CONVERT_RGB_LIMITED:
+			return set_rgb_limited_sizes(source, frame);
+
 		case CONVERT_NONE:
 			assert(false && "No conversion requested");
 			break;
@@ -1434,16 +1463,19 @@ static inline bool init_gpu_conversion(struct obs_source *source,
 bool set_async_texture_size(struct obs_source *source,
 		const struct obs_source_frame *frame)
 {
-	enum convert_type cur = get_convert_type(frame->format);
+	enum convert_type cur = get_convert_type(frame->format,
+			frame->full_range);
 
-	if (source->async_width  == frame->width  &&
-	    source->async_height == frame->height &&
-	    source->async_format == frame->format)
+	if (source->async_width      == frame->width  &&
+	    source->async_height     == frame->height &&
+	    source->async_format     == frame->format &&
+	    source->async_full_range == frame->full_range)
 		return true;
 
-	source->async_width  = frame->width;
-	source->async_height = frame->height;
-	source->async_format = frame->format;
+	source->async_width      = frame->width;
+	source->async_height     = frame->height;
+	source->async_format     = frame->format;
+	source->async_full_range = frame->full_range;
 
 	gs_enter_context(obs->video.graphics);
 
@@ -1459,8 +1491,10 @@ bool set_async_texture_size(struct obs_source *source,
 	if (cur != CONVERT_NONE && init_gpu_conversion(source, frame)) {
 		source->async_gpu_conversion = true;
 
+		enum gs_color_format format = CONVERT_RGB_LIMITED ?
+			convert_video_format(frame->format) : GS_BGRX;
 		source->async_texrender =
-			gs_texrender_create(GS_BGRX, GS_ZS_NONE);
+			gs_texrender_create(format, GS_ZS_NONE);
 
 		source->async_texture = gs_texture_create(
 				source->async_convert_width,
@@ -1489,23 +1523,17 @@ bool set_async_texture_size(struct obs_source *source,
 static void upload_raw_frame(gs_texture_t *tex,
 		const struct obs_source_frame *frame)
 {
-	switch (get_convert_type(frame->format)) {
+	switch (get_convert_type(frame->format, frame->full_range)) {
 		case CONVERT_422_U:
 		case CONVERT_422_Y:
+		case CONVERT_800:
+		case CONVERT_RGB_LIMITED:
 			gs_texture_set_image(tex, frame->data[0],
 					frame->linesize[0], false);
 			break;
 
 		case CONVERT_420:
-			gs_texture_set_image(tex, frame->data[0],
-					frame->width, false);
-			break;
-
 		case CONVERT_NV12:
-			gs_texture_set_image(tex, frame->data[0],
-					frame->width, false);
-			break;
-
 		case CONVERT_444:
 			gs_texture_set_image(tex, frame->data[0],
 					frame->width, false);
@@ -1517,7 +1545,8 @@ static void upload_raw_frame(gs_texture_t *tex,
 	}
 }
 
-static const char *select_conversion_technique(enum video_format format)
+static const char *select_conversion_technique(enum video_format format,
+		bool full_range)
 {
 	switch (format) {
 		case VIDEO_FORMAT_UYVY:
@@ -1539,11 +1568,16 @@ static const char *select_conversion_technique(enum video_format format)
 			return "I444_Reverse";
 
 		case VIDEO_FORMAT_Y800:
+			return full_range ? "Y800_Full" : "Y800_Limited";
+
 		case VIDEO_FORMAT_BGRA:
 		case VIDEO_FORMAT_BGRX:
 		case VIDEO_FORMAT_RGBA:
 		case VIDEO_FORMAT_NONE:
-			assert(false && "No conversion requested");
+			if (full_range)
+				assert(false && "No conversion requested");
+			else
+				return "RGB_Limited";
 			break;
 	}
 	return NULL;
@@ -1577,8 +1611,9 @@ static bool update_async_texrender(struct obs_source *source,
 	float convert_width  = (float)source->async_convert_width;
 
 	gs_effect_t *conv = obs->video.conversion_effect;
-	gs_technique_t *tech = gs_effect_get_technique(conv,
-			select_conversion_technique(frame->format));
+	const char *tech_name = select_conversion_technique(frame->format,
+			frame->full_range);
+	gs_technique_t *tech = gs_effect_get_technique(conv, tech_name);
 
 	if (!gs_texrender_begin(texrender, cx, cy)) {
 		GS_DEBUG_MARKER_END();
@@ -1632,7 +1667,7 @@ bool update_async_texture(struct obs_source *source,
 		const struct obs_source_frame *frame,
 		gs_texture_t *tex, gs_texrender_t *texrender)
 {
-	enum convert_type type      = get_convert_type(frame->format);
+	enum convert_type type;
 	uint8_t           *ptr;
 	uint32_t          linesize;
 
@@ -1641,6 +1676,7 @@ bool update_async_texture(struct obs_source *source,
 	if (source->async_gpu_conversion && texrender)
 		return update_async_texrender(source, frame, tex, texrender);
 
+	type = get_convert_type(frame->format, frame->full_range);
 	if (type == CONVERT_NONE) {
 		gs_texture_set_image(tex, frame->data[0], frame->linesize[0],
 				false);
@@ -2247,41 +2283,6 @@ static inline void copy_frame_data_plane(struct obs_source_frame *dst,
 				dst->linesize[plane] * lines);
 }
 
-static void copy_frame_data_line_y800(uint32_t *dst, uint8_t *src, uint8_t *end)
-{
-	while (src < end) {
-		register uint32_t val = *(src++);
-		val |= (val << 8);
-		val |= (val << 16);
-		*(dst++) = val;
-	}
-}
-
-static inline void copy_frame_data_y800(struct obs_source_frame *dst,
-		const struct obs_source_frame *src)
-{
-	uint32_t *ptr_dst;
-	uint8_t  *ptr_src;
-	uint8_t  *src_end;
-
-	if ((src->linesize[0] * 4) != dst->linesize[0]) {
-		for (uint32_t cy = 0; cy < src->height; cy++) {
-			ptr_dst = (uint32_t*)
-				(dst->data[0] + cy * dst->linesize[0]);
-			ptr_src = (src->data[0] + cy * src->linesize[0]);
-			src_end = ptr_src + src->width;
-
-			copy_frame_data_line_y800(ptr_dst, ptr_src, src_end);
-		}
-	} else {
-		ptr_dst = (uint32_t*)dst->data[0];
-		ptr_src = (uint8_t *)src->data[0];
-		src_end = ptr_src + src->height * src->linesize[0];
-
-		copy_frame_data_line_y800(ptr_dst, ptr_src, src_end);
-	}
-}
-
 static void copy_frame_data(struct obs_source_frame *dst,
 		const struct obs_source_frame *src)
 {
@@ -2320,11 +2321,8 @@ static void copy_frame_data(struct obs_source_frame *dst,
 	case VIDEO_FORMAT_RGBA:
 	case VIDEO_FORMAT_BGRA:
 	case VIDEO_FORMAT_BGRX:
-		copy_frame_data_plane(dst, src, 0, dst->height);
-		break;
-
 	case VIDEO_FORMAT_Y800:
-		copy_frame_data_y800(dst, src);
+		copy_frame_data_plane(dst, src, 0, dst->height);
 		break;
 	}
 }
@@ -2339,8 +2337,9 @@ static inline bool async_texture_changed(struct obs_source *source,
 		const struct obs_source_frame *frame)
 {
 	enum convert_type prev, cur;
-	prev = get_convert_type(source->async_cache_format);
-	cur  = get_convert_type(frame->format);
+	prev = get_convert_type(source->async_cache_format,
+			source->async_cache_full_range);
+	cur  = get_convert_type(frame->format, frame->full_range);
 
 	return source->async_cache_width  != frame->width ||
 	       source->async_cache_height != frame->height ||
@@ -2393,9 +2392,10 @@ static inline struct obs_source_frame *cache_video(struct obs_source *source,
 
 	if (async_texture_changed(source, frame)) {
 		free_async_cache(source);
-		source->async_cache_width  = frame->width;
-		source->async_cache_height = frame->height;
-		source->async_cache_format = frame->format;
+		source->async_cache_width      = frame->width;
+		source->async_cache_height     = frame->height;
+		source->async_cache_format     = frame->format;
+		source->async_cache_full_range = frame->full_range;
 	}
 
 	for (size_t i = 0; i < source->async_cache.num; i++) {
@@ -2414,9 +2414,6 @@ static inline struct obs_source_frame *cache_video(struct obs_source *source,
 		struct async_frame new_af;
 		enum video_format format = frame->format;
 
-		if (format == VIDEO_FORMAT_Y800)
-			format = VIDEO_FORMAT_BGRX;
-
 		new_frame = obs_source_frame_create(format,
 				frame->width, frame->height);
 		new_af.frame = new_frame;
@@ -2436,7 +2433,7 @@ static inline struct obs_source_frame *cache_video(struct obs_source *source,
 	return new_frame;
 }
 
-void obs_source_output_video(obs_source_t *source,
+static void obs_source_output_video_internal(obs_source_t *source,
 		const struct obs_source_frame *frame)
 {
 	if (!obs_source_valid(source, "obs_source_output_video"))
@@ -2464,6 +2461,56 @@ void obs_source_output_video(obs_source_t *source,
 	pthread_mutex_unlock(&source->async_mutex);
 }
 
+void obs_source_output_video(obs_source_t *source,
+		const struct obs_source_frame *frame)
+{
+	if (!frame) {
+		obs_source_output_video_internal(source, NULL);
+		return;
+	}
+
+	struct obs_source_frame new_frame = *frame;
+	new_frame.full_range = format_is_yuv(frame->format)
+		? new_frame.full_range
+		: true;
+
+	obs_source_output_video_internal(source, &new_frame);
+}
+
+void obs_source_output_video2(obs_source_t *source,
+		const struct obs_source_frame2 *frame)
+{
+	if (!frame) {
+		obs_source_output_video_internal(source, NULL);
+		return;
+	}
+
+	struct obs_source_frame new_frame;
+	enum video_range_type range = resolve_video_range(frame->format,
+			frame->range);
+
+	for (size_t i = 0; i < MAX_AV_PLANES; i++) {
+		new_frame.data[i] = frame->data[i];
+		new_frame.linesize[i] = frame->linesize[i];
+	}
+
+	new_frame.width = frame->width;
+	new_frame.height = frame->height;
+	new_frame.timestamp = frame->timestamp;
+	new_frame.format = frame->format;
+	new_frame.full_range = range == VIDEO_RANGE_FULL;
+	new_frame.flip = frame->flip;
+
+	memcpy(&new_frame.color_matrix, &frame->color_matrix,
+			sizeof(frame->color_matrix));
+	memcpy(&new_frame.color_range_min, &frame->color_range_min,
+			sizeof(frame->color_range_min));
+	memcpy(&new_frame.color_range_max, &frame->color_range_max,
+			sizeof(frame->color_range_max));
+
+	obs_source_output_video_internal(source, &new_frame);
+}
+
 static inline bool preload_frame_changed(obs_source_t *source,
 		const struct obs_source_frame *in)
 {
@@ -2475,7 +2522,7 @@ static inline bool preload_frame_changed(obs_source_t *source,
 	       in->format != source->async_preload_frame->format;
 }
 
-void obs_source_preload_video(obs_source_t *source,
+static void obs_source_preload_video_internal(obs_source_t *source,
 		const struct obs_source_frame *frame)
 {
 	if (!obs_source_valid(source, "obs_source_preload_video"))
@@ -2504,6 +2551,56 @@ void obs_source_preload_video(obs_source_t *source,
 	obs_leave_graphics();
 }
 
+void obs_source_preload_video(obs_source_t *source,
+		const struct obs_source_frame *frame)
+{
+	if (!frame) {
+		obs_source_preload_video_internal(source, NULL);
+		return;
+	}
+
+	struct obs_source_frame new_frame = *frame;
+	new_frame.full_range = format_is_yuv(frame->format)
+		? new_frame.full_range
+		: true;
+
+	obs_source_preload_video_internal(source, &new_frame);
+}
+
+void obs_source_preload_video2(obs_source_t *source,
+		const struct obs_source_frame2 *frame)
+{
+	if (!frame) {
+		obs_source_preload_video_internal(source, NULL);
+		return;
+	}
+
+	struct obs_source_frame new_frame;
+	enum video_range_type range = resolve_video_range(frame->format,
+			frame->range);
+
+	for (size_t i = 0; i < MAX_AV_PLANES; i++) {
+		new_frame.data[i] = frame->data[i];
+		new_frame.linesize[i] = frame->linesize[i];
+	}
+
+	new_frame.width = frame->width;
+	new_frame.height = frame->height;
+	new_frame.timestamp = frame->timestamp;
+	new_frame.format = frame->format;
+	new_frame.full_range = range == VIDEO_RANGE_FULL;
+	new_frame.flip = frame->flip;
+
+	memcpy(&new_frame.color_matrix, &frame->color_matrix,
+			sizeof(frame->color_matrix));
+	memcpy(&new_frame.color_range_min, &frame->color_range_min,
+			sizeof(frame->color_range_min));
+	memcpy(&new_frame.color_range_max, &frame->color_range_max,
+			sizeof(frame->color_range_max));
+
+	obs_source_preload_video_internal(source, &new_frame);
+}
+
 void obs_source_show_preloaded_video(obs_source_t *source)
 {
 	uint64_t sys_ts;

+ 2 - 1
libobs/obs.c

@@ -1129,7 +1129,8 @@ int obs_reset_video(struct obs_video_info *ovi)
 
 	bool yuv = format_is_yuv(ovi->output_format);
 	const char *yuv_format = get_video_colorspace_name(ovi->colorspace);
-	const char *yuv_range = get_video_range_name(ovi->range);
+	const char *yuv_range = get_video_range_name(ovi->output_format,
+			ovi->range);
 
 	blog(LOG_INFO, "---------------------------------");
 	blog(LOG_INFO, "video settings reset:\n"

+ 37 - 2
libobs/obs.h

@@ -220,6 +220,10 @@ struct obs_source_audio {
  *
  * If a YUV format is specified, it will be automatically upsampled and
  * converted to RGB via shader on the graphics processor.
+ *
+ * NOTE: Non-YUV formats will always be treated as full range with this
+ * structure!  Use obs_source_frame2 along with obs_source_output_video2
+ * instead if partial range support is desired for non-YUV video formats.
  */
 struct obs_source_frame {
 	uint8_t             *data[MAX_AV_PLANES];
@@ -240,6 +244,21 @@ struct obs_source_frame {
 	bool                prev_frame;
 };
 
+struct obs_source_frame2 {
+	uint8_t               *data[MAX_AV_PLANES];
+	uint32_t              linesize[MAX_AV_PLANES];
+	uint32_t              width;
+	uint32_t              height;
+	uint64_t              timestamp;
+
+	enum video_format     format;
+	enum video_range_type range;
+	float                 color_matrix[16];
+	float                 color_range_min[3];
+	float                 color_range_max[3];
+	bool                  flip;
+};
+
 /** Access to the argc/argv used to start OBS. What you see is what you get. */
 struct obs_cmdline_args {
 	int argc;
@@ -1117,13 +1136,29 @@ EXPORT void obs_source_draw_set_color_matrix(
 EXPORT void obs_source_draw(gs_texture_t *image, int x, int y,
 		uint32_t cx, uint32_t cy, bool flip);
 
-/** Outputs asynchronous video data.  Set to NULL to deactivate the texture */
+/**
+ * Outputs asynchronous video data.  Set to NULL to deactivate the texture
+ *
+ * NOTE: Non-YUV formats will always be treated as full range with this
+ * function!  Use obs_source_output_video2 instead if partial range support is
+ * desired for non-YUV video formats.
+ */
 EXPORT void obs_source_output_video(obs_source_t *source,
 		const struct obs_source_frame *frame);
+EXPORT void obs_source_output_video2(obs_source_t *source,
+		const struct obs_source_frame2 *frame);
 
-/** Preloads asynchronous video data to allow instantaneous playback */
+/**
+ * Preloads asynchronous video data to allow instantaneous playback
+ *
+ * NOTE: Non-YUV formats will always be treated as full range with this
+ * function!  Use obs_source_preload_video2 instead if partial range support is
+ * desired for non-YUV video formats.
+ */
 EXPORT void obs_source_preload_video(obs_source_t *source,
 		const struct obs_source_frame *frame);
+EXPORT void obs_source_preload_video2(obs_source_t *source,
+		const struct obs_source_frame2 *frame);
 
 /** Shows any preloaded video data */
 EXPORT void obs_source_show_preloaded_video(obs_source_t *source);

+ 2 - 2
plugins/decklink/data/locale/en-US.ini

@@ -3,9 +3,9 @@ Device="Device"
 Mode="Mode"
 Buffering="Use Buffering"
 PixelFormat="Pixel Format"
-ColorSpace="YUV Color Space"
+ColorSpace="Color Space"
 ColorSpace.Default="Default"
-ColorRange="YUV Color Range"
+ColorRange="Color Range"
 ColorRange.Default="Default"
 ColorRange.Partial="Partial"
 ColorRange.Full="Full"

+ 2 - 2
plugins/decklink/decklink-device-instance.cpp

@@ -135,7 +135,7 @@ void DeckLinkDeviceInstance::HandleVideoFrame(
 	currentFrame.height      = (uint32_t)videoFrame->GetHeight();
 	currentFrame.timestamp   = timestamp;
 
-	obs_source_output_video(static_cast<DeckLinkInput*>(decklink)->GetSource(), &currentFrame);
+	obs_source_output_video2(static_cast<DeckLinkInput*>(decklink)->GetSource(), &currentFrame);
 }
 
 void DeckLinkDeviceInstance::FinalizeStream()
@@ -177,7 +177,7 @@ void DeckLinkDeviceInstance::SetupVideoFormat(DeckLinkDeviceMode *mode_)
 	}
 
 	colorRange = static_cast<DeckLinkInput*>(decklink)->GetColorRange();
-	currentFrame.full_range = colorRange == VIDEO_RANGE_FULL;
+	currentFrame.range = colorRange;
 
 	video_format_get_parameters(activeColorSpace, colorRange,
 			currentFrame.color_matrix, currentFrame.color_range_min,

+ 1 - 1
plugins/decklink/decklink-device-instance.hpp

@@ -11,7 +11,7 @@ class DecklinkBase;
 
 class DeckLinkDeviceInstance : public IDeckLinkInputCallback {
 protected:
-	struct obs_source_frame currentFrame;
+	struct obs_source_frame2 currentFrame;
 	struct obs_source_audio currentPacket;
 	DecklinkBase            *decklink = nullptr;
 	DeckLinkDevice          *device = nullptr;

+ 0 - 22
plugins/decklink/decklink-source.cpp

@@ -220,9 +220,6 @@ static bool decklink_device_changed(obs_properties_t *props,
 	return true;
 }
 
-static bool color_format_changed(obs_properties_t *props,
-		obs_property_t *list, obs_data_t *settings);
-
 static bool mode_id_changed(obs_properties_t *props,
 		obs_property_t *list, obs_data_t *settings)
 {
@@ -231,24 +228,6 @@ static bool mode_id_changed(obs_properties_t *props,
 	list = obs_properties_get(props, PIXEL_FORMAT);
 	obs_property_set_visible(list, id != MODE_ID_AUTO);
 
-	return color_format_changed(props, nullptr, settings);
-}
-
-static bool color_format_changed(obs_properties_t *props,
-		obs_property_t *list, obs_data_t *settings)
-{
-	long long id = obs_data_get_int(settings, MODE_ID);
-	BMDPixelFormat pixelFormat = (BMDPixelFormat)obs_data_get_int(settings,
-		PIXEL_FORMAT);
-
-	list = obs_properties_get(props, COLOR_SPACE);
-	obs_property_set_visible(list,
-			id != MODE_ID_AUTO && pixelFormat == bmdFormat8BitYUV);
-
-	list = obs_properties_get(props, COLOR_RANGE);
-	obs_property_set_visible(list,
-			id == MODE_ID_AUTO || pixelFormat == bmdFormat8BitYUV);
-
 	return true;
 }
 
@@ -274,7 +253,6 @@ static obs_properties_t *decklink_get_properties(void *data)
 	list = obs_properties_add_list(props, PIXEL_FORMAT,
 			TEXT_PIXEL_FORMAT, OBS_COMBO_TYPE_LIST,
 			OBS_COMBO_FORMAT_INT);
-	obs_property_set_modified_callback(list, color_format_changed);
 
 	obs_property_list_add_int(list, "8-bit YUV", bmdFormat8BitYUV);
 	obs_property_list_add_int(list, "8-bit BGRA", bmdFormat8BitBGRA);

+ 2 - 2
plugins/win-dshow/data/locale/en-US.ini

@@ -1,9 +1,9 @@
 # video capture device text
 VideoCaptureDevice="Video Capture Device"
 Device="Device"
-ColorSpace="YUV Color Space"
+ColorSpace="Color Space"
 ColorSpace.Default="Default"
-ColorRange="YUV Color Range"
+ColorRange="Color Range"
 ColorRange.Partial="Partial"
 ColorRange.Full="Full"
 ConfigureAudio="Configure Audio"

+ 5 - 8
plugins/win-dshow/ffmpeg-decode.c

@@ -181,7 +181,7 @@ bool ffmpeg_decode_audio(struct ffmpeg_decode *decode,
 
 bool ffmpeg_decode_video(struct ffmpeg_decode *decode,
 		uint8_t *data, size_t size, long long *ts,
-		struct obs_source_frame *frame,
+		struct obs_source_frame2 *frame,
 		bool *got_output)
 {
 	AVPacket packet = {0};
@@ -230,17 +230,14 @@ bool ffmpeg_decode_video(struct ffmpeg_decode *decode,
 	new_format = convert_pixel_format(decode->frame->format);
 	if (new_format != frame->format) {
 		bool success;
-		enum video_range_type range;
 
 		frame->format = new_format;
-		frame->full_range =
-			decode->frame->color_range == AVCOL_RANGE_JPEG;
-
-		range = frame->full_range ?
-			VIDEO_RANGE_FULL : VIDEO_RANGE_PARTIAL;
+		frame->range = decode->frame->color_range == AVCOL_RANGE_JPEG
+			? VIDEO_RANGE_FULL
+			: VIDEO_RANGE_DEFAULT;
 
 		success = video_format_get_parameters(VIDEO_CS_601,
-				range, frame->color_matrix,
+				frame->range, frame->color_matrix,
 				frame->color_range_min, frame->color_range_max);
 		if (!success) {
 			blog(LOG_ERROR, "Failed to get video format "

+ 1 - 1
plugins/win-dshow/ffmpeg-decode.h

@@ -56,7 +56,7 @@ extern bool ffmpeg_decode_audio(struct ffmpeg_decode *decode,
 
 extern bool ffmpeg_decode_video(struct ffmpeg_decode *decode,
 		uint8_t *data, size_t size, long long *ts,
-		struct obs_source_frame *frame,
+		struct obs_source_frame2 *frame,
 		bool *got_output);
 
 static inline bool ffmpeg_decode_valid(struct ffmpeg_decode *decode)

+ 7 - 9
plugins/win-dshow/win-dshow.cpp

@@ -176,7 +176,7 @@ struct DShowInput {
 	VideoConfig  videoConfig;
 	AudioConfig  audioConfig;
 
-	obs_source_frame frame;
+	obs_source_frame2 frame;
 	obs_source_audio audio;
 
 	WinHandle semaphore;
@@ -327,7 +327,7 @@ void DShowInput::DShowLoop()
 				obs_data_t *settings;
 				settings = obs_source_get_settings(source);
 				if (!Activate(settings)) {
-					obs_source_output_video(source,
+					obs_source_output_video2(source,
 							nullptr);
 				}
 				if (block)
@@ -468,7 +468,7 @@ void DShowInput::OnEncodedVideoData(enum AVCodecID id,
 #if LOG_ENCODED_VIDEO_TS
 		blog(LOG_DEBUG, "video ts: %llu", frame.timestamp);
 #endif
-		obs_source_output_video(source, &frame);
+		obs_source_output_video2(source, &frame);
 	}
 }
 
@@ -537,7 +537,7 @@ void DShowInput::OnVideoData(const VideoConfig &config,
 		return;
 	}
 
-	obs_source_output_video(source, &frame);
+	obs_source_output_video2(source, &frame);
 
 	UNUSED_PARAMETER(endTime); /* it's the enndd tiimmes! */
 	UNUSED_PARAMETER(size);
@@ -1040,15 +1040,13 @@ inline bool DShowInput::Activate(obs_data_t *settings)
 		return false;
 
 	enum video_colorspace cs = GetColorSpace(settings);
-
-	video_range_type range = GetColorRange(settings);
-	frame.full_range = range == VIDEO_RANGE_FULL;
+	frame.range = GetColorRange(settings);
 
 	if (device.Start() != Result::Success)
 		return false;
 
 	bool success = video_format_get_parameters(
-			cs, range,
+			cs, frame.range,
 			frame.color_matrix,
 			frame.color_range_min,
 			frame.color_range_max);
@@ -1063,7 +1061,7 @@ inline bool DShowInput::Activate(obs_data_t *settings)
 inline void DShowInput::Deactivate()
 {
 	device.ResetGraph();
-	obs_source_output_video(source, nullptr);
+	obs_source_output_video2(source, nullptr);
 }
 
 /* ------------------------------------------------------------------------- */