mirror of
https://github.com/obsproject/obs-studio.git
synced 2026-09-25 07:50:39 -05:00
libobs: Reduce synchronization limit for multiple audio tracks
Since65eb3c0815we tried to get as close a sync between audio and video tracks as we could before starting to send frames to the output. But inbe717dbb2cwhen multi-track audio was considered for synchronization it continued to try and line ALL audio packets up with one video packet. While audio and video packets are similar size this will work out. But once video packets duration is smaller than 1/2 audio packet duration this may fail forever. In practice with AAC's 20-23ms frame duration we can often get tracks producing frames 5-10ms out of phase. For 60fps video this mostly fine as 16ms frame duration will cover the gap, but for framerates as low as 100 its possible to fail to synchronize. In practice this is ~50% for 6 audio tracks and 120fps video on my system, or 100% at 240fps.
This commit is contained in:
+25
-1
@@ -1388,14 +1388,21 @@ static size_t get_interleaved_start_idx(struct obs_output *output)
|
||||
return video_idx < idx ? video_idx : idx;
|
||||
}
|
||||
|
||||
static int64_t get_encoder_duration(struct obs_encoder *encoder)
|
||||
{
|
||||
return (encoder->timebase_num * 1000000LL / encoder->timebase_den) *
|
||||
encoder->framesize;
|
||||
}
|
||||
|
||||
static int prune_premature_packets(struct obs_output *output)
|
||||
{
|
||||
struct encoder_packet *video;
|
||||
int video_idx;
|
||||
int max_idx;
|
||||
int64_t duration_usec;
|
||||
int64_t duration_usec, max_audio_duration_usec = 0;
|
||||
int64_t max_diff = 0;
|
||||
int64_t diff = 0;
|
||||
int audio_encoders = 0;
|
||||
|
||||
video_idx = find_first_packet_type_idx(output, OBS_ENCODER_VIDEO, 0);
|
||||
if (video_idx == -1) {
|
||||
@@ -1410,9 +1417,11 @@ static int prune_premature_packets(struct obs_output *output)
|
||||
for (size_t i = 0; i < MAX_OUTPUT_AUDIO_ENCODERS; i++) {
|
||||
struct encoder_packet *audio;
|
||||
int audio_idx;
|
||||
int64_t audio_duration_usec = 0;
|
||||
|
||||
if (!output->audio_encoders[i])
|
||||
continue;
|
||||
audio_encoders++;
|
||||
|
||||
audio_idx = find_first_packet_type_idx(output,
|
||||
OBS_ENCODER_AUDIO, i);
|
||||
@@ -1428,6 +1437,21 @@ static int prune_premature_packets(struct obs_output *output)
|
||||
diff = audio->dts_usec - video->dts_usec;
|
||||
if (diff > max_diff)
|
||||
max_diff = diff;
|
||||
|
||||
audio_duration_usec =
|
||||
get_encoder_duration(output->audio_encoders[i]);
|
||||
if (audio_duration_usec > max_audio_duration_usec)
|
||||
max_audio_duration_usec = audio_duration_usec;
|
||||
}
|
||||
|
||||
/* Once multiple audio encoders are running they are almost always out
|
||||
* of phase by ~Xms. If users change their video to > 100fps then it
|
||||
* becomes probable that this phase difference will be larger than the
|
||||
* video duration preventing us from ever finding a synchronization
|
||||
* point due to their larger frame duration. Instead give up on a tight
|
||||
* video sync. */
|
||||
if (audio_encoders > 1 && duration_usec < max_audio_duration_usec) {
|
||||
duration_usec = max_audio_duration_usec;
|
||||
}
|
||||
|
||||
return diff > duration_usec ? max_idx + 1 : 0;
|
||||
|
||||
Reference in New Issue
Block a user