Browse Source

Add API functions for output/encoder scaling

API functions added:
-----------------------------------------------
obs_output_set_preferred_size
obs_output_get_width
obs_output_get_height
obs_encoder_set_scaled_size
obs_encoder_get_width
obs_encoder_get_height

These functions allow for easier means of setting a custom resolution on
an output or encoder.

If an output uses an encoder and you set the preferred width/height
using the output, then the output will attempt to set the scaled
width/height for the encoder it's currently using.

Outputs and encoders now should use these functions to determine the
width/height of the raw frame data instead of using the video-io
functions.
jp9000 11 years ago
parent
commit
a0f679bc40
4 changed files with 189 additions and 4 deletions
  1. 64 3
      libobs/obs-encoder.c
  2. 6 0
      libobs/obs-internal.h
  3. 88 1
      libobs/obs-output.c
  4. 31 0
      libobs/obs.h

+ 64 - 3
libobs/obs-encoder.c

@@ -130,6 +130,16 @@ static inline struct video_scale_info *get_video_info(
 	return NULL;
 }
 
+static inline bool has_scaling(struct obs_encoder *encoder)
+{
+	uint32_t video_width  = video_output_get_width(encoder->media);
+	uint32_t video_height = video_output_get_height(encoder->media);
+
+	return encoder->scaled_width && encoder->scaled_height &&
+		(video_width  != encoder->scaled_width ||
+		 video_height != encoder->scaled_height);
+}
+
 static void add_connection(struct obs_encoder *encoder)
 {
 	struct audio_convert_info audio_info = {0};
@@ -140,11 +150,23 @@ static void add_connection(struct obs_encoder *encoder)
 		audio_output_connect(encoder->media, &audio_info, receive_audio,
 				encoder);
 	} else {
-		struct video_scale_info *info = NULL;
+		struct video_scale_info *info =
+			get_video_info(encoder, &video_info);
+
+		if (!info && has_scaling(encoder)) {
+			info = &video_info;
+			info->format = video_output_get_format(encoder->media);
+			info->colorspace = VIDEO_CS_DEFAULT;
+			info->range      = VIDEO_RANGE_DEFAULT;
+		}
+
+		if (info && (!info->width || !info->height)) {
+			info->width  = obs_encoder_get_width(encoder);
+			info->height = obs_encoder_get_height(encoder);
+		}
 
-		info = get_video_info(encoder, &video_info);
 		video_output_connect(encoder->media, info, receive_video,
-				encoder);
+			encoder);
 	}
 
 	encoder->active = true;
@@ -410,6 +432,45 @@ const char *obs_encoder_get_codec(obs_encoder_t encoder)
 	return encoder ? encoder->info.codec : NULL;
 }
 
+void obs_encoder_set_scaled_size(obs_encoder_t encoder, uint32_t width,
+		uint32_t height)
+{
+	if (!encoder || encoder->info.type != OBS_ENCODER_VIDEO)
+		return;
+
+	if (encoder->active) {
+		blog(LOG_WARNING, "encoder '%s': Cannot set the scaled "
+		                  "resolution while the encoder is active",
+		                  obs_encoder_get_name(encoder));
+		return;
+	}
+
+	encoder->scaled_width  = width;
+	encoder->scaled_height = height;
+}
+
+uint32_t obs_encoder_get_width(obs_encoder_t encoder)
+{
+	if (!encoder || !encoder->media ||
+	    encoder->info.type != OBS_ENCODER_VIDEO)
+		return 0;
+
+	return encoder->scaled_width != 0 ?
+		encoder->scaled_width :
+		video_output_get_width(encoder->media);
+}
+
+uint32_t obs_encoder_get_height(obs_encoder_t encoder)
+{
+	if (!encoder || !encoder->media ||
+	    encoder->info.type != OBS_ENCODER_VIDEO)
+		return 0;
+
+	return encoder->scaled_width != 0 ?
+		encoder->scaled_height :
+		video_output_get_height(encoder->media);
+}
+
 void obs_encoder_set_video(obs_encoder_t encoder, video_t video)
 {
 	const struct video_output_info *voi;

+ 6 - 0
libobs/obs-internal.h

@@ -419,6 +419,9 @@ struct obs_output {
 	obs_encoder_t                   audio_encoder;
 	obs_service_t                   service;
 
+	uint32_t                        scaled_width;
+	uint32_t                        scaled_height;
+
 	bool                            video_conversion_set;
 	bool                            audio_conversion_set;
 	struct video_scale_info         video_conversion;
@@ -452,6 +455,9 @@ struct obs_encoder {
 	size_t                          framesize;
 	size_t                          framesize_bytes;
 
+	uint32_t                        scaled_width;
+	uint32_t                        scaled_height;
+
 	bool                            active;
 
 	uint32_t                        timebase_num;

+ 88 - 1
libobs/obs-output.c

@@ -296,6 +296,11 @@ void obs_output_set_video_encoder(obs_output_t output, obs_encoder_t encoder)
 	obs_encoder_remove_output(encoder, output);
 	obs_encoder_add_output(encoder, output);
 	output->video_encoder = encoder;
+
+	/* set the preferred resolution on the encoder */
+	if (output->scaled_width && output->scaled_height)
+		obs_encoder_set_scaled_size(output->video_encoder,
+				output->scaled_width, output->scaled_height);
 }
 
 void obs_output_set_audio_encoder(obs_output_t output, obs_encoder_t encoder)
@@ -365,6 +370,55 @@ int obs_output_get_total_frames(obs_output_t output)
 	return output ? output->total_frames : 0;
 }
 
+void obs_output_set_preferred_size(obs_output_t output, uint32_t width,
+		uint32_t height)
+{
+	if (!output || (output->info.flags & OBS_OUTPUT_VIDEO) == 0)
+		return;
+
+	if (output->active) {
+		blog(LOG_WARNING, "output '%s': Cannot set the preferred "
+		                  "resolution while the output is active",
+		                  obs_output_get_name(output));
+		return;
+	}
+
+	output->scaled_width  = width;
+	output->scaled_height = height;
+
+	if (output->info.flags & OBS_OUTPUT_ENCODED) {
+		if (output->video_encoder)
+			obs_encoder_set_scaled_size(output->video_encoder,
+					width, height);
+	}
+}
+
+uint32_t obs_output_get_width(obs_output_t output)
+{
+	if (!output || (output->info.flags & OBS_OUTPUT_VIDEO) == 0)
+		return 0;
+
+	if (output->info.flags & OBS_OUTPUT_ENCODED)
+		return obs_encoder_get_width(output->video_encoder);
+	else
+		return output->scaled_width != 0 ?
+			output->scaled_width :
+			video_output_get_width(output->video);
+}
+
+uint32_t obs_output_get_height(obs_output_t output)
+{
+	if (!output || (output->info.flags & OBS_OUTPUT_VIDEO) == 0)
+		return 0;
+
+	if (output->info.flags & OBS_OUTPUT_ENCODED)
+		return obs_encoder_get_height(output->video_encoder);
+	else
+		return output->scaled_height != 0 ?
+			output->scaled_height :
+			video_output_get_height(output->video);
+}
+
 void obs_output_set_video_conversion(obs_output_t output,
 		const struct video_scale_info *conversion)
 {
@@ -412,10 +466,43 @@ static bool can_begin_data_capture(struct obs_output *output, bool encoded,
 	return true;
 }
 
+static inline bool has_scaling(struct obs_output *output)
+{
+	uint32_t video_width  = video_output_get_width(output->video);
+	uint32_t video_height = video_output_get_height(output->video);
+
+	return output->scaled_width && output->scaled_height &&
+		(video_width  != output->scaled_width ||
+		 video_height != output->scaled_height);
+}
+
 static inline struct video_scale_info *get_video_conversion(
 		struct obs_output *output)
 {
-	return output->video_conversion_set ? &output->video_conversion : NULL;
+	if (output->video_conversion_set) {
+		if (!output->video_conversion.width)
+			output->video_conversion.width =
+				obs_output_get_width(output);
+
+		if (!output->video_conversion.height)
+			output->video_conversion.height =
+				obs_output_get_height(output);
+
+		return &output->video_conversion;
+
+	} else if (has_scaling(output)) {
+		const struct video_output_info *info =
+			video_output_get_info(output->video);
+
+		output->video_conversion.format     = info->format;
+		output->video_conversion.colorspace = VIDEO_CS_DEFAULT;
+		output->video_conversion.range      = VIDEO_RANGE_DEFAULT;
+		output->video_conversion.width      = output->scaled_width;
+		output->video_conversion.height     = output->scaled_height;
+		return &output->video_conversion;
+	}
+
+	return NULL;
 }
 
 static inline struct audio_convert_info *get_audio_conversion(

+ 31 - 0
libobs/obs.h

@@ -953,6 +953,23 @@ EXPORT uint64_t obs_output_get_total_bytes(obs_output_t output);
 EXPORT int obs_output_get_frames_dropped(obs_output_t output);
 EXPORT int obs_output_get_total_frames(obs_output_t output);
 
+/**
+ * Sets the preferred scaled resolution for this output.  Set width and height
+ * to 0 to disable scaling.
+ *
+ * If this output uses an encoder, it will call obs_encoder_set_scaled_size on
+ * the encoder before the stream is started.  If the encoder is already active,
+ * then this function will trigger a warning and do nothing.
+ */
+EXPORT void obs_output_set_preferred_size(obs_output_t output, uint32_t width,
+		uint32_t height);
+
+/** For video outputs, returns the width of the encoded image */
+EXPORT uint32_t obs_output_get_width(obs_output_t output);
+
+/** For video outputs, returns the height of the encoded image */
+EXPORT uint32_t obs_output_get_height(obs_output_t output);
+
 /* ------------------------------------------------------------------------- */
 /* Functions used by outputs */
 
@@ -1032,6 +1049,20 @@ EXPORT const char *obs_encoder_get_name(obs_encoder_t encoder);
 /** Returns the codec of the encoder */
 EXPORT const char *obs_encoder_get_codec(obs_encoder_t encoder);
 
+/**
+ * Sets the scaled resolution for a video encoder.  Set width and height to 0
+ * to disable scaling.  If the encoder is active, this function will trigger
+ * a warning, and do nothing.
+ */
+EXPORT void obs_encoder_set_scaled_size(obs_encoder_t encoder, uint32_t width,
+		uint32_t height);
+
+/** For video encoders, returns the width of the encoded image */
+EXPORT uint32_t obs_encoder_get_width(obs_encoder_t encoder);
+
+/** For video encoders, returns the height of the encoded image */
+EXPORT uint32_t obs_encoder_get_height(obs_encoder_t encoder);
+
 /** Gets the default settings for an encoder type */
 EXPORT obs_data_t obs_encoder_defaults(const char *id);