Browse Source

libobs: Refactor obs-output encoded use of mixes

There was quite a bit of conflated usage of mixes (which refers
to raw audio) and encoder counts. This fully separates the two
and makes a distinct separation when iterating over mixes vs
encoders.
John Bradley 2 years ago
parent
commit
61284cf9ba
3 changed files with 108 additions and 113 deletions
  1. 2 2
      libobs/obs-internal.h
  2. 104 111
      libobs/obs-output.c
  3. 2 0
      libobs/obs-output.h

+ 2 - 2
libobs/obs-internal.h

@@ -1024,7 +1024,7 @@ struct obs_output {
 	volatile bool data_active;
 	volatile bool end_data_capture_thread_active;
 	int64_t video_offset;
-	int64_t audio_offsets[MAX_AUDIO_MIXES];
+	int64_t audio_offsets[MAX_OUTPUT_AUDIO_ENCODERS];
 	int64_t highest_audio_ts;
 	int64_t highest_video_ts;
 	pthread_t end_data_capture_thread;
@@ -1054,7 +1054,7 @@ struct obs_output {
 	video_t *video;
 	audio_t *audio;
 	obs_encoder_t *video_encoder;
-	obs_encoder_t *audio_encoders[MAX_AUDIO_MIXES];
+	obs_encoder_t *audio_encoders[MAX_OUTPUT_AUDIO_ENCODERS];
 	obs_service_t *service;
 	size_t mixer_mask;
 

+ 104 - 111
libobs/obs-output.c

@@ -180,7 +180,7 @@ static inline void free_packets(struct obs_output *output)
 	da_free(output->interleaved_packets);
 }
 
-static inline void clear_audio_buffers(obs_output_t *output)
+static inline void clear_raw_audio_buffers(obs_output_t *output)
 {
 	for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
 		for (size_t j = 0; j < MAX_AV_PLANES; j++) {
@@ -215,14 +215,14 @@ void obs_output_destroy(obs_output_t *output)
 						  output);
 		}
 
-		for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
+		for (size_t i = 0; i < MAX_OUTPUT_AUDIO_ENCODERS; i++) {
 			if (output->audio_encoders[i]) {
 				obs_encoder_remove_output(
 					output->audio_encoders[i], output);
 			}
 		}
 
-		clear_audio_buffers(output);
+		clear_raw_audio_buffers(output);
 
 		os_event_destroy(output->stopping_event);
 		pthread_mutex_destroy(&output->pause.mutex);
@@ -572,16 +572,16 @@ static inline bool pause_can_stop(struct pause_data *pause)
 static bool obs_encoded_output_pause(obs_output_t *output, bool pause)
 {
 	obs_encoder_t *venc;
-	obs_encoder_t *aenc[MAX_AUDIO_MIXES];
+	obs_encoder_t *aenc[MAX_OUTPUT_AUDIO_ENCODERS];
 	uint64_t closest_v_ts;
 	bool success = false;
 
 	venc = output->video_encoder;
-	for (size_t i = 0; i < MAX_AUDIO_MIXES; i++)
+	for (size_t i = 0; i < MAX_OUTPUT_AUDIO_ENCODERS; i++)
 		aenc[i] = output->audio_encoders[i];
 
 	pthread_mutex_lock(&venc->pause.mutex);
-	for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
+	for (size_t i = 0; i < MAX_OUTPUT_AUDIO_ENCODERS; i++) {
 		if (aenc[i]) {
 			pthread_mutex_lock(&aenc[i]->pause.mutex);
 		}
@@ -595,7 +595,7 @@ static bool obs_encoded_output_pause(obs_output_t *output, bool pause)
 		if (!pause_can_start(&venc->pause)) {
 			goto fail;
 		}
-		for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
+		for (size_t i = 0; i < MAX_OUTPUT_AUDIO_ENCODERS; i++) {
 			if (aenc[i] && !pause_can_start(&aenc[i]->pause)) {
 				goto fail;
 			}
@@ -604,7 +604,7 @@ static bool obs_encoded_output_pause(obs_output_t *output, bool pause)
 		os_atomic_set_bool(&venc->paused, true);
 		venc->pause.ts_start = closest_v_ts;
 
-		for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
+		for (size_t i = 0; i < MAX_OUTPUT_AUDIO_ENCODERS; i++) {
 			if (aenc[i]) {
 				os_atomic_set_bool(&aenc[i]->paused, true);
 				aenc[i]->pause.ts_start = closest_v_ts;
@@ -614,7 +614,7 @@ static bool obs_encoded_output_pause(obs_output_t *output, bool pause)
 		if (!pause_can_stop(&venc->pause)) {
 			goto fail;
 		}
-		for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
+		for (size_t i = 0; i < MAX_OUTPUT_AUDIO_ENCODERS; i++) {
 			if (aenc[i] && !pause_can_stop(&aenc[i]->pause)) {
 				goto fail;
 			}
@@ -623,7 +623,7 @@ static bool obs_encoded_output_pause(obs_output_t *output, bool pause)
 		os_atomic_set_bool(&venc->paused, false);
 		end_pause(&venc->pause, closest_v_ts);
 
-		for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
+		for (size_t i = 0; i < MAX_OUTPUT_AUDIO_ENCODERS; i++) {
 			if (aenc[i]) {
 				os_atomic_set_bool(&aenc[i]->paused, false);
 				end_pause(&aenc[i]->pause, closest_v_ts);
@@ -636,7 +636,7 @@ static bool obs_encoded_output_pause(obs_output_t *output, bool pause)
 	success = true;
 
 fail:
-	for (size_t i = MAX_AUDIO_MIXES; i > 0; i--) {
+	for (size_t i = MAX_OUTPUT_AUDIO_ENCODERS; i > 0; i--) {
 		if (aenc[i - 1]) {
 			pthread_mutex_unlock(&aenc[i - 1]->pause.mutex);
 		}
@@ -801,8 +801,9 @@ void obs_output_remove_encoder_internal(struct obs_output *output,
 	if (output->video_encoder == encoder) {
 		output->video_encoder = NULL;
 	} else {
-		for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
-			if (output->audio_encoders[i] == encoder)
+		for (size_t i = 0; i < MAX_OUTPUT_AUDIO_ENCODERS; i++) {
+			obs_encoder_t *audio = output->audio_encoders[i];
+			if (audio == encoder)
 				output->audio_encoders[i] = NULL;
 		}
 	}
@@ -870,7 +871,7 @@ void obs_output_set_audio_encoder(obs_output_t *output, obs_encoder_t *encoder,
 	}
 
 	if ((output->info.flags & OBS_OUTPUT_MULTI_TRACK) != 0) {
-		if (idx >= MAX_AUDIO_MIXES) {
+		if (idx >= MAX_OUTPUT_AUDIO_ENCODERS) {
 			return;
 		}
 	} else {
@@ -900,15 +901,8 @@ obs_encoder_t *obs_output_get_audio_encoder(const obs_output_t *output,
 	if (!obs_output_valid(output, "obs_output_get_audio_encoder"))
 		return NULL;
 
-	if ((output->info.flags & OBS_OUTPUT_MULTI_TRACK) != 0) {
-		if (idx >= MAX_AUDIO_MIXES) {
-			return NULL;
-		}
-	} else {
-		if (idx > 0) {
-			return NULL;
-		}
-	}
+	if (idx >= MAX_OUTPUT_AUDIO_ENCODERS)
+		return NULL;
 
 	return output->audio_encoders[idx];
 }
@@ -1054,42 +1048,18 @@ void obs_output_set_audio_conversion(
 	output->audio_conversion_set = true;
 }
 
-static inline size_t num_audio_mixes(const struct obs_output *output)
-{
-	size_t mix_count = 1;
-
-	if ((output->info.flags & OBS_OUTPUT_MULTI_TRACK) != 0) {
-		mix_count = 0;
-
-		for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
-			if (!output->audio_encoders[i])
-				break;
-
-			mix_count++;
-		}
-	}
-
-	return mix_count;
-}
-
 static inline bool audio_valid(const struct obs_output *output, bool encoded)
 {
 	if (encoded) {
-		size_t mix_count = num_audio_mixes(output);
-		if (!mix_count)
-			return false;
-
-		for (size_t i = 0; i < mix_count; i++) {
-			if (!output->audio_encoders[i]) {
-				return false;
+		for (size_t i = 0; i < MAX_OUTPUT_AUDIO_ENCODERS; i++) {
+			if (output->audio_encoders[i]) {
+				return true;
 			}
 		}
-	} else {
-		if (!output->audio)
-			return false;
+		return false;
 	}
 
-	return true;
+	return output->audio != NULL;
 }
 
 static bool can_begin_data_capture(const struct obs_output *output,
@@ -1166,10 +1136,10 @@ get_audio_conversion(struct obs_output *output)
 static size_t get_track_index(const struct obs_output *output,
 			      struct encoder_packet *pkt)
 {
-	for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
+	for (size_t i = 0; i < MAX_OUTPUT_AUDIO_ENCODERS; i++) {
 		struct obs_encoder *encoder = output->audio_encoders[i];
 
-		if (pkt->encoder == encoder)
+		if (encoder && pkt->encoder == encoder)
 			return i;
 	}
 
@@ -1420,7 +1390,6 @@ static size_t get_interleaved_start_idx(struct obs_output *output)
 
 static int prune_premature_packets(struct obs_output *output)
 {
-	size_t audio_mixes = num_audio_mixes(output);
 	struct encoder_packet *video;
 	int video_idx;
 	int max_idx;
@@ -1438,10 +1407,13 @@ static int prune_premature_packets(struct obs_output *output)
 	video = &output->interleaved_packets.array[video_idx];
 	duration_usec = video->timebase_num * 1000000LL / video->timebase_den;
 
-	for (size_t i = 0; i < audio_mixes; i++) {
+	for (size_t i = 0; i < MAX_OUTPUT_AUDIO_ENCODERS; i++) {
 		struct encoder_packet *audio;
 		int audio_idx;
 
+		if (!output->audio_encoders[i])
+			continue;
+
 		audio_idx = find_first_packet_type_idx(output,
 						       OBS_ENCODER_AUDIO, i);
 		if (audio_idx == -1) {
@@ -1565,18 +1537,20 @@ find_last_packet_type(struct obs_output *output, enum obs_encoder_type type,
 
 static bool get_audio_and_video_packets(struct obs_output *output,
 					struct encoder_packet **video,
-					struct encoder_packet **audio,
-					size_t audio_mixes)
+					struct encoder_packet **audio)
 {
 	*video = find_first_packet_type(output, OBS_ENCODER_VIDEO, 0);
 	if (!*video)
 		output->received_video = false;
 
-	for (size_t i = 0; i < audio_mixes; i++) {
-		audio[i] = find_first_packet_type(output, OBS_ENCODER_AUDIO, i);
-		if (!audio[i]) {
-			output->received_audio = false;
-			return false;
+	for (size_t i = 0; i < MAX_OUTPUT_AUDIO_ENCODERS; i++) {
+		if (output->audio_encoders[i]) {
+			audio[i] = find_first_packet_type(output,
+							  OBS_ENCODER_AUDIO, i);
+			if (!audio[i]) {
+				output->received_audio = false;
+				return false;
+			}
 		}
 	}
 
@@ -1587,26 +1561,50 @@ static bool get_audio_and_video_packets(struct obs_output *output,
 	return true;
 }
 
+static bool get_first_audio_encoder_index(const struct obs_output *output,
+					  size_t *index)
+{
+	if (!index)
+		return false;
+
+	for (size_t i = 0; i < MAX_OUTPUT_AUDIO_ENCODERS; i++) {
+		if (output->audio_encoders[i]) {
+			*index = i;
+			return true;
+		}
+	}
+
+	return false;
+}
+
 static bool initialize_interleaved_packets(struct obs_output *output)
 {
 	struct encoder_packet *video;
-	struct encoder_packet *audio[MAX_AUDIO_MIXES];
-	struct encoder_packet *last_audio[MAX_AUDIO_MIXES];
-	size_t audio_mixes = num_audio_mixes(output);
+	struct encoder_packet *audio[MAX_OUTPUT_AUDIO_ENCODERS];
+	struct encoder_packet *last_audio[MAX_OUTPUT_AUDIO_ENCODERS];
 	size_t start_idx;
+	size_t first_audio_idx;
 
-	if (!get_audio_and_video_packets(output, &video, audio, audio_mixes))
+	if (!get_first_audio_encoder_index(output, &first_audio_idx))
 		return false;
 
-	for (size_t i = 0; i < audio_mixes; i++)
-		last_audio[i] =
-			find_last_packet_type(output, OBS_ENCODER_AUDIO, i);
+	if (!get_audio_and_video_packets(output, &video, audio))
+		return false;
+
+	for (size_t i = 0; i < MAX_OUTPUT_AUDIO_ENCODERS; i++) {
+		if (output->audio_encoders[i]) {
+			last_audio[i] = find_last_packet_type(
+				output, OBS_ENCODER_AUDIO, i);
+		}
+	}
 
 	/* ensure that there is audio past the first video packet */
-	for (size_t i = 0; i < audio_mixes; i++) {
-		if (last_audio[i]->dts_usec < video->dts_usec) {
-			output->received_audio = false;
-			return false;
+	for (size_t i = 0; i < MAX_OUTPUT_AUDIO_ENCODERS; i++) {
+		if (output->audio_encoders[i]) {
+			if (last_audio[i]->dts_usec < video->dts_usec) {
+				output->received_audio = false;
+				return false;
+			}
 		}
 	}
 
@@ -1614,19 +1612,20 @@ static bool initialize_interleaved_packets(struct obs_output *output)
 	start_idx = get_interleaved_start_idx(output);
 	if (start_idx) {
 		discard_to_idx(output, start_idx);
-		if (!get_audio_and_video_packets(output, &video, audio,
-						 audio_mixes))
+		if (!get_audio_and_video_packets(output, &video, audio))
 			return false;
 	}
 
 	/* get new offsets */
 	output->video_offset = video->pts;
-	for (size_t i = 0; i < audio_mixes; i++)
-		output->audio_offsets[i] = audio[i]->dts;
-
+	for (size_t i = 0; i < MAX_OUTPUT_AUDIO_ENCODERS; i++) {
+		if (output->audio_encoders[i]) {
+			output->audio_offsets[i] = audio[i]->dts;
+		}
+	}
 #if DEBUG_STARTING_PACKETS == 1
 	int64_t v = video->dts_usec;
-	int64_t a = audio[0]->dts_usec;
+	int64_t a = audio[first_audio_idx]->dts_usec;
 	int64_t diff = v - a;
 
 	blog(LOG_DEBUG,
@@ -1636,7 +1635,7 @@ static bool initialize_interleaved_packets(struct obs_output *output)
 #endif
 
 	/* subtract offsets from highest TS offset variables */
-	output->highest_audio_ts -= audio[0]->dts_usec;
+	output->highest_audio_ts -= audio[first_audio_idx]->dts_usec;
 	output->highest_video_ts -= video->dts_usec;
 
 	/* apply new offsets to all existing packet DTS/PTS values */
@@ -1885,11 +1884,11 @@ static void default_raw_audio_callback(void *param, size_t mix_idx,
 static inline void start_audio_encoders(struct obs_output *output,
 					encoded_callback_t encoded_callback)
 {
-	size_t num_mixes = num_audio_mixes(output);
-
-	for (size_t i = 0; i < num_mixes; i++) {
-		obs_encoder_start(output->audio_encoders[i], encoded_callback,
-				  output);
+	for (size_t i = 0; i < MAX_OUTPUT_AUDIO_ENCODERS; i++) {
+		if (output->audio_encoders[i]) {
+			obs_encoder_start(output->audio_encoders[i],
+					  encoded_callback, output);
+		}
 	}
 }
 
@@ -1919,7 +1918,7 @@ static void reset_packet_data(obs_output_t *output)
 	output->highest_video_ts = 0;
 	output->video_offset = 0;
 
-	for (size_t i = 0; i < MAX_AUDIO_MIXES; i++)
+	for (size_t i = 0; i < MAX_OUTPUT_AUDIO_ENCODERS; i++)
 		output->audio_offsets[i] = 0;
 
 	free_packets(output);
@@ -2049,14 +2048,14 @@ bool obs_output_can_begin_data_capture(const obs_output_t *output,
 				      has_service);
 }
 
-static inline bool initialize_audio_encoders(obs_output_t *output,
-					     size_t num_mixes)
+static inline bool initialize_audio_encoders(obs_output_t *output)
 {
-	for (size_t i = 0; i < num_mixes; i++) {
-		if (!obs_encoder_initialize(output->audio_encoders[i])) {
+	for (size_t i = 0; i < MAX_OUTPUT_AUDIO_ENCODERS; i++) {
+		obs_encoder_t *audio = output->audio_encoders[i];
+
+		if (audio && !obs_encoder_initialize(audio)) {
 			obs_output_set_last_error(
-				output, obs_encoder_get_last_error(
-						output->audio_encoders[i]));
+				output, obs_encoder_get_last_error(audio));
 			return false;
 		}
 	}
@@ -2064,10 +2063,9 @@ static inline bool initialize_audio_encoders(obs_output_t *output,
 	return true;
 }
 
-static inline obs_encoder_t *find_inactive_audio_encoder(obs_output_t *output,
-							 size_t num_mixes)
+static inline obs_encoder_t *find_inactive_audio_encoder(obs_output_t *output)
 {
-	for (size_t i = 0; i < num_mixes; i++) {
+	for (size_t i = 0; i < MAX_OUTPUT_AUDIO_ENCODERS; i++) {
 		struct obs_encoder *audio = output->audio_encoders[i];
 
 		if (audio && !audio->active && !audio->paired_encoder)
@@ -2077,11 +2075,10 @@ static inline obs_encoder_t *find_inactive_audio_encoder(obs_output_t *output,
 	return NULL;
 }
 
-static inline void pair_encoders(obs_output_t *output, size_t num_mixes)
+static inline void pair_encoders(obs_output_t *output)
 {
 	struct obs_encoder *video = output->video_encoder;
-	struct obs_encoder *audio =
-		find_inactive_audio_encoder(output, num_mixes);
+	struct obs_encoder *audio = find_inactive_audio_encoder(output);
 
 	if (video && audio) {
 		pthread_mutex_lock(&audio->init_mutex);
@@ -2103,7 +2100,6 @@ static inline void pair_encoders(obs_output_t *output, size_t num_mixes)
 bool obs_output_initialize_encoders(obs_output_t *output, uint32_t flags)
 {
 	bool encoded, has_video, has_audio, has_service;
-	size_t num_mixes = num_audio_mixes(output);
 
 	if (!obs_output_valid(output, "obs_output_initialize_encoders"))
 		return false;
@@ -2122,7 +2118,7 @@ bool obs_output_initialize_encoders(obs_output_t *output, uint32_t flags)
 			obs_encoder_get_last_error(output->video_encoder));
 		return false;
 	}
-	if (has_audio && !initialize_audio_encoders(output, num_mixes))
+	if (has_audio && !initialize_audio_encoders(output))
 		return false;
 
 	return true;
@@ -2150,7 +2146,7 @@ static bool begin_delayed_capture(obs_output_t *output)
 
 static void reset_raw_output(obs_output_t *output)
 {
-	clear_audio_buffers(output);
+	clear_raw_audio_buffers(output);
 
 	if (output->audio) {
 		const struct audio_output_info *aoi =
@@ -2187,7 +2183,6 @@ static void reset_raw_output(obs_output_t *output)
 bool obs_output_begin_data_capture(obs_output_t *output, uint32_t flags)
 {
 	bool encoded, has_video, has_audio, has_service;
-	size_t num_mixes;
 
 	if (!obs_output_valid(output, "obs_output_begin_data_capture"))
 		return false;
@@ -2210,9 +2205,8 @@ bool obs_output_begin_data_capture(obs_output_t *output, uint32_t flags)
 				    has_service))
 		return false;
 
-	num_mixes = num_audio_mixes(output);
 	if (has_video && has_audio)
-		pair_encoders(output, num_mixes);
+		pair_encoders(output);
 
 	os_atomic_set_bool(&output->data_active, true);
 	hook_data_capture(output, encoded, has_video, has_audio);
@@ -2240,11 +2234,10 @@ bool obs_output_begin_data_capture(obs_output_t *output, uint32_t flags)
 static inline void stop_audio_encoders(obs_output_t *output,
 				       encoded_callback_t encoded_callback)
 {
-	size_t num_mixes = num_audio_mixes(output);
-
-	for (size_t i = 0; i < num_mixes; i++) {
-		obs_encoder_stop(output->audio_encoders[i], encoded_callback,
-				 output);
+	for (size_t i = 0; i < MAX_OUTPUT_AUDIO_ENCODERS; i++) {
+		obs_encoder_t *audio = output->audio_encoders[i];
+		if (audio)
+			obs_encoder_stop(audio, encoded_callback, output);
 	}
 }
 
@@ -2650,7 +2643,7 @@ const char *obs_output_get_last_error(obs_output_t *output)
 			return vencoder->last_error_message;
 		}
 
-		for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
+		for (size_t i = 0; i < MAX_OUTPUT_AUDIO_ENCODERS; i++) {
 			obs_encoder_t *aencoder = output->audio_encoders[i];
 			if (aencoder && aencoder->last_error_message) {
 				return aencoder->last_error_message;

+ 2 - 0
libobs/obs-output.h

@@ -29,6 +29,8 @@ extern "C" {
 #define OBS_OUTPUT_MULTI_TRACK (1 << 4)
 #define OBS_OUTPUT_CAN_PAUSE (1 << 5)
 
+#define MAX_OUTPUT_AUDIO_ENCODERS 6
+
 struct encoder_packet;
 
 struct obs_output_info {