From cffd25872b0d0956191d29a86821c569282ceea5 Mon Sep 17 00:00:00 2001
From: philippegorley <philippe.gorley@savoirfairelinux.com>
Date: Fri, 8 Jun 2018 12:05:40 -0400
Subject: [PATCH] encoder: correctly set frame timestamp

Timestamp has to consider frame/sample rate and stream time base.

Fixes recording synchronization issues.

Change-Id: Ib270f9482b757eed65e7daa8ad7acf46db7f6450
Reviewed-by: Sebastien Blin <sebastien.blin@savoirfairelinux.com>
---
 src/media/media_encoder.cpp  | 15 +++++++++++++--
 src/media/media_recorder.cpp | 14 ++++----------
 2 files changed, 17 insertions(+), 12 deletions(-)

diff --git a/src/media/media_encoder.cpp b/src/media/media_encoder.cpp
index b4ea60b312..9736f2c6fa 100644
--- a/src/media/media_encoder.cpp
+++ b/src/media/media_encoder.cpp
@@ -341,6 +341,15 @@ MediaEncoder::startIO()
 #endif
 }
 
+// seq: frame number for video, sent samples audio
+// sampleFreq: fps for video, sample rate for audio
+// clock: stream time base (packetization interval times)
+int64_t
+getNextTimestamp(int64_t seq, rational<int64_t> sampleFreq, rational<int64_t> clock)
+{
+    return (seq / (sampleFreq * clock)).real<int64_t>();
+}
+
 #ifdef RING_VIDEO
 int
 MediaEncoder::encode(VideoFrame& input, bool is_keyframe,
@@ -354,7 +363,8 @@ MediaEncoder::encode(VideoFrame& input, bool is_keyframe,
     scaler_.scale_with_aspect(input, scaledFrame_);
 
     auto frame = scaledFrame_.pointer();
-    frame->pts = frame_number;
+    AVStream* st = outputCtx_->streams[currentStreamIdx_];
+    frame->pts = getNextTimestamp(frame_number, st->avg_frame_rate, st->time_base);
 
     if (is_keyframe) {
         frame->pict_type = AV_PICTURE_TYPE_I;
@@ -412,7 +422,8 @@ int MediaEncoder::encode_audio(const AudioBuffer &buffer)
         frame->channels = buffer.channels();
         frame->sample_rate = sample_rate;
 
-        frame->pts = sent_samples;
+        AVStream* st = outputCtx_->streams[currentStreamIdx_];
+        frame->pts = getNextTimestamp(sent_samples, st->codecpar->sample_rate, st->time_base);
         sent_samples += frame->nb_samples;
 
         const auto buffer_size = \
diff --git a/src/media/media_recorder.cpp b/src/media/media_recorder.cpp
index 7d7cc16df9..fbb481a337 100644
--- a/src/media/media_recorder.cpp
+++ b/src/media/media_recorder.cpp
@@ -182,12 +182,6 @@ MediaRecorder::recordData(AVFrame* frame, bool isVideo, bool fromPeer)
     const MediaStream& ms = streams_[isVideo][fromPeer];
     // stream has to start at 0
     input->pts = input->pts - ms.firstTimestamp;
-    // convert streams to rtp timestamps if not already done by FFmpeg
-    if (isVideo && !fromPeer) {
-        input->pts = input->pts / (ms.frameRate * ms.timeBase).real();
-    } else if (!isVideo) {
-        input->pts = input->pts / (ms.timeBase * ms.sampleRate).real();
-    }
 
     if (inputName.empty()) // #nofilters
         return sendToEncoder(input, streamIdx);
@@ -228,7 +222,7 @@ MediaRecorder::initRecord()
 
     videoFilter_.reset();
     if (nbReceivedVideoStreams_ > 0) {
-        auto videoStream = setupVideoOutput();
+        const MediaStream& videoStream = setupVideoOutput();
         if (videoStream.format < 0) {
             RING_ERR() << "Could not retrieve video recorder stream properties";
             return -1;
@@ -242,7 +236,7 @@ MediaRecorder::initRecord()
 
     audioFilter_.reset();
     if (nbReceivedAudioStreams_ > 0) {
-        auto audioStream = setupAudioOutput();
+        const MediaStream& audioStream = setupAudioOutput();
         if (audioStream.format < 0) {
             RING_ERR() << "Could not retrieve audio recorder stream properties";
             return -1;
@@ -338,8 +332,8 @@ MediaRecorder::buildVideoFilter()
 {
     std::stringstream v;
 
-    const auto p = streams_[true][true];
-    const auto l = streams_[true][false];
+    const MediaStream& p = streams_[true][true];
+    const MediaStream& l = streams_[true][false];
 
     const constexpr int minHeight = 720;
     const auto newFps = std::max(p.frameRate, l.frameRate);
-- 
GitLab