From 87624f98c0cf9bb68eeb6bbf7f1107346b082f65 Mon Sep 17 00:00:00 2001
From: Eloi BAIL <eloi.bail@savoirfairelinux.com>
Date: Thu, 27 Aug 2015 10:22:53 -0400
Subject: [PATCH] daemon: force keyframe rate on encoder at 5 seconds

Some codecs, as h264, use a default keyframe rate based on frame count.
As example, on h264 this rate is one IFrame each 250 frames.
So this rate is sensible to fps changes, that ofen happens with
output type (images, frame size, screen casting, etc).
Using a rate based on fps seems more viable solution.

Moreover, in order to handle video artifacts in case of missed packets,
we want to send more keyframes so that artifacts will be seen for
a shorter period.

Note: the drawback of this solution is an average bitrate higher than
before as I frames are bigger than P frames.

Issue: #79690
Change-Id: I0b9daef8723c84b5998c9eb156d1e73538e8abed
Signed-off-by: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
---
 src/media/video/video_sender.cpp | 8 ++++++--
 src/media/video/video_sender.h   | 5 ++++-
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/src/media/video/video_sender.cpp b/src/media/video/video_sender.cpp
index 087d142791..e8e332fb0b 100644
--- a/src/media/video/video_sender.cpp
+++ b/src/media/video/video_sender.cpp
@@ -50,6 +50,7 @@ VideoSender::VideoSender(const std::string& dest, const DeviceParams& dev,
     , videoEncoder_(new MediaEncoder)
 {
     videoEncoder_->setDeviceOptions(dev);
+    keyFrameFreq_ = dev.framerate.numerator() * KEY_FRAME_PERIOD;
     videoEncoder_->openOutput(dest.c_str(), args);
     videoEncoder_->setInitSeqVal(seqVal);
     videoEncoder_->setIOContext(muxContext_);
@@ -66,10 +67,13 @@ VideoSender::~VideoSender()
 
 void VideoSender::encodeAndSendVideo(VideoFrame& input_frame)
 {
-    bool is_keyframe = forceKeyFrame_ > 0;
+    bool is_keyframe = forceKeyFrame_ > 0 \
+        or (keyFrameFreq_ > 0 and (frameNumber_ % keyFrameFreq_) == 0);
 
-    if (is_keyframe)
+    if (is_keyframe) {
+        RING_DBG("keyframe requested");
         --forceKeyFrame_;
+    }
 
     if (videoEncoder_->encode(input_frame, is_keyframe, frameNumber_++) < 0)
         RING_ERR("encoding failed");
diff --git a/src/media/video/video_sender.h b/src/media/video/video_sender.h
index cac8f30d85..d1d1fd6452 100644
--- a/src/media/video/video_sender.h
+++ b/src/media/video/video_sender.h
@@ -74,6 +74,9 @@ public:
     bool useCodec(const AccountVideoCodecInfo* codec) const;
 
 private:
+    static constexpr int KEYFRAMES_AT_START {3}; // Number of keyframes to enforce at stream startup
+    static constexpr unsigned KEY_FRAME_PERIOD {5}; // seconds before forcing a keyframe
+
     NON_COPYABLE(VideoSender);
 
     void encodeAndSendVideo(VideoFrame&);
@@ -82,8 +85,8 @@ private:
     std::unique_ptr<MediaIOHandle> muxContext_ = nullptr;
     std::unique_ptr<MediaEncoder> videoEncoder_ = nullptr;
 
-    static constexpr int KEYFRAMES_AT_START {3}; // Number of keyframes to enforce at stream startup
     std::atomic<int> forceKeyFrame_ {KEYFRAMES_AT_START};
+    int keyFrameFreq_ {0}; // Set keyframe rate, 0 to disable auto-keyframe. Computed in constructor
     int64_t frameNumber_ = 0;
     std::string sdp_ = "";
 };
-- 
GitLab