libobs: Fix another sync issue with encoder sharing

If audio buffering is very high, the audio packets built up in the
interleaved buffer would be significantly before the first video packet,
causing the offset between the starting video/audio packet pairs to be
significantly off, leading to desync.

This issue was not spotted until recently because it only happens when
streaming/recording with same encoders while audio buffering is very
high.
master
jp9000 2016-04-18 14:02:57 -07:00
parent bef1b37ae2
commit cbd13063c6
1 changed files with 40 additions and 0 deletions

View File

@ -1039,6 +1039,26 @@ static int find_first_packet_type_idx(struct obs_output *output,
return -1;
}
static int find_last_packet_type_idx(struct obs_output *output,
enum obs_encoder_type type, size_t audio_idx)
{
for (size_t i = output->interleaved_packets.num; i > 0; i--) {
struct encoder_packet *packet =
&output->interleaved_packets.array[i - 1];
if (packet->type == type) {
if (type == OBS_ENCODER_AUDIO &&
packet->track_idx != audio_idx) {
continue;
}
return (int)(i - 1);
}
}
return -1;
}
static inline struct encoder_packet *find_first_packet_type(
struct obs_output *output, enum obs_encoder_type type,
size_t audio_idx)
@ -1047,10 +1067,19 @@ static inline struct encoder_packet *find_first_packet_type(
return (idx != -1) ? &output->interleaved_packets.array[idx] : NULL;
}
static inline struct encoder_packet *find_last_packet_type(
struct obs_output *output, enum obs_encoder_type type,
size_t audio_idx)
{
int idx = find_last_packet_type_idx(output, type, audio_idx);
return (idx != -1) ? &output->interleaved_packets.array[idx] : NULL;
}
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);
video = find_first_packet_type(output, OBS_ENCODER_VIDEO, 0);
@ -1063,12 +1092,23 @@ static bool initialize_interleaved_packets(struct obs_output *output)
output->received_audio = false;
return false;
}
last_audio[i] = find_last_packet_type(output, OBS_ENCODER_AUDIO,
i);
}
if (!video) {
return false;
}
/* 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;
}
}
/* get new offsets */
output->video_offset = video->dts;
for (size_t i = 0; i < audio_mixes; i++)