Просмотр исходного кода

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

jp9000 7 лет назад
Родитель
Сommit
b8a3ae1b10
6 измененных файлов с 119 добавлено и 17 удалено
  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
    This is called when the output recieves raw audio data.  Only applies
    to outputs that are not encoded.
    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
    :param frames: The raw audio frames
 
 
 .. member:: void (*obs_output_info.encoded_packet)(void *data, struct encoder_packet *packet)
 .. 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)
 .. 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)
               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                   *video_encoder;
 	obs_encoder_t                   *audio_encoders[MAX_AUDIO_MIXES];
 	obs_encoder_t                   *audio_encoders[MAX_AUDIO_MIXES];
 	obs_service_t                   *service;
 	obs_service_t                   *service;
-	size_t                          mixer_idx;
+	size_t                          mixer_mask;
 
 
 	uint32_t                        scaled_width;
 	uint32_t                        scaled_width;
 	uint32_t                        scaled_height;
 	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,
 			CHECK_REQUIRED_VAL_(info, raw_video,
 					obs_register_output);
 					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_
 #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;
 		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)
 void obs_output_set_mixer(obs_output_t *output, size_t mixer_idx)
 {
 {
 	if (!obs_output_valid(output, "obs_output_set_mixer"))
 	if (!obs_output_valid(output, "obs_output_set_mixer"))
 		return;
 		return;
 
 
 	if (!active(output))
 	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)
 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,
 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++;
 	output->total_frames++;
 }
 }
 
 
+
 static void default_raw_audio_callback(void *param, size_t mix_idx,
 static void default_raw_audio_callback(void *param, size_t mix_idx,
 		struct audio_data *frames)
 		struct audio_data *frames)
 {
 {
@@ -1483,9 +1511,10 @@ static void default_raw_audio_callback(void *param, size_t mix_idx,
 	if (!data_active(output))
 	if (!data_active(output))
 		return;
 		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,
 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)
 static void reset_packet_data(obs_output_t *output)
 {
 {
 	output->received_audio   = false;
 	output->received_audio   = false;
@@ -1557,9 +1605,7 @@ static void hook_data_capture(struct obs_output *output, bool encoded,
 					get_video_conversion(output),
 					get_video_conversion(output),
 					default_raw_video_callback, output);
 					default_raw_video_callback, output);
 		if (has_audio)
 		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)
 static void *end_data_capture_thread(void *data)
 {
 {
 	bool encoded, has_video, has_audio, has_service;
 	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,
 			stop_raw_video(output->video,
 					default_raw_video_callback, output);
 					default_raw_video_callback, output);
 		if (has_audio)
 		if (has_audio)
-			audio_output_disconnect(output->audio,
-					output->mixer_idx,
-					default_raw_audio_callback, output);
+			stop_raw_audio(output);
 	}
 	}
 
 
 	if (has_service)
 	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 */
 	/* only used with encoded outputs, separated with semicolon */
 	const char *encoded_video_codecs;
 	const char *encoded_video_codecs;
 	const char *encoded_audio_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,
 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 */
 /** Gets the current audio mixer for non-encoded outputs */
 EXPORT size_t obs_output_get_mixer(const obs_output_t *output);
 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,
  * Sets the current video encoder associated with this output,
  * required for encoded outputs
  * required for encoded outputs