Browse Source

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 10 years ago
parent
commit
ffc7b3c666
2 changed files with 27 additions and 14 deletions
  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 =