From 0176c99ce717b0245770efde8b1a9576ac4aff89 Mon Sep 17 00:00:00 2001
From: agsantos <aline.gondimsantos@savoirfairelinux.com>
Date: Fri, 16 Apr 2021 18:31:11 -0400
Subject: [PATCH] conference: keep frame sizes if frame is empty

This is needed to have a proper overlay for conference participant with muted video.

GitLab: #484
Change-Id: Ie037728f4651d937741b24a656b7c49cf7670856
---
 src/media/video/video_mixer.cpp | 67 ++++++++++++++++++++-------------
 1 file changed, 41 insertions(+), 26 deletions(-)

diff --git a/src/media/video/video_mixer.cpp b/src/media/video/video_mixer.cpp
index 3bcf40ad8f..f7f6950f8c 100644
--- a/src/media/video/video_mixer.cpp
+++ b/src/media/video/video_mixer.cpp
@@ -58,7 +58,8 @@ struct VideoMixer::VideoMixerSource
         render_frame = newFrame;
     }
 
-    std::shared_ptr<VideoFrame> getRenderFrame() {
+    std::shared_ptr<VideoFrame> getRenderFrame()
+    {
         std::lock_guard<std::mutex> lock(mutex_);
         return render_frame;
     }
@@ -68,7 +69,7 @@ struct VideoMixer::VideoMixerSource
     int y {};
     int w {};
     int h {};
-    bool hasVideo {false};
+    bool hasVideo {true};
 
 private:
     std::mutex mutex_;
@@ -140,7 +141,8 @@ VideoMixer::switchInput(const std::string& input)
 }
 
 void
-VideoMixer::switchSecondaryInput(const std::string& input) {
+VideoMixer::switchSecondaryInput(const std::string& input)
+{
     if (auto local = videoLocalSecondary_) {
         // Detach videoInput from mixer
         local->detach(this);
@@ -216,7 +218,8 @@ VideoMixer::detached(Observable<std::shared_ptr<MediaFrame>>* ob)
             // Handle the case where the current shown source leave the conference
             if (activeSource_ == ob) {
                 currentLayout_ = Layout::GRID;
-                activeSource_ = videoLocalSecondary_ ? videoLocalSecondary_.get() : videoLocal_.get();
+                activeSource_ = videoLocalSecondary_ ? videoLocalSecondary_.get()
+                                                     : videoLocal_.get();
             }
             sources_.remove(x);
             updateLayout();
@@ -236,7 +239,9 @@ VideoMixer::update(Observable<std::shared_ptr<MediaFrame>>* ob,
 #ifdef RING_ACCEL
             std::shared_ptr<VideoFrame> frame;
             try {
-                frame = HardwareAccel::transferToMainMemory(*std::static_pointer_cast<VideoFrame>(frame_p), AV_PIX_FMT_NV12);
+                frame = HardwareAccel::transferToMainMemory(*std::static_pointer_cast<VideoFrame>(
+                                                                frame_p),
+                                                            AV_PIX_FMT_NV12);
                 x->atomic_copy(*std::static_pointer_cast<VideoFrame>(frame));
             } catch (const std::runtime_error& e) {
                 JAMI_ERR("Accel failure: %s", e.what());
@@ -284,16 +289,7 @@ VideoMixer::process()
                 // make rendered frame temporarily unavailable for update()
                 // to avoid concurrent access.
                 std::shared_ptr<VideoFrame> input = x->getRenderFrame();
-
-                if (!input->height() or !input->width())
-                    continue;
-
-                // If orientation changed or if the first valid frame for source
-                // is received -> trigger layout calculation and confInfo update
-                if (x->rotation != input->getOrientation() or !x->w or !x->h) {
-                    updateLayout();
-                    needsUpdate = true;
-                }
+                std::shared_ptr<VideoFrame> fooInput = std::make_shared<VideoFrame>();
 
                 auto wantedIndex = i;
                 if (currentLayout_ == Layout::ONE_BIG) {
@@ -308,16 +304,35 @@ VideoMixer::process()
                     }
                 }
 
+                auto hasVideo = x->hasVideo;
+                bool blackFrame = false;
+
+                if (!input->height() or !input->width()) {
+                    successfullyRendered = true;
+                    fooInput->reserve(format_, width_, height_);
+                    blackFrame = true;
+                } else {
+                    fooInput.swap(input);
+                }
+
+                // If orientation changed or if the first valid frame for source
+                // is received -> trigger layout calculation and confInfo update
+                if (x->rotation != fooInput->getOrientation() or !x->w or !x->h) {
+                    updateLayout();
+                    needsUpdate = true;
+                }
+
                 if (needsUpdate)
-                    calc_position(x, input, wantedIndex);
+                    calc_position(x, fooInput, wantedIndex);
 
-                if (input)
-                    successfullyRendered |= render_frame(output, input, x);
-                else
-                    JAMI_WARN("Nothing to render for %p", x->source);
+                if (!blackFrame) {
+                    if (fooInput)
+                        successfullyRendered |= render_frame(output, fooInput, x);
+                    else
+                        JAMI_WARN("Nothing to render for %p", x->source);
+                }
 
-                auto hasVideo = x->hasVideo;
-                x->hasVideo = input && successfullyRendered;
+                x->hasVideo = !blackFrame && successfullyRendered;
                 if (hasVideo != x->hasVideo) {
                     updateLayout();
                     needsUpdate = true;
@@ -348,10 +363,10 @@ VideoMixer::process()
     }
 
     output.pointer()->pts = av_rescale_q_rnd(av_gettime() - startTime_,
-                                      {1, AV_TIME_BASE},
-                                      {1, MIXER_FRAMERATE},
-                                      static_cast<AVRounding>(AV_ROUND_NEAR_INF
-                                                              | AV_ROUND_PASS_MINMAX));
+                                             {1, AV_TIME_BASE},
+                                             {1, MIXER_FRAMERATE},
+                                             static_cast<AVRounding>(AV_ROUND_NEAR_INF
+                                                                     | AV_ROUND_PASS_MINMAX));
     lastTimestamp_ = output.pointer()->pts;
     publishFrame();
 }
-- 
GitLab