obs-ffmpeg: Split file by PTS instead of DTS

If B-frame is enabled in video encoder, video packets have different PTS
and DTS, however audio packets do not. That caused audio packets at the
splitting point goes to a different file and audio glitch appeared in an
NLE.
This commit is contained in:
Norihiro Kamae 2021-12-11 21:46:10 +09:00
parent 550b1331ac
commit 61c0a76fc0
2 changed files with 56 additions and 2 deletions

View File

@ -320,6 +320,11 @@ inline static void ts_offset_clear(struct ffmpeg_muxer *stream)
}
}
static inline int64_t packet_pts_usec(struct encoder_packet *packet)
{
return packet->pts * 1000000 / packet->timebase_den;
}
inline static void ts_offset_update(struct ffmpeg_muxer *stream,
struct encoder_packet *packet)
{
@ -731,6 +736,19 @@ static bool prepare_split_file(struct ffmpeg_muxer *stream,
return true;
}
static inline bool has_audio(struct ffmpeg_muxer *stream)
{
return !!obs_output_get_audio_encoder(stream->output, 0);
}
static void push_back_packet(struct darray *packets,
struct encoder_packet *packet)
{
struct encoder_packet pkt;
obs_encoder_packet_ref(&pkt, packet);
darray_push_back(sizeof(pkt), packets, &pkt);
}
static void ffmpeg_mux_data(void *data, struct encoder_packet *packet)
{
struct ffmpeg_muxer *stream = data;
@ -744,9 +762,31 @@ static void ffmpeg_mux_data(void *data, struct encoder_packet *packet)
return;
}
if (stream->split_file && should_split(stream, packet)) {
if (!prepare_split_file(stream, packet))
if (stream->split_file && stream->mux_packets.num) {
int64_t pts_usec = packet_pts_usec(packet);
struct encoder_packet *first_pkt = stream->mux_packets.array;
int64_t first_pts_usec = packet_pts_usec(first_pkt);
if (pts_usec >= first_pts_usec) {
if (packet->type != OBS_ENCODER_AUDIO) {
push_back_packet(&stream->mux_packets.da,
packet);
return;
}
if (!prepare_split_file(stream, first_pkt))
return;
stream->split_file_ready = true;
}
} else if (stream->split_file && should_split(stream, packet)) {
if (has_audio(stream)) {
push_back_packet(&stream->mux_packets.da, packet);
return;
} else {
if (!prepare_split_file(stream, packet))
return;
stream->split_file_ready = true;
}
}
if (!stream->sent_headers) {
@ -766,6 +806,19 @@ static void ffmpeg_mux_data(void *data, struct encoder_packet *packet)
}
}
if (stream->split_file && stream->split_file_ready) {
for (size_t i = 0; i < stream->mux_packets.num; i++) {
struct encoder_packet *pkt =
&stream->mux_packets.array[i];
if (stream->reset_timestamps)
ts_offset_update(stream, pkt);
write_packet(stream, pkt);
obs_encoder_packet_release(pkt);
}
da_free(stream->mux_packets);
stream->split_file_ready = false;
}
if (stream->split_file && stream->reset_timestamps)
ts_offset_update(stream, packet);

View File

@ -42,6 +42,7 @@ struct ffmpeg_muxer {
bool found_audio[MAX_AUDIO_MIXES];
int64_t video_pts_offset;
int64_t audio_dts_offsets[MAX_AUDIO_MIXES];
bool split_file_ready;
/* these are accessed both by replay buffer and by HLS */
pthread_t mux_thread;