1
0
Эх сурвалжийг харах

libobs: Consider multi-track audio when pruning packets

In a multi-track scenario it was not taking in to consideration the
possibility of secondary audio tracks, which could have caused desync on
some of the audio tracks.
jp9000 9 жил өмнө
parent
commit
be717dbb2c
1 өөрчлөгдсөн 49 нэмэгдсэн , 21 устгасан
  1. 49 21
      libobs/obs-output.c

+ 49 - 21
libobs/obs-output.c

@@ -932,26 +932,47 @@ static size_t get_interleaved_start_idx(struct obs_output *output)
 	return video_idx < idx ? video_idx : idx;
 }
 
-static bool prune_premature_video_packet(struct obs_output *output)
+static int prune_premature_packets(struct obs_output *output)
 {
-	struct encoder_packet *packet;
-	struct encoder_packet *next;
+	size_t audio_mixes = num_audio_mixes(output);
+	struct encoder_packet *video;
+	int video_idx;
+	int max_idx;
 	int64_t duration_usec;
+	int64_t max_diff = 0;
 	int64_t diff;
 
-	if (output->interleaved_packets.num < 2)
-		return false;
+	video_idx = find_first_packet_type_idx(output, OBS_ENCODER_VIDEO, 0);
+	if (video_idx == -1) {
+		output->received_video = false;
+		return -1;
+	}
 
-	packet = &output->interleaved_packets.array[0];
+	max_idx = video_idx;
+	video = &output->interleaved_packets.array[video_idx];
+	duration_usec = video->timebase_num * 1000000LL / video->timebase_den;
 
-	if (packet->type == OBS_ENCODER_AUDIO)
-		return false;
+	for (size_t i = 0; i < audio_mixes; i++) {
+		struct encoder_packet *audio;
+		int audio_idx;
 
-	next = &output->interleaved_packets.array[1];
-	diff = next->dts_usec - packet->dts_usec;
-	duration_usec = packet->timebase_num * 1000000LL / packet->timebase_den;
+		audio_idx = find_first_packet_type_idx(output,
+				OBS_ENCODER_AUDIO, i);
+		if (audio_idx == -1) {
+			output->received_audio = false;
+			return -1;
+		}
+
+		audio = &output->interleaved_packets.array[audio_idx];
+		if (audio_idx > max_idx)
+			max_idx = audio_idx;
+
+		diff = audio->dts_usec - video->dts_usec;
+		if (diff > max_diff)
+			max_diff = diff;
+	}
 
-	return diff > duration_usec;
+	return diff > duration_usec ? max_idx + 1 : 0;
 }
 
 static void discard_to_idx(struct obs_output *output, size_t idx)
@@ -967,29 +988,35 @@ static void discard_to_idx(struct obs_output *output, size_t idx)
 
 #define DEBUG_STARTING_PACKETS 0
 
-static void prune_interleaved_packets(struct obs_output *output)
+static bool prune_interleaved_packets(struct obs_output *output)
 {
 	size_t start_idx = 0;
+	int prune_start = prune_premature_packets(output);
 
 #if DEBUG_STARTING_PACKETS == 1
 	blog(LOG_DEBUG, "--------- Pruning! ---------");
 	for (size_t i = 0; i < output->interleaved_packets.num; i++) {
 		struct encoder_packet *packet =
 			&output->interleaved_packets.array[i];
-		blog(LOG_DEBUG, "packet: %s, ts: %lld",
+		blog(LOG_DEBUG, "packet: %s %d, ts: %lld",
 				packet->type == OBS_ENCODER_AUDIO ?
-				"audio" : "video", packet->dts_usec);
+				"audio" : "video", (int)packet->track_idx,
+				packet->dts_usec);
 	}
 #endif
 
 	/* prunes the first video packet if it's too far away from audio */
-	if (prune_premature_video_packet(output))
-		start_idx++;
+	if (prune_start == -1)
+		return false;
+	else if (prune_start != 0)
+		start_idx = (size_t)prune_start;
 	else
 		start_idx = get_interleaved_start_idx(output);
 
 	if (start_idx)
 		discard_to_idx(output, start_idx);
+
+	return true;
 }
 
 static int find_first_packet_type_idx(struct obs_output *output,
@@ -1156,10 +1183,11 @@ static void interleave_packets(void *data, struct encoder_packet *packet)
 	 * to start sending out packets (one at a time) */
 	if (output->received_audio && output->received_video) {
 		if (!was_started) {
-			prune_interleaved_packets(output);
-			if (initialize_interleaved_packets(output)) {
-				resort_interleaved_packets(output);
-				send_interleaved(output);
+			if (prune_interleaved_packets(output)) {
+				if (initialize_interleaved_packets(output)) {
+					resort_interleaved_packets(output);
+					send_interleaved(output);
+				}
 			}
 		} else {
 			send_interleaved(output);