Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make continuous recording handle bad timestamps gracefully #708

Merged
merged 2 commits into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 23 additions & 25 deletions server/media_writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ static void bc_avlog(int val, const char *msg)
// S.K. >> Implementation of separated media writer
///////////////////////////////////////////////////////////////

media_writer::media_writer()
media_writer::media_writer():
last_mux_dts{0, 0}
{
}

Expand Down Expand Up @@ -74,31 +75,24 @@ bool media_writer::write_packet(const stream_packet &pkt)
opkt.stream_index = stream->index;

/* Fix non-increasing timestamps */
if (pkt.type == AVMEDIA_TYPE_AUDIO)
{
if (opkt.pts < last_audio_pts || opkt.dts < last_audio_dts)
{
opkt.pts = last_audio_pts + 1;
opkt.dts = last_audio_dts + 1;
bc_log(Debug, "fixing timestamps in audio packet");
}

last_audio_pts = opkt.pts;
last_audio_dts = opkt.dts;
}

if (pkt.type == AVMEDIA_TYPE_VIDEO)
{
if (opkt.pts < last_video_pts || opkt.dts < last_video_dts)
{
opkt.pts = last_video_pts + 1;
opkt.dts = last_video_dts + 1;
bc_log(Debug, "fixing timestamps in video packet");
}

last_video_pts = opkt.pts;
last_video_dts = opkt.dts;
static_assert(AVMEDIA_TYPE_VIDEO == 0);
static_assert(AVMEDIA_TYPE_AUDIO == 1);
int64_t &last_mux_dts = this->last_mux_dts[pkt.type];
if (opkt.dts == AV_NOPTS_VALUE) {
// Do nothing.
// In ffmpeg, ffmpeg_mux.c:write_packet() does nothing and
// lavf/mux.c:compute_muxer_pkt_fields() deals with it for now
bc_log(Info, "Got bad dts=NOPTS on stream %d, passing to libavformat to handle", opkt.stream_index);
} else if (last_mux_dts < opkt.dts) {
// Do nothing. This is normal.
} else {
// In this clause we're dealing with incorrect timestamp received from the source.
assert(last_mux_dts >= opkt.dts);
assert(last_mux_dts != AV_NOPTS_VALUE);
bc_log(Info, "Got bad dts=%" PRId64 " while last was %" PRId64 " on stream %d, setting to last+1", opkt.dts, last_mux_dts, opkt.stream_index);
opkt.dts = last_mux_dts + 1;
}
last_mux_dts = opkt.dts;

bc_log(Debug, "av_interleaved_write_frame: dts=%" PRId64 " pts=%" PRId64 " tb=%d/%d s_i=%d k=%d",
opkt.dts, opkt.pts, out_ctx->streams[opkt.stream_index]->time_base.num,
Expand All @@ -109,6 +103,10 @@ bool media_writer::write_packet(const stream_packet &pkt)
if (re < 0)
{
bc_avlog(re, "Error writing frame to recording");
if (re == AVERROR(EINVAL)) {
bc_log(Error, "Error writing frame to recording. Likely timestamping problem. Ignoring.");
return true;
}
return false;
}

Expand Down
9 changes: 2 additions & 7 deletions server/media_writer.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,8 @@ class media_writer
AVStream *audio_st = NULL;
std::string recording_path;

/* Base PTS value for the start of the recording. This assumes that all streams
* share a time_base of AV_TIME_BASE, and 0 represents the same instant across all
* streams. This is set automatically by the first written packet. */
int64_t last_video_pts = 0;
int64_t last_video_dts = 0;
int64_t last_audio_pts = 0;
int64_t last_audio_dts = 0;
/* Control monotonicity of timestamps we feed to muxer, the same way as in ffmpeg_mux.c in ffmpeg.*/
int64_t last_mux_dts[2] = {0, 0};
};

class snapshot_writer
Expand Down
Loading