Explorar o código

libobs: Fix multi. video encoder sync issues

When using multiple video encoders together with a single audio encoder,
the audio wouldn't be in sync.

The reason why this occurred is because the dts_usec variable of the
encoder packet (which is based on system time) would always be reset to
a value based upon the dts (which is not guaranteed to be based on
system time) in the apply_interleaved_packet_offset function.  This
would then in turn cause it to miscalculate the starting audio/video
offsets, which are required to calculate sync.

So instead of calling that function unnecessarily, separate the check
for whether audio/video has been received in to a new function, and only
start applying the interleaved offsets after audio and video have
actually started up and the starting offsets have been calculated.
jp9000 %!s(int64=11) %!d(string=hai) anos
pai
achega
ffc7b3c666
Modificáronse 2 ficheiros con 27 adicións e 14 borrados
  1. 4 1
      libobs/obs-encoder.c
  2. 23 13
      libobs/obs-output.c

+ 4 - 1
libobs/obs-encoder.c

@@ -671,7 +671,7 @@ static bool buffer_audio(struct obs_encoder *encoder, struct audio_data *data)
 	size_t size = data->frames * encoder->blocksize;
 	size_t offset_size = 0;
 
-	if (encoder->paired_encoder && !encoder->start_ts) {
+	if (!encoder->start_ts && encoder->paired_encoder) {
 		uint64_t end_ts     = data->timestamp;
 		uint64_t v_start_ts = encoder->paired_encoder->start_ts;
 
@@ -693,6 +693,9 @@ static bool buffer_audio(struct obs_encoder *encoder, struct audio_data *data)
 		}
 
 		encoder->start_ts = v_start_ts;
+
+	} else if (!encoder->start_ts && !encoder->paired_encoder) {
+		encoder->start_ts = data->timestamp;
 	}
 
 	size -= offset_size;

+ 23 - 13
libobs/obs-output.c

@@ -677,26 +677,29 @@ static size_t get_track_index(const struct obs_output *output,
 	return 0;
 }
 
-static void apply_interleaved_packet_offset(struct obs_output *output,
+static inline void check_received(struct obs_output *output,
 		struct encoder_packet *out)
 {
-	int64_t offset;
-
-	/* audio and video need to start at timestamp 0, and the encoders
-	 * may not currently be at 0 when we get data.  so, we store the
-	 * current dts as offset and subtract that value from the dts/pts
-	 * of the output packet. */
 	if (out->type == OBS_ENCODER_VIDEO) {
 		if (!output->received_video)
 			output->received_video = true;
-
-		offset = output->video_offset;
 	} else {
 		if (!output->received_audio)
 			output->received_audio = true;
-
-		offset = output->audio_offsets[out->track_idx];
 	}
+}
+
+static inline void apply_interleaved_packet_offset(struct obs_output *output,
+		struct encoder_packet *out)
+{
+	int64_t offset;
+
+	/* audio and video need to start at timestamp 0, and the encoders
+	 * may not currently be at 0 when we get data.  so, we store the
+	 * current dts as offset and subtract that value from the dts/pts
+	 * of the output packet. */
+	offset = (out->type == OBS_ENCODER_VIDEO) ?
+		output->video_offset : output->audio_offsets[out->track_idx];
 
 	out->dts -= offset;
 	out->pts -= offset;
@@ -896,7 +899,12 @@ static void interleave_packets(void *data, struct encoder_packet *packet)
 	was_started = output->received_audio && output->received_video;
 
 	obs_duplicate_encoder_packet(&out, packet);
-	apply_interleaved_packet_offset(output, &out);
+
+	if (was_started)
+		apply_interleaved_packet_offset(output, &out);
+	else
+		check_received(output, packet);
+
 	insert_interleaved_packet(output, &out);
 	set_higher_ts(output, &out);
 
@@ -1078,7 +1086,9 @@ static inline bool pair_encoders(obs_output_t *output, size_t num_mixes)
 {
 	if (num_mixes == 1 &&
 	    !output->audio_encoders[0]->active &&
-	    !output->video_encoder->active) {
+	    !output->video_encoder->active &&
+	    !output->video_encoder->paired_encoder &&
+	    !output->audio_encoders[0]->paired_encoder) {
 
 		output->audio_encoders[0]->wait_for_video = true;
 		output->audio_encoders[0]->paired_encoder =