Browse Source

libobs: Add multi-track support to non-encoded outputs

jp9000 7 years ago
parent
commit
b8a3ae1b10
6 changed files with 119 additions and 17 deletions
  1. 25 1
      docs/sphinx/reference-outputs.rst
  2. 1 1
      libobs/obs-internal.h
  3. 9 3
      libobs/obs-module.c
  4. 75 12
      libobs/obs-output.c
  5. 3 0
      libobs/obs-output.h
  6. 6 0
      libobs/obs.h

+ 25 - 1
docs/sphinx/reference-outputs.rst

@@ -117,6 +117,18 @@ Output Definition Structure (obs_output_info)
    This is called when the output recieves raw audio data.  Only applies
    to outputs that are not encoded.
 
+   **This callback must be used with single-track raw outputs.**
+
+   :param frames: The raw audio frames
+
+.. member:: void (*obs_output_info.raw_audio2)(void *data, size_t idx, struct audio_data *frames)
+
+   This is called when the output recieves raw audio data.  Only applies
+   to outputs that are not encoded.
+
+   **This callback must be used with multi-track raw outputs.**
+
+   :param idx:    The audio track index
    :param frames: The raw audio frames
 
 .. member:: void (*obs_output_info.encoded_packet)(void *data, struct encoder_packet *packet)
@@ -472,7 +484,19 @@ General Output Functions
 .. function:: void obs_output_set_mixer(obs_output_t *output, size_t mixer_idx)
               size_t obs_output_get_mixer(const obs_output_t *output)
 
-   Sets/gets the current audio mixer for non-encoded outputs.
+   Sets/gets the current audio mixer for non-encoded outputs.  For
+   multi-track outputs, this would be the equivalent of setting the mask
+   only for the specified mixer index.
+
+---------------------
+
+.. function:: void obs_output_set_mixers(obs_output_t *output, size_t mixers)
+              size_t obs_output_get_mixers(const obs_output_t *output)
+
+   Sets/gets the current audio mixers (via mask) for non-encoded
+   multi-track outputs.  If used with single-track outputs, the
+   single-track output will use either the first set mixer track in the
+   bitmask, or the first track if none is set in the bitmask.
 
 ---------------------
 

+ 1 - 1
libobs/obs-internal.h

@@ -863,7 +863,7 @@ struct obs_output {
 	obs_encoder_t                   *video_encoder;
 	obs_encoder_t                   *audio_encoders[MAX_AUDIO_MIXES];
 	obs_service_t                   *service;
-	size_t                          mixer_idx;
+	size_t                          mixer_mask;
 
 	uint32_t                        scaled_width;
 	uint32_t                        scaled_height;

+ 9 - 3
libobs/obs-module.c

@@ -675,9 +675,15 @@ void obs_register_output_s(const struct obs_output_info *info, size_t size)
 			CHECK_REQUIRED_VAL_(info, raw_video,
 					obs_register_output);
 
-		if (info->flags & OBS_OUTPUT_AUDIO)
-			CHECK_REQUIRED_VAL_(info, raw_audio,
-					obs_register_output);
+		if (info->flags & OBS_OUTPUT_AUDIO) {
+			if (info->flags & OBS_OUTPUT_MULTI_TRACK) {
+				CHECK_REQUIRED_VAL_(info, raw_audio2,
+						obs_register_output);
+			} else {
+				CHECK_REQUIRED_VAL_(info, raw_audio,
+						obs_register_output);
+			}
+		}
 	}
 #undef CHECK_REQUIRED_VAL_
 

+ 75 - 12
libobs/obs-output.c

@@ -544,19 +544,46 @@ audio_t *obs_output_audio(const obs_output_t *output)
 		output->audio : NULL;
 }
 
+static inline size_t get_first_mixer(const obs_output_t *output)
+{
+	for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
+		if ((((size_t)1 << i) & output->mixer_mask) != 0) {
+			return i;
+		}
+	}
+
+	return 0;
+}
+
 void obs_output_set_mixer(obs_output_t *output, size_t mixer_idx)
 {
 	if (!obs_output_valid(output, "obs_output_set_mixer"))
 		return;
 
 	if (!active(output))
-		output->mixer_idx = mixer_idx;
+		output->mixer_mask = (size_t)1 << mixer_idx;
 }
 
 size_t obs_output_get_mixer(const obs_output_t *output)
 {
-	return obs_output_valid(output, "obs_output_get_mixer") ?
-		output->mixer_idx : 0;
+	if (!obs_output_valid(output, "obs_output_get_mixer"))
+		return 0;
+
+	return get_first_mixer(output);
+}
+
+void obs_output_set_mixers(obs_output_t *output, size_t mixers)
+{
+	if (!obs_output_valid(output, "obs_output_set_mixers"))
+		return;
+
+	output->mixer_mask = mixers;
+}
+
+size_t obs_output_get_mixers(const obs_output_t *output)
+{
+	return obs_output_valid(output, "obs_output_get_mixers") ?
+		output->mixer_mask : 0;
 }
 
 void obs_output_remove_encoder(struct obs_output *output,
@@ -1476,6 +1503,7 @@ static void default_raw_video_callback(void *param, struct video_data *frame)
 	output->total_frames++;
 }
 
+
 static void default_raw_audio_callback(void *param, size_t mix_idx,
 		struct audio_data *frames)
 {
@@ -1483,9 +1511,10 @@ static void default_raw_audio_callback(void *param, size_t mix_idx,
 	if (!data_active(output))
 		return;
 
-	output->info.raw_audio(output->context.data, frames);
-
-	UNUSED_PARAMETER(mix_idx);
+	if (output->info.raw_audio2)
+		output->info.raw_audio2(output->context.data, mix_idx, frames);
+	else
+		output->info.raw_audio(output->context.data, frames);
 }
 
 static inline void start_audio_encoders(struct obs_output *output,
@@ -1499,6 +1528,25 @@ static inline void start_audio_encoders(struct obs_output *output,
 	}
 }
 
+static inline void start_raw_audio(obs_output_t *output)
+{
+	if (output->info.raw_audio2) {
+		for (int idx = 0; idx < MAX_AUDIO_MIXES; idx++) {
+			if ((output->mixer_mask & ((size_t)1 << idx)) != 0) {
+				audio_output_connect(output->audio, idx,
+						get_audio_conversion(output),
+						default_raw_audio_callback,
+						output);
+			}
+		}
+	} else {
+		audio_output_connect(output->audio, get_first_mixer(output),
+				     get_audio_conversion(output),
+				     default_raw_audio_callback,
+				     output);
+	}
+}
+
 static void reset_packet_data(obs_output_t *output)
 {
 	output->received_audio   = false;
@@ -1557,9 +1605,7 @@ static void hook_data_capture(struct obs_output *output, bool encoded,
 					get_video_conversion(output),
 					default_raw_video_callback, output);
 		if (has_audio)
-			audio_output_connect(output->audio, output->mixer_idx,
-					get_audio_conversion(output),
-					default_raw_audio_callback, output);
+			start_raw_audio(output);
 	}
 }
 
@@ -1786,6 +1832,25 @@ static inline void stop_audio_encoders(obs_output_t *output,
 	}
 }
 
+static inline void stop_raw_audio(obs_output_t *output)
+{
+	if (output->info.raw_audio2) {
+		for (int idx = 0; idx < MAX_AUDIO_MIXES; idx++) {
+			if ((output->mixer_mask & ((size_t)1 << idx)) != 0) {
+				audio_output_disconnect(output->audio,
+						     idx,
+						     default_raw_audio_callback,
+						     output);
+			}
+		}
+	} else {
+		audio_output_disconnect(output->audio,
+				     get_first_mixer(output),
+				     default_raw_audio_callback,
+				     output);
+	}
+}
+
 static void *end_data_capture_thread(void *data)
 {
 	bool encoded, has_video, has_audio, has_service;
@@ -1812,9 +1877,7 @@ static void *end_data_capture_thread(void *data)
 			stop_raw_video(output->video,
 					default_raw_video_callback, output);
 		if (has_audio)
-			audio_output_disconnect(output->audio,
-					output->mixer_idx,
-					default_raw_audio_callback, output);
+			stop_raw_audio(output);
 	}
 
 	if (has_service)

+ 3 - 0
libobs/obs-output.h

@@ -71,6 +71,9 @@ struct obs_output_info {
 	/* only used with encoded outputs, separated with semicolon */
 	const char *encoded_video_codecs;
 	const char *encoded_audio_codecs;
+
+	/* raw audio callback for multi track outputs */
+	void (*raw_audio2)(void *data, size_t idx, struct audio_data *frames);
 };
 
 EXPORT void obs_register_output_s(const struct obs_output_info *info,

+ 6 - 0
libobs/obs.h

@@ -1632,6 +1632,12 @@ EXPORT void obs_output_set_mixer(obs_output_t *output, size_t mixer_idx);
 /** Gets the current audio mixer for non-encoded outputs */
 EXPORT size_t obs_output_get_mixer(const obs_output_t *output);
 
+/** Sets the current audio mixes (mask) for a non-encoded multi-track output */
+EXPORT void obs_output_set_mixers(obs_output_t *output, size_t mixers);
+
+/** Gets the current audio mixes (mask) for a non-encoded multi-track output */
+EXPORT size_t obs_output_get_mixers(const obs_output_t *output);
+
 /**
  * Sets the current video encoder associated with this output,
  * required for encoded outputs