From 46f4294a903ef2b9bad83c000b3336b0b8f1ec9d Mon Sep 17 00:00:00 2001
From: Ming Rui Zhang <mingrui.zhang@savoirfairelinux.com>
Date: Wed, 4 Sep 2019 17:15:51 -0400
Subject: [PATCH] video: refactor/separate preview from the distant renderer

Change-Id: I9af9e0a4bb07a83b68647015dc8a4e2a21cd2170
---
 callwidget.cpp                      |  46 ++++-
 callwidget.h                        |   8 +-
 jami-qt.pro                         |  10 +-
 lrcinstance.cpp                     | 127 ++++++++++++
 lrcinstance.h                       |  81 ++++++++
 mainwindow.cpp                      |  88 +-------
 mainwindow.h                        |   5 +-
 newwizardwidget.cpp                 |   2 +
 photoboothwidget.cpp                |  66 +++---
 photoboothwidget.h                  |  22 +-
 photoboothwidget.ui                 |  21 +-
 previewrender.cpp                   | 151 ++++++++++++++
 previewrender.h                     |  96 +++++++++
 previewrender.ui                    |  19 ++
 ring-client-windows.vcxproj         |   7 +
 ring-client-windows.vcxproj.filters |  19 +-
 settingswidget.cpp                  | 156 +++-----------
 settingswidget.h                    |  21 +-
 settingswidget.ui                   |  22 +-
 stylesheet.css                      |   4 +
 utils.cpp                           |  42 ++++
 utils.h                             |  19 +-
 videoview.cpp                       | 119 +++++------
 videoview.h                         |  14 +-
 videowidget.cpp                     | 302 +++-------------------------
 videowidget.h                       |  59 +-----
 26 files changed, 782 insertions(+), 744 deletions(-)
 create mode 100644 lrcinstance.cpp
 create mode 100644 previewrender.cpp
 create mode 100644 previewrender.h
 create mode 100644 previewrender.ui

diff --git a/callwidget.cpp b/callwidget.cpp
index 5d855f6..27cce37 100644
--- a/callwidget.cpp
+++ b/callwidget.cpp
@@ -50,6 +50,7 @@
 #include <QScrollBar>
 #include <QWebEngineScript>
 #include <QMimeData>
+#include <QtConcurrent/QtConcurrent>
 
 #include <algorithm>
 #include <memory>
@@ -222,6 +223,8 @@ CallWidget::CallWidget(QWidget* parent) :
     setCallPanelVisibility(false);
 
     ui->containerWidget->setVisible(false);
+
+    previewRenderer_ = PreviewRenderWidget::attachPreview();
 }
 
 CallWidget::~CallWidget()
@@ -256,6 +259,16 @@ CallWidget::navigated(bool to)
         } else {
             backToWelcomePage();
         }
+        // reset preview renderer
+        if (LRCInstance::getActiveCalls().size() && !LRCInstance::getCurrentCallModel()->getCall(conversation->callId).isAudioOnly) {
+            previewRenderer_->setParent(ui->videoWidget);
+            previewRenderer_->changeToRoundedBoarder();
+            previewRenderer_->setCurrentConainerGeo(ui->videoWidget->width(), ui->videoWidget->height());
+            previewRenderer_->setPhotoMode(false);
+            previewRenderer_->setNeedToCentre(false);
+            previewRenderer_->triggerResetPreviewAfterImageReloaded();
+            previewRenderer_->show();
+        }
     } else {
         QObject::disconnect(smartlistSelectionConnection_);
         smartListModel_.reset(nullptr);
@@ -676,6 +689,16 @@ CallWidget::slotShowCallView(const std::string& accountId,
     }
     ui->callStackWidget->setCurrentWidget(ui->videoPage);
     hideMiniSpinner();
+
+    // reset preview renderer when call is not audio only
+    if (!LRCInstance::getCurrentCallModel()->getCall(convInfo.callId).isAudioOnly) {
+        previewRenderer_->setParent(ui->videoWidget);
+        previewRenderer_->changeToRoundedBoarder();
+        previewRenderer_->setCurrentConainerGeo(ui->videoWidget->width(), ui->videoWidget->height());
+        previewRenderer_->setPhotoMode(false);
+        previewRenderer_->setNeedToCentre(false);
+        previewRenderer_->triggerResetPreviewAfterImageReloaded();
+    }
     ui->videoWidget->pushRenderer(convInfo.callId, LRCInstance::accountModel().getAccountInfo(accountId).profileInfo.type == lrc::api::profile::Type::SIP);
     ui->videoWidget->setFocus();
 }
@@ -1412,13 +1435,26 @@ CallWidget::Copy()
 }
 
 void
-CallWidget::disconnectRendering()
+CallWidget::reconnectRenderingVideoDeviceChanged()
 {
-    ui->videoWidget->disconnectRendering();
+    // for distant renderer to reconnect rendering
+    ui->videoWidget->reconnectRenderingVideoDeviceChanged();
 }
 
 void
-CallWidget::connectRendering(bool started)
-{
-    ui->videoWidget->connectRendering(started);
+CallWidget::restartPreviewWhenSwitchDevice()
+{
+    previewRenderer_->setCurrentConainerGeo(ui->videoWidget->width(), ui->videoWidget->height());
+    // since there is the possiblity of image not reloaded properly
+    // after rendering reconnect, so trigger reset after image reloaded
+    previewRenderer_->triggerResetPreviewAfterImageReloaded();
+    if (LRCInstance::getActiveCalls().size() && !LRCInstance::getIfCurrentSelectedCallIsAudioOnly()) {
+        // if no active calls, or device is changed -> reactive preview
+        previewRenderer_->connectRendering();
+        QtConcurrent::run(
+            [this] {
+                LRCInstance::avModel().stopPreview();
+                LRCInstance::avModel().startPreview();
+            });
+    }
 }
diff --git a/callwidget.h b/callwidget.h
index 0160b62..2186a5d 100644
--- a/callwidget.h
+++ b/callwidget.h
@@ -32,6 +32,7 @@
 
 #include "navwidget.h"
 #include "smartlistmodel.h"
+#include "previewrender.h"
 
 // new LRC
 #include "api/account.h"
@@ -57,11 +58,9 @@ public:
     explicit CallWidget(QWidget* parent = 0);
     ~CallWidget();
 
+    void restartPreviewWhenSwitchDevice();
     int getLeftPanelWidth();
-    void disconnectRendering();
-
-    // if started is true, only update, stop signals are connected
-    void connectRendering(bool started = false);
+    void reconnectRenderingVideoDeviceChanged();
 
     // NavWidget
     virtual void navigated(bool to);
@@ -143,6 +142,7 @@ private:
 
     QMenu* menu_;
     QClipboard* clipboard_;
+    PreviewRenderWidget* previewRenderer_;
 
     Ui::CallWidget* ui;
     QMovie* miniSpinner_;
diff --git a/jami-qt.pro b/jami-qt.pro
index 63eb28e..0c54bfc 100644
--- a/jami-qt.pro
+++ b/jami-qt.pro
@@ -74,7 +74,8 @@ HEADERS += ./aboutdialog.h \
         ./sipinputpanel.h \
         ./callaudioonlyavataroverlay.h \
         ./overlaybutton.h \
-        ./accountmigrationdialog.h
+        ./accountmigrationdialog.h \
+        ./previewrender.h
 SOURCES += ./aboutdialog.cpp \
         ./banneditemwidget.cpp \
         ./conversationsfilterwidget.cpp \
@@ -130,7 +131,9 @@ SOURCES += ./aboutdialog.cpp \
         ./sipinputpanel.cpp \
         ./callaudioonlyavataroverlay.cpp \
         ./overlaybutton.cpp \
-        ./accountmigrationdialog.cpp
+        ./accountmigrationdialog.cpp \
+        ./previewrender.cpp \
+        ./lrcinstance.cpp
 FORMS += ./aboutdialog.ui \
         ./advancedsipsettingwidget.ui \
         ./callwidget.ui \
@@ -156,5 +159,6 @@ FORMS += ./aboutdialog.ui \
         ./videoview.ui \
         ./sipkeypad.ui \
         ./callaudioonlyavataroverlay.ui \
-        ./accountmigration.ui
+        ./accountmigration.ui \
+        ./previewrender.ui
 RESOURCES += ressources.qrc
diff --git a/lrcinstance.cpp b/lrcinstance.cpp
new file mode 100644
index 0000000..431b588
--- /dev/null
+++ b/lrcinstance.cpp
@@ -0,0 +1,127 @@
+/**************************************************************************
+| Copyright (C) 2019 by Savoir-faire Linux                                |
+| Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>              |
+|                                                                         |
+| This program is free software; you can redistribute it and/or modify    |
+| it under the terms of the GNU General Public License as published by    |
+| the Free Software Foundation; either version 3 of the License, or       |
+| (at your option) any later version.                                     |
+|                                                                         |
+| This program is distributed in the hope that it will be useful,         |
+| but WITHOUT ANY WARRANTY; without even the implied warranty of          |
+| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           |
+| GNU General Public License for more details.                            |
+|                                                                         |
+| You should have received a copy of the GNU General Public License       |
+| along with this program.  If not, see <https://www.gnu.org/licenses/>.  |
+**************************************************************************/
+
+#include "lrcinstance.h"
+
+FrameWrapper::FrameWrapper(bool isPreview) :
+    isPreview_(isPreview)
+{
+}
+
+FrameWrapper::~FrameWrapper()
+{
+
+}
+
+void
+FrameWrapper::connectPreviewRendering()
+{
+    QObject::disconnect(frameWrapperConnections_.started);
+    if (isPreview_) {
+        frameWrapperConnections_.started = connect(
+            &LRCInstance::avModel(),
+            &lrc::api::AVModel::rendererStarted,
+            this,
+            &FrameWrapper::slotPreviewStarted);
+    }
+}
+
+void
+FrameWrapper::slotPreviewStarted(const std::string& id)
+{
+    if (id != lrc::api::video::PREVIEW_RENDERER_ID)
+        return;
+
+    QObject::disconnect(frameWrapperConnections_.started);
+
+    QObject::disconnect(frameWrapperConnections_.updated);
+    frameWrapperConnections_.updated = connect(
+        &LRCInstance::avModel(),
+        &lrc::api::AVModel::frameUpdated,
+        this,
+        &FrameWrapper::slotPreviewUpdated);
+
+    QObject::disconnect(frameWrapperConnections_.stopped);
+    frameWrapperConnections_.stopped = connect(
+        &LRCInstance::avModel(),
+        &lrc::api::AVModel::rendererStopped,
+        this,
+        &FrameWrapper::slotPreviewStoped);
+}
+
+void
+FrameWrapper::slotPreviewUpdated(const std::string& id)
+{
+    if (id != lrc::api::video::PREVIEW_RENDERER_ID)
+        return;
+    auto avModel = &LRCInstance::avModel();
+    auto renderer = &avModel->getRenderer(id);
+    if (!renderer->isRendering()) {
+        return;
+    }
+    previewRenderer_ = const_cast<lrc::api::video::Renderer*>(renderer);
+    renderFrame(id);
+}
+
+void
+FrameWrapper::renderFrame(const std::string& id)
+{
+    auto avModel = &LRCInstance::avModel();
+    using namespace lrc::api::video;
+    auto renderer = &avModel->getRenderer(id);
+    if (renderer && renderer->isRendering()) {
+        {
+            QMutexLocker lock(&mutex_);
+            auto tmp = renderer->currentFrame();
+            if (tmp.storage.size()) {
+                previewFrame_ = tmp;
+            }
+        }
+        emit previewRenderReady();
+    }
+}
+
+void
+FrameWrapper::slotPreviewStoped(const std::string& id)
+{
+    if (id != lrc::api::video::PREVIEW_RENDERER_ID)
+        return;
+    QObject::disconnect(frameWrapperConnections_.updated);
+    QObject::disconnect(frameWrapperConnections_.stopped);
+    previewRenderer_ = nullptr;
+    emit previewRenderStopped();
+}
+
+RenderDistributer::RenderDistributer()
+{
+    previewFrameWrapper_ = std::make_unique<FrameWrapper>(true);
+
+    connect(previewFrameWrapper_.get(), &FrameWrapper::previewRenderReady,
+        [this]() {
+            emit previewRenderReady();
+        });
+    connect(previewFrameWrapper_.get(), &FrameWrapper::previewRenderStopped,
+        [this]() {
+            emit previewRenderStopped();
+        });
+}
+
+RenderDistributer::~RenderDistributer()
+{
+    previewFrameWrapper_.reset();
+}
diff --git a/lrcinstance.h b/lrcinstance.h
index 54cf86e..0e5c068 100644
--- a/lrcinstance.h
+++ b/lrcinstance.h
@@ -2,6 +2,7 @@
 | Copyright (C) 2019 by Savoir-faire Linux                                |
 | Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>          |
 | Author: Isa Nanic <isa.nanic@savoirfairelinux.com>                      |
+| Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>              |
 |                                                                         |
 | This program is free software; you can redistribute it and/or modify    |
 | it under the terms of the GNU General Public License as published by    |
@@ -23,6 +24,7 @@
 #endif
 
 #include <QObject>
+#include <QMutex>
 #include <QSettings>
 #include <QRegularExpression>
 #include <QPixmap>
@@ -30,6 +32,7 @@
 
 #include "settingskey.h"
 #include "accountlistmodel.h"
+#include "utils.h"
 
 #include "api/lrc.h"
 #include "api/account.h"
@@ -46,6 +49,67 @@
 #include "api/conversationmodel.h"
 #include "api/peerdiscoverymodel.h"
 
+#include <memory>
+
+class FrameWrapper : public QObject
+{
+
+    Q_OBJECT
+
+public:
+    FrameWrapper(bool isPreview);
+    ~FrameWrapper();
+
+    void connectPreviewRendering();
+    lrc::api::video::Renderer* getPreviewRenderer() { return previewRenderer_;  }
+    lrc::api::video::Frame getPreviewFrame() { return previewFrame_; }
+
+signals:
+    void previewRenderReady();
+    void previewRenderStopped();
+
+private slots:
+    void slotPreviewStarted(const std::string& id = {});
+    void slotPreviewUpdated(const std::string& id = {});
+    void slotPreviewStoped(const std::string& id = {});
+
+private:
+    bool isPreview_;
+    lrc::api::video::Renderer* previewRenderer_;
+    lrc::api::video::Frame previewFrame_;
+
+    QMutex mutex_;
+
+    struct frameWrapperConnections {
+        QMetaObject::Connection started, stopped, updated;
+    } frameWrapperConnections_;
+
+    void renderFrame(const std::string& id);
+};
+
+class RenderDistributer : public QObject
+{
+
+    Q_OBJECT
+
+public:
+    RenderDistributer();
+    ~RenderDistributer();
+    lrc::api::video::Renderer* getPreviewRenderer() { return previewFrameWrapper_->getPreviewRenderer(); }
+    lrc::api::video::Frame getPreviewFrame() { return previewFrameWrapper_->getPreviewFrame(); }
+    void connectPreviewRendering() { previewFrameWrapper_->connectPreviewRendering(); }
+
+signals:
+    void previewRenderReady();
+    void previewRenderStopped();
+
+private:
+    // one preview to rule them all
+    std::unique_ptr<FrameWrapper> previewFrameWrapper_;
+    // distant for each call/conf/conversation
+    //std::map<std::string, std::unique_ptr<FrameWrapper>> distantFrames_;
+};
+
 using namespace lrc::api;
 
 using migrateCallback = std::function<void()>;
@@ -67,6 +131,9 @@ public:
     static Lrc& getAPI() {
         return *(instance().lrc_);
     };
+    static RenderDistributer* getRenderDistributer() {
+        return instance().renderer_.get();
+    }
     static void connectivityChanged() {
         instance().lrc_->connectivityChanged();
     };
@@ -132,11 +199,22 @@ public:
         instance().selectedConvUid_ = convUid;
     };
 
+    static bool getIfCurrentSelectedCallIsAudioOnly() {
+        auto isAudioOnly = false;
+        auto convInfo = Utils::getSelectedConversation();
+        if (!convInfo.uid.empty()) {
+            isAudioOnly = LRCInstance::getCurrentCallModel()->getCall(convInfo.callId).isAudioOnly;
+        }
+        return isAudioOnly;
+    };
+
     static void reset(bool newInstance = false) {
         if (newInstance) {
             instance().lrc_.reset(new Lrc());
+            instance().renderer_.reset(new RenderDistributer());
         } else {
             instance().lrc_.reset();
+            instance().renderer_.reset();
         }
     };
 
@@ -189,8 +267,11 @@ private:
     LRCInstance(migrateCallback willMigrateCb = {},
                 migrateCallback didMigrateCb = {}) {
         lrc_ = std::make_unique<Lrc>(willMigrateCb, didMigrateCb);
+        renderer_ = std::make_unique<RenderDistributer>();
     };
 
     std::string selectedAccountId_;
     std::string selectedConvUid_;
+
+    std::unique_ptr<RenderDistributer> renderer_;
 };
diff --git a/mainwindow.cpp b/mainwindow.cpp
index e09cf26..7da621e 100644
--- a/mainwindow.cpp
+++ b/mainwindow.cpp
@@ -21,7 +21,6 @@
 #include "mainwindow.h"
 #include "ui_mainwindow.h"
 
-#include <QtConcurrent/QtConcurrent>
 #include <QDesktopWidget>
 #include <QDir>
 #include <QScreen>
@@ -43,9 +42,7 @@
 
 MainWindow::MainWindow(QWidget* parent)
     : QMainWindow(parent)
-    ,
-
-    ui(new Ui::MainWindow)
+    , ui(new Ui::MainWindow)
 {
     ui->setupUi(this);
 
@@ -187,17 +184,10 @@ MainWindow::MainWindow(QWidget* parent)
         });
     timer->start(1000);
 #endif
-    connect(ui->settingswidget, &SettingsWidget::switchCallWidgetToSettingsWidgetPreview,
-            this, &MainWindow::slotSwitchVideoWidget);
-    connect(ui->settingswidget, &SettingsWidget::switchSettingsWidgetPreviewToCallWidget,
-            this, &MainWindow::slotSwitchVideoWidget);
-    connect(ui->settingswidget, &SettingsWidget::switchCallWidgetToSettingsWidgetPhotoBooth,
-            this, &MainWindow::slotSwitchVideoWidget);
-    connect(ui->settingswidget, &SettingsWidget::switchSettingsWidgetPhotoBoothToCallWidget,
-            this, &MainWindow::slotSwitchVideoWidget);
-    connect(ui->settingswidget, &SettingsWidget::videoInputDeviceConnectionLost,
-            this, &MainWindow::slotSwitchVideoWidget);
+    // preview renderer is initialized firstly here
+    previewRenderer_ = PreviewRenderWidget::attachPreview(this);
 
+    connect(ui->settingswidget, &SettingsWidget::videoDeviceChanged, this, &MainWindow::slotVideoDeviceChanged);
     connect(&LRCInstance::accountModel(), &lrc::api::NewAccountModel::accountRemoved,
         [this](const std::string& accountId) {
             Q_UNUSED(accountId);
@@ -429,69 +419,11 @@ void MainWindow::slotAccountListChanged()
     }
 }
 
-void MainWindow::slotSwitchVideoWidget(Utils::VideoWidgetSwapType type)
+void MainWindow::slotVideoDeviceChanged(const std::string& device, bool avSettingOrAccountSettingVisible)
 {
-    auto convInfo = Utils::getCurrentConvInfo();
-    bool isAudioOnly = LRCInstance::getCurrentCallModel()->getCall(convInfo.callId).isAudioOnly;
-    switch (type)
-    {
-        case Utils::VideoWidgetSwapType::CallWidgetToSettingsWidgetPreview: {
-            // switch local rendering from call to setting preview
-            ui->callwidget->disconnectRendering();
-            ui->settingswidget->connectStartedRenderingToPreview();
-            if (isAudioOnly) {
-                QtConcurrent::run(
-                    [this] {
-                        LRCInstance::avModel().stopPreview();
-                        LRCInstance::avModel().startPreview();
-                    });
-                break;
-            }
-            break;
-        }
-        case Utils::VideoWidgetSwapType::CallWidgetToSettingsWidgetPhotoBooth: {
-            // switch local rendering from call to setting photo booth
-            ui->callwidget->disconnectRendering();
-            ui->settingswidget->connectStartedRenderingToPhotoBooth();
-            if (isAudioOnly) {
-                QtConcurrent::run(
-                    [this] {
-                        LRCInstance::avModel().stopPreview();
-                        LRCInstance::avModel().startPreview();
-                    });
-                break;
-            }
-            break;
-        }
-        case Utils::VideoWidgetSwapType::SettingsWidgetPreviewToCallWidget: {
-            // switch local rendering from setting preview to call
-            ui->settingswidget->disconnectPreviewRendering();
-            if (isAudioOnly) {
-                QtConcurrent::run([this] { LRCInstance::avModel().stopPreview(); });
-                break;
-            }
-            ui->callwidget->connectRendering(true);
-            break;
-        }
-        case Utils::VideoWidgetSwapType::SettingsWidgetPhotoBoothToCallWidget: {
-            // switch local rendering from setting photo booth to call
-            ui->settingswidget->disconnectPhotoBoothRendering();
-            if (isAudioOnly) {
-                QtConcurrent::run([this] { LRCInstance::avModel().stopPreview(); });
-                break;
-            }
-            ui->callwidget->connectRendering(true);
-            break;
-        }
-        case Utils::VideoWidgetSwapType::VideoInputDeviceConnectionLost: {
-            if (isAudioOnly) {
-                break;
-            }
-            ui->callwidget->connectRendering(false);
-            break;
-        }
-        default: {
-            break;
-        }
-    }
+    Q_UNUSED(device)
+    ui->callwidget->reconnectRenderingVideoDeviceChanged();
+    // if the device is not changed in avSettings, then restart preview manually
+    if(!avSettingOrAccountSettingVisible)
+        ui->callwidget->restartPreviewWhenSwitchDevice();
 }
diff --git a/mainwindow.h b/mainwindow.h
index 74d1df7..d4412c4 100644
--- a/mainwindow.h
+++ b/mainwindow.h
@@ -22,6 +22,7 @@
 #include "settingswidget.h"
 #include "utils.h"
 #include "connectivitymonitor.h"
+#include "previewrender.h"
 #include "globalsystemtray.h"
 
 #include <QMainWindow>
@@ -55,8 +56,7 @@ public:
     void showWindow();
 
 public slots:
-    // A slot where covers all cases of video rendering switch between widgets
-    void slotSwitchVideoWidget(Utils::VideoWidgetSwapType Type);
+    void slotVideoDeviceChanged(const std::string&, bool);
 
 protected:
     bool nativeEvent(const QByteArray& eventType, void* message, long* result);
@@ -96,6 +96,7 @@ private:
     std::unique_ptr<ConnectivityMonitor> connectivityMonitor_;
 
     QMetaObject::Connection screenChangedConnection_;
+    PreviewRenderWidget* previewRenderer_;
 
     QTimer *updateTimer_;
 };
diff --git a/newwizardwidget.cpp b/newwizardwidget.cpp
index d9b7646..fd19c27 100644
--- a/newwizardwidget.cpp
+++ b/newwizardwidget.cpp
@@ -238,6 +238,7 @@ void NewWizardWidget::changePage(QWidget* toPage)
             &LRCInstance::accountModel(), &lrc::api::NewAccountModel::registeredNameFound,
             this, &NewWizardWidget::slotRegisteredNameFound);
         validateWizardProgression();
+        ui->setAvatarWidget->setUpPreviewRenderer();
         ui->setAvatarWidget->startBooth();
     } else if (toPage == ui->createSIPAccountPage) {
         ui->SIPusernameEdit->clear();
@@ -248,6 +249,7 @@ void NewWizardWidget::changePage(QWidget* toPage)
         ui->SIPusernameEdit->setEnabled(true);
         setNavBarVisibility(true);
         ui->nextButton->setEnabled(true);
+        ui->setSIPAvatarWidget->setUpPreviewRenderer();
         ui->setSIPAvatarWidget->startBooth();
     } else if (toPage == ui->importFromDevicePage) {
         ui->pinFromDevice->clear();
diff --git a/photoboothwidget.cpp b/photoboothwidget.cpp
index 5f2eff6..162b38f 100644
--- a/photoboothwidget.cpp
+++ b/photoboothwidget.cpp
@@ -20,7 +20,6 @@
 
 #include "photoboothwidget.h"
 #include "ui_photoboothwidget.h"
-#include "settingswidget.h"
 
 #include <QFileDialog>
 #include <QStandardPaths>
@@ -37,8 +36,8 @@ PhotoboothWidget::PhotoboothWidget(QWidget *parent) :
     hasAvatar_(false)
 {
     ui->setupUi(this);
-    ui->videoFeed->setIsFullPreview(true);
-    ui->videoFeed->setPhotoMode(true);
+
+    previewRenderer_ = PreviewRenderWidget::attachPreview();
 
     flashOverlay_ = new QLabel(this);
     flashOverlay_->setStyleSheet("background-color:#fff");
@@ -53,6 +52,8 @@ PhotoboothWidget::PhotoboothWidget(QWidget *parent) :
     flashAnimation_->setEndValue(0);
     flashAnimation_->setEasingCurve(QEasingCurve::OutCubic);
 
+    Utils::drawBlackCircularImageOntoLabel(ui->previewContainer);
+    ui->previewContainer->hide();
     ui->takePhotoButton->setIcon(QIcon(":/images/icons/baseline-camera_alt-24px.svg"));
 }
 
@@ -66,28 +67,18 @@ void
 PhotoboothWidget::startBooth(bool isDeviceChanged)
 {
     hasAvatar_ = false;
-    ui->videoFeed->setResetPreview(true);
-    if (!LRCInstance::getActiveCalls().size() || isDeviceChanged) {
+    if (!LRCInstance::getActiveCalls().size() || isDeviceChanged || LRCInstance::getIfCurrentSelectedCallIsAudioOnly()) {
         // if no active calls
-        ui->videoFeed->connectPreviewOnlyRendering();
+        previewRenderer_->connectRendering();
         QtConcurrent::run(
             [this] {
                 LRCInstance::avModel().stopPreview();
                 LRCInstance::avModel().startPreview();
             });
-    } else if (settingsPreviewed_) {
-        // if setting preview is viewed
-        emit leaveSettingsWidgetPreviewToSettingsWidgetPhotoBooth(
-            Utils::VideoWidgetSwapType::SettingsWidgetPreviewToSettingsWidgetPhotoBooth);
-        hasConnection_ = true;
-    } else {
-        // call video rendering direct to photo booth
-        emit enterSettingsWidgetPhotoBoothFromCallWidget(
-            Utils::VideoWidgetSwapType::CallWidgetToSettingsWidgetPhotoBooth);
-        hasConnection_ = true;
     }
     takePhotoState_ = true;
-    ui->videoFeed->show();
+    ui->previewContainer->show();
+    setUpPreviewRenderer();
     ui->avatarLabel->hide();
     ui->takePhotoButton->setIcon(QIcon(":/images/icons/baseline-camera_alt-24px.svg"));
 }
@@ -95,14 +86,9 @@ PhotoboothWidget::startBooth(bool isDeviceChanged)
 void
 PhotoboothWidget::stopBooth()
 {
-    if (!LRCInstance::getActiveCalls().size() && takePhotoState_) {
+    if ((!LRCInstance::getActiveCalls().size() || LRCInstance::getIfCurrentSelectedCallIsAudioOnly()) && takePhotoState_) {
         // if no active calls
         QtConcurrent::run([this] { LRCInstance::avModel().stopPreview(); });
-    } else if(hasConnection_){
-        // if video connection is still on photo booth (now stopBooth will onlt be called once leaving the setting widget)
-        emit enterCallWidgetFromSettingsWidgetPhotoBooth(
-            Utils::VideoWidgetSwapType::SettingsWidgetPhotoBoothToCallWidget);
-        hasConnection_ = false;
     }
     resetToAvatarLabel();
 }
@@ -118,8 +104,6 @@ PhotoboothWidget::on_importButton_clicked()
                                              picturesDir,
                                              tr("Image Files") + " (*.jpg *.jpeg *.png)");
     if (fileName_.isEmpty()) {
-        ui->videoFeed->connectRendering();
-        LRCInstance::avModel().startPreview();
         return;
     }
     auto image = Utils::cropImage(QImage(fileName_));
@@ -143,8 +127,8 @@ PhotoboothWidget::on_takePhotoButton_clicked()
         startBooth();
         return;
     } else {
-        auto videoRect = ui->videoFeed->rect();
-        QPoint avatarLabelPos = ui->videoFeed->mapTo(this, videoRect.topLeft());
+        auto videoRect = previewRenderer_->rect();
+        QPoint avatarLabelPos = previewRenderer_->mapTo(this, videoRect.topLeft());
         flashOverlay_->setGeometry(
             avatarLabelPos.x(),
             avatarLabelPos.y(),
@@ -156,7 +140,7 @@ PhotoboothWidget::on_takePhotoButton_clicked()
 
         QtConcurrent::run(
             [this] {
-                auto photo = Utils::cropImage(ui->videoFeed->takePhoto());
+                auto photo = Utils::cropImage(previewRenderer_->takePhoto());
                 auto avatar = photo.scaled(224, 224, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
                 avatarPixmap_ = QPixmap::fromImage(avatar);
                 ui->avatarLabel->setPixmap(QPixmap::fromImage(Utils::getCirclePhoto(avatar, ui->avatarLabel->width())));
@@ -205,23 +189,10 @@ PhotoboothWidget::hasAvatar()
     return hasAvatar_;
 }
 
-void
-PhotoboothWidget::connectRendering()
-{
-    // connect only local preview
-    ui->videoFeed->rendererStartedWithoutDistantRender();
-}
-
-void
-PhotoboothWidget::disconnectRendering()
-{
-    ui->videoFeed->disconnectRendering();
-}
-
 void
 PhotoboothWidget::resetToAvatarLabel()
 {
-    ui->videoFeed->hide();
+    ui->previewContainer->hide();
     ui->avatarLabel->show();
     takePhotoState_ = false;
     if (!hasAvatar_) {
@@ -230,3 +201,14 @@ PhotoboothWidget::resetToAvatarLabel()
         ui->takePhotoButton->setIcon(QIcon(":/images/icons/baseline-refresh-24px.svg"));
     }
 }
+
+void
+PhotoboothWidget::setUpPreviewRenderer()
+{
+    previewRenderer_->setParent(ui->previewContainer);
+    previewRenderer_->setGeometry(ui->previewContainer->rect());
+    previewRenderer_->resetBoarder();
+    previewRenderer_->setPhotoMode(true);
+    previewRenderer_->setNeedToCentre(false);
+    previewRenderer_->show();
+}
diff --git a/photoboothwidget.h b/photoboothwidget.h
index 3aa6b66..0d0894b 100644
--- a/photoboothwidget.h
+++ b/photoboothwidget.h
@@ -20,6 +20,7 @@
 #pragma once
 
 #include "utils.h"
+#include "previewrender.h"
 
 #include <QWidget>
 #include <QLabel>
@@ -42,21 +43,9 @@ public:
     void setAvatarPixmap(const QPixmap& avatarPixmap, bool default = false, bool stopPhotoboothPreview = false);
     const QPixmap& getAvatarPixmap();
     bool hasAvatar();
-    void connectRendering();
-    void disconnectRendering();
-
-    // hasConnection_ decides whether the video rendering connection is still in photobooth
-    // (connection transmitted from other video widget)
-    bool isPhotoBoothOpened() { return takePhotoState_;  }
-    bool isPhotoBoothConnected() { return hasConnection_;  }
-    void resetTakePhotoState(bool state) { takePhotoState_ = state;  }
-    // settingsPreviewed_ changed once the setting's preview is previewed
-    void setIsSettingsPreviewed(bool state) { settingsPreviewed_ = state; }
-
-signals:
-    void enterSettingsWidgetPhotoBoothFromCallWidget(Utils::VideoWidgetSwapType type);
-    void enterCallWidgetFromSettingsWidgetPhotoBooth(Utils::VideoWidgetSwapType type);
-    void leaveSettingsWidgetPreviewToSettingsWidgetPhotoBooth(Utils::VideoWidgetSwapType type);
+    bool isPhotoBoothOpened() { return takePhotoState_; }
+    void resetTakePhotoState(bool state) { takePhotoState_ = state; }
+    void setUpPreviewRenderer();
 
 private slots:
     void on_importButton_clicked();
@@ -68,14 +57,13 @@ private:
     QString fileName_;
     Ui::PhotoboothWidget *ui;
 
+    PreviewRenderWidget* previewRenderer_;
     QLabel* flashOverlay_;
     QPropertyAnimation *flashAnimation_;
     QPixmap avatarPixmap_;
     bool hasAvatar_;
 
     bool takePhotoState_ { false };
-    bool hasConnection_ { false };
-    bool settingsPreviewed_ { false };
 
 signals:
     void photoTaken();
diff --git a/photoboothwidget.ui b/photoboothwidget.ui
index 21a95ba..d61b423 100644
--- a/photoboothwidget.ui
+++ b/photoboothwidget.ui
@@ -103,7 +103,7 @@
           </widget>
          </item>
          <item>
-          <widget class="VideoWidget" name="videoFeed" native="true">
+          <widget class="QLabel" name="previewContainer">
            <property name="sizePolicy">
             <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
              <horstretch>0</horstretch>
@@ -116,11 +116,14 @@
              <height>224</height>
             </size>
            </property>
-           <property name="toolTip">
-            <string>Photobooth display</string>
+           <property name="maximumSize">
+            <size>
+             <width>224</width>
+             <height>224</height>
+            </size>
            </property>
-           <property name="autoFillBackground">
-            <bool>true</bool>
+           <property name="text">
+            <string/>
            </property>
           </widget>
          </item>
@@ -241,14 +244,6 @@
    </item>
   </layout>
  </widget>
- <customwidgets>
-  <customwidget>
-   <class>VideoWidget</class>
-   <extends>QWidget</extends>
-   <header>videowidget.h</header>
-   <container>1</container>
-  </customwidget>
- </customwidgets>
  <resources>
   <include location="ressources.qrc"/>
  </resources>
diff --git a/previewrender.cpp b/previewrender.cpp
new file mode 100644
index 0000000..1f5f47d
--- /dev/null
+++ b/previewrender.cpp
@@ -0,0 +1,151 @@
+/***************************************************************************
+ * Copyright (C) 2015-2019 by Savoir-faire Linux                           *
+ * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>              *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 3 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ **************************************************************************/
+
+#include "previewrender.h"
+#include "ui_previewrender.h"
+
+#include "lrcinstance.h"
+#include "utils.h"
+
+PreviewRenderWidget::PreviewRenderWidget(QWidget* parent)
+    : QWidget(parent)
+    , ui(new Ui::PreviewRenderWidget)
+{
+    ui->setupUi(this);
+
+    setWindowFlags(Qt::CustomizeWindowHint);
+    setWindowFlags(Qt::Popup | Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint);
+    setAttribute(Qt::WA_NoSystemBackground, true);
+    setAttribute(Qt::WA_TranslucentBackground, true);
+
+    QPalette pal(palette());
+    pal.setColor(QPalette::Background, Qt::transparent);
+    setAutoFillBackground(true);
+    setPalette(pal);
+
+    connect(LRCInstance::getRenderDistributer(), &RenderDistributer::previewRenderReady,
+        [this]() {
+            QMutexLocker lock(&mutex_);
+            previewRenderer_ = LRCInstance::getRenderDistributer()->getPreviewRenderer();
+            previewFrame_ = LRCInstance::getRenderDistributer()->getPreviewFrame();
+        });
+    connect(LRCInstance::getRenderDistributer(), &RenderDistributer::previewRenderStopped,
+        [this]() {
+            QMutexLocker lock(&mutex_);
+            previewRenderer_ = LRCInstance::getRenderDistributer()->getPreviewRenderer();
+            previewFrame_ = LRCInstance::getRenderDistributer()->getPreviewFrame();
+        });
+}
+
+PreviewRenderWidget::~PreviewRenderWidget()
+{
+    delete ui;
+}
+
+void
+PreviewRenderWidget::paintEvent(QPaintEvent* e)
+{
+    Q_UNUSED(e);
+    QPainter painter(this);
+    painter.setRenderHint(QPainter::Antialiasing, true);
+
+    if (previewRenderer_ || (photoMode_ && hasFrame_)) {
+        QMutexLocker lock(&mutex_);
+        if (previewRenderer_
+            && previewFrame_.storage.size() != 0
+            && previewFrame_.storage.size() == (unsigned int)(previewRenderer_->size().height() * previewRenderer_->size().width() * 4)) {
+            framePreview_ = std::move(previewFrame_.storage);
+            previewImage_.reset(
+                new QImage((uchar*)framePreview_.data(),
+                    previewRenderer_->size().width(),
+                    previewRenderer_->size().height(),
+                    QImage::Format_ARGB32_Premultiplied));
+            hasFrame_ = true;
+            if (triggerResetPreviewAfterImageReloaded_) {
+                resetPreview_ = true;
+                triggerResetPreviewAfterImageReloaded_ = false;
+            }
+        } else {
+            hasFrame_ = false;
+        }
+        if (previewImage_) {
+            QImage scaledPreview;
+            int previewHeight = resetPreview_ ? currentConainerHeight_ / 5 : (needToCentre_ ? currentConainerHeight_ : height());
+            int previewWidth = resetPreview_ ? currentConainerWidth_ / 5 : (needToCentre_ ? currentConainerWidth_ : width());
+            if (photoMode_) {
+                scaledPreview = Utils::getCirclePhoto(*previewImage_, previewHeight);
+            } else {
+                scaledPreview = previewImage_->scaled(previewWidth,
+                                                      previewHeight,
+                                                      Qt::KeepAspectRatio);
+            }
+            if (isroundedBoarder_) {
+                scaledPreview = Utils::getRoundedEdgePhoto(scaledPreview, scaledPreview.width(), scaledPreview.height(), 10);
+            }
+            previewGeometry_.setRect(0, 0, scaledPreview.width(), scaledPreview.height());
+
+            QRect resetGeo(previewGeometry_);
+            if (resetPreview_) {
+                resetGeo.moveTo(currentConainerWidth_ - resetGeo.width() - previewMargin_,
+                                currentConainerHeight_ - resetGeo.height() - previewMargin_);
+                resetPreview_ = false;
+            } else if (needToCentre_) {
+                auto centreX = (currentConainerWidth_ - resetGeo.width()) / 2;
+                auto centreY = (currentConainerHeight_ - resetGeo.height()) / 2;
+                resetGeo.moveTo(centreX, centreY);
+            } else {
+                resetGeo.moveTo(this->x(), this->y());
+            }
+            this->setGeometry(resetGeo);
+            painter.drawImage(previewGeometry_, scaledPreview);
+        }
+    }
+    painter.end();
+}
+
+void
+PreviewRenderWidget::connectRendering()
+{
+    LRCInstance::getRenderDistributer()->connectPreviewRendering();
+}
+
+QImage
+PreviewRenderWidget::takePhoto()
+{
+    if (previewImage_) {
+        return previewImage_.get()->copy();
+    }
+    return QImage();
+}
+
+void
+PreviewRenderWidget::setPhotoMode(bool isPhotoMode)
+{
+    photoMode_ = isPhotoMode;
+}
+
+void
+PreviewRenderWidget::changeToRoundedBoarder() {
+    isroundedBoarder_ = true;
+}
+
+void
+PreviewRenderWidget::resetBoarder()
+{
+    isroundedBoarder_ = false;
+}
diff --git a/previewrender.h b/previewrender.h
new file mode 100644
index 0000000..619c559
--- /dev/null
+++ b/previewrender.h
@@ -0,0 +1,96 @@
+/***************************************************************************
+ * Copyright (C) 2015-2019 by Savoir-faire Linux                           *
+ * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>              *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 3 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ **************************************************************************/
+
+#pragma once
+
+#include <QWidget>
+#include <QPainter>
+#include <QPaintEvent>
+#include <QPainterPath>
+#include <QMutex>
+
+#include <memory>
+#include <array>
+
+#include "lrcinstance.h"
+
+namespace Ui {
+class PreviewRenderWidget;
+}
+
+class PreviewRenderWidget : public QWidget {
+    Q_OBJECT;
+
+public:
+    static PreviewRenderWidget* attachPreview(QWidget* parent = 0) {
+        static PreviewRenderWidget* instance_ = new PreviewRenderWidget(parent);
+        return instance_;
+    }
+    ~PreviewRenderWidget();
+
+    // rounded boarder for preview in calls
+    void setRoundedBoarder(bool rounded) { isroundedBoarder_ = rounded; }
+    // reset preview when in resize event
+    void resetPreview() { resetPreview_ = true; }
+    // set current container geometry for preview renderer
+    void setCurrentConainerGeo(int width, int height) { currentConainerHeight_ = height; currentConainerWidth_ = width; }
+    // centre for preview in avsettings
+    void setNeedToCentre(bool need) { needToCentre_ = need; }
+    // only trigger preview reset when image is reloaded
+    void triggerResetPreviewAfterImageReloaded() { triggerResetPreviewAfterImageReloaded_ = true; }
+    QImage takePhoto();
+    void setPhotoMode(bool isPhotoMode);
+    void connectRendering();
+    void changeToRoundedBoarder();
+    void resetBoarder();
+    QRect getPreviewRect() { return previewGeometry_; }
+    // force the preview to repaint
+    void forceRepaint() { paintEvent(&QPaintEvent(QRect(0, 0, 0, 0))); }
+
+    constexpr static int previewMargin_ = 15;
+    constexpr static int boarderRadius_ = 39;
+
+private:
+    Ui::PreviewRenderWidget* ui;
+
+    explicit PreviewRenderWidget(QWidget* parent = 0);
+
+    struct previewRendererConnections {
+        QMetaObject::Connection started, stopped, updated;
+    } previewRendererConnections_;
+
+    QMutex mutex_;
+
+    bool photoMode_ { false };
+    bool hasFrame_ { false };
+    bool isroundedBoarder_ { false };
+    bool resetPreview_ { false };
+    bool needToCentre_ { false };
+    bool triggerResetPreviewAfterImageReloaded_ { false };
+    QRect previewGeometry_;
+    int currentConainerHeight_ { 0 };
+    int currentConainerWidth_ { 0 };
+
+    lrc::api::video::Renderer* previewRenderer_;
+    lrc::api::video::Frame previewFrame_;
+    std::unique_ptr<QImage> previewImage_;
+    std::vector<uint8_t> framePreview_;
+
+protected:
+    void paintEvent(QPaintEvent* e);
+};
diff --git a/previewrender.ui b/previewrender.ui
new file mode 100644
index 0000000..9fc7dcc
--- /dev/null
+++ b/previewrender.ui
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PreviewRenderWidget</class>
+ <widget class="QWidget" name="PreviewRenderWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>500</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/ring-client-windows.vcxproj b/ring-client-windows.vcxproj
index 87f8c13..ab31ded 100644
--- a/ring-client-windows.vcxproj
+++ b/ring-client-windows.vcxproj
@@ -244,7 +244,9 @@ del /s /q $(OutDir)\Jami.exp</Command>
     <ClCompile Include="currentaccountcombobox.cpp" />
     <ClCompile Include="aboutdialog.cpp" />
     <ClCompile Include="levelmeter.cpp" />
+    <ClCompile Include="lrcinstance.cpp" />
     <ClCompile Include="overlaybutton.cpp" />
+    <ClCompile Include="previewrender.cpp" />
     <ClCompile Include="sipinputpanel.cpp" />
     <ClCompile Include="splashscreen.cpp" />
     <ClCompile Include="updatedownloaddialog.cpp" />
@@ -483,6 +485,10 @@ del /s /q $(OutDir)\Jami.exp</Command>
       <Define Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_WINDOWS;UNICODE;_UNICODE;WIN32;WIN64;NIGHTLY_VERSION=20180706;ENABLE_AUTOUPDATE;QT_NO_DEBUG;NDEBUG;QT_MULTIMEDIA_LIB;QT_MULTIMEDIAWIDGETS_LIB</Define>
       <IncludePath Condition="'$(Configuration)|$(Platform)'=='ReleaseCompile|x64'">.\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;$(ProjectDir)..\ring-daemon\contrib\msvc\include;$(ProjectDir)..\daemon\contrib\msvc\include;$(ProjectDir)..\ring-lrc\src;$(ProjectDir)..\lrc\src;$(ProjectDir)winsparkle\include;$(ProjectDir)qrencode-win32\qrencode-win32;$(QTDIR)\include;$(QTDIR)\include\QtSvg;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtWinExtras;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtXml;$(QTDIR)\include\QtNetwork;$(QTDIR)\include\QtWebEngineWidgets;$(QTDIR)\include\QtWebChannel;$(QTDIR)\include\QtCore;$(QTDIR)\mkspecs\win32-msvc;.\release</IncludePath>
     </QtMoc>
+    <QtMoc Include="previewrender.h">
+      <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;$(ProjectDir)..\ring-daemon\contrib\msvc\include;$(ProjectDir)..\daemon\contrib\msvc\include;$(ProjectDir)..\ring-lrc\src;$(ProjectDir)..\lrc\src;$(ProjectDir)qrencode-win32\qrencode-win32;$(QTDIR)\include;$(QTDIR)\include\QtSvg;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtWinExtras;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtXml;$(QTDIR)\include\QtNetwork;$(QTDIR)\include\QtWebEngineWidgets;$(QTDIR)\include\QtWebChannel;$(QTDIR)\include\QtCore;$(QTDIR)\mkspecs\win32-msvc;.\release</IncludePath>
+      <IncludePath Condition="'$(Configuration)|$(Platform)'=='ReleaseCompile|x64'">.\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;$(ProjectDir)..\ring-daemon\contrib\msvc\include;$(ProjectDir)..\daemon\contrib\msvc\include;$(ProjectDir)..\ring-lrc\src;$(ProjectDir)..\lrc\src;$(ProjectDir)winsparkle\include;$(ProjectDir)qrencode-win32\qrencode-win32;$(QTDIR)\include;$(QTDIR)\include\QtSvg;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtWinExtras;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtXml;$(QTDIR)\include\QtNetwork;$(QTDIR)\include\QtWebEngineWidgets;$(QTDIR)\include\QtWebChannel;$(QTDIR)\include\QtCore;$(QTDIR)\mkspecs\win32-msvc;.\release</IncludePath>
+    </QtMoc>
     <ClInclude Include="ringthemeutils.h" />
     <QtMoc Include="selectareadialog.h">
     </QtMoc>
@@ -659,6 +665,7 @@ del /s /q $(OutDir)\Jami.exp</Command>
     <QtUic Include="callwidget.ui">
       <SubType>Designer</SubType>
     </QtUic>
+    <QtUic Include="previewrender.ui" />
     <QtUic Include="sipkeypad.ui" />
     <QtUic Include="updatedownloaddialog.ui" />
     <QtUic Include="contactpicker.ui" />
diff --git a/ring-client-windows.vcxproj.filters b/ring-client-windows.vcxproj.filters
index 9f1315f..8554093 100644
--- a/ring-client-windows.vcxproj.filters
+++ b/ring-client-windows.vcxproj.filters
@@ -234,6 +234,12 @@
     <ClCompile Include="connectivitymonitor.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="previewrender.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="lrcinstance.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <QtMoc Include="aboutdialog.h">
@@ -404,12 +410,8 @@
     <QtMoc Include="overlaybutton.h">
       <Filter>Header Files</Filter>
     </QtMoc>
-    <QtMoc Include="accountmigrationdialog.h">
-      <Filter>Header Files</Filter>
-    </QtMoc>
-    <QtMoc Include="connectivitymonitor.h">
-      <Filter>Header Files</Filter>
-    </QtMoc>
+==== BASE ====
+==== BASE ====
   </ItemGroup>
   <ItemGroup>
     <CustomBuild Include="debug\moc_predefs.h.cbt">
@@ -704,6 +706,9 @@
     <QtUic Include="accountmigration.ui">
       <Filter>Form Files</Filter>
     </QtUic>
+    <QtUic Include="previewrender.ui">
+      <Filter>Form Files</Filter>
+    </QtUic>
   </ItemGroup>
   <ItemGroup>
     <None Include="images\FontAwesome.otf">
@@ -864,4 +869,4 @@
       <Filter>Resource Files</Filter>
     </Image>
   </ItemGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/settingswidget.cpp b/settingswidget.cpp
index 19e591d..8420888 100644
--- a/settingswidget.cpp
+++ b/settingswidget.cpp
@@ -130,6 +130,10 @@ SettingsWidget::SettingsWidget(QWidget* parent)
 
     connect(ui->mediaSettingsButton, &QPushButton::clicked, [this]() { setSelected(Button::mediaSettingsButton); });
 
+    /*connect(ui->currentSIPAccountAvatar, &QPushButton::clicked, [this]() {
+        avatarClicked();
+    });*/
+
     connect(ui->advancedAccountSettingsSIPButton, &QPushButton::clicked, this, &SettingsWidget::toggleAdvancedSIPSettings);
 
     // connect "delete SIP account" button
@@ -250,39 +254,11 @@ SettingsWidget::SettingsWidget(QWidget* parent)
 
     connect(ui->hardwareAccelCheckBox, &QAbstractButton::clicked, this, &SettingsWidget::slotSetHardwareAccel);
 
-    connect(ui->currentAccountAvatar, &PhotoboothWidget::enterSettingsWidgetPhotoBoothFromCallWidget,
-            this, &SettingsWidget::photoBoothEnterReceived);
-
-    connect(ui->currentSIPAccountAvatar, &PhotoboothWidget::enterSettingsWidgetPhotoBoothFromCallWidget,
-            this, &SettingsWidget::photoBoothEnterReceived);
-
-    connect(ui->currentAccountAvatar, &PhotoboothWidget::enterCallWidgetFromSettingsWidgetPhotoBooth,
-            this, &SettingsWidget::photoBoothLeaveReceived);
-
-    connect(ui->currentSIPAccountAvatar, &PhotoboothWidget::enterCallWidgetFromSettingsWidgetPhotoBooth,
-            this, &SettingsWidget::photoBoothLeaveReceived);
-
-    connect(&LRCInstance::avModel(),&lrc::api::AVModel::deviceEvent, [this] { videoDeviceEventHandlerAndMediaSettingSetUp(); });
-
-    connect(this, &SettingsWidget::settingWidgetPhotoBoothTosettingWidgetPreviewSignal,
-        [this]() {
-            this->disconnectPhotoBoothRendering();
-            this->connectStartedRenderingToPreview();
-        });
-
-    connect(ui->currentAccountAvatar, &PhotoboothWidget::leaveSettingsWidgetPreviewToSettingsWidgetPhotoBooth,
-        [this]() {
-            this->disconnectPreviewRendering();
-            this->connectStartedRenderingToPhotoBooth();
-        });
-
-    connect(ui->currentSIPAccountAvatar, &PhotoboothWidget::leaveSettingsWidgetPreviewToSettingsWidgetPhotoBooth,
-        [this]() {
-            this->disconnectPreviewRendering();
-            this->connectStartedRenderingToPhotoBooth();
-        });
+    connect(&LRCInstance::avModel(), &lrc::api::AVModel::deviceEvent, [this] { videoDeviceEventHandlerAndMediaSettingSetUp(); });
 
     ui->containerWidget->setVisible(false);
+
+    previewRenderer_ = PreviewRenderWidget::attachPreview();
 }
 
 void SettingsWidget::slotAccountListChanged()
@@ -327,21 +303,12 @@ void SettingsWidget::leaveSettingsSlot()
 
     bool isSIP = LRCInstance::getCurrentAccountInfo().profileInfo.type == lrc::api::profile::Type::SIP;
     auto photoBooth = isSIP ? ui->currentSIPAccountAvatar : ui->currentAccountAvatar;
-    if (LRCInstance::getActiveCalls().size()) {
+    QtConcurrent::run([this, &photoBooth] {
         photoBooth->stopBooth();
-        bool isPhotoBoothConnected = photoBooth->isPhotoBoothConnected();
-        // reset setting preview is not viewed
-        photoBooth->setIsSettingsPreviewed(false);
-        // check if is previewed and photo booth does not have video rendering connection
-        if (previewed_ && !isPhotoBoothConnected) {
-            emit switchSettingsWidgetPreviewToCallWidget(Utils::VideoWidgetSwapType::SettingsWidgetPreviewToCallWidget);
-            previewed_ = false;
-        }
-    } else {
-        QtConcurrent::run([this, &photoBooth] {
-            photoBooth->stopBooth();
-        });
-    }
+        if (isPreviewed_)
+            stopPreviewing();
+    });
+
     emit NavigationRequested(ScreenEnum::CallScreen);
 }
 
@@ -349,7 +316,6 @@ SettingsWidget::~SettingsWidget()
 {
     delete ui;
 }
-
 void SettingsWidget::setSelected(Button sel)
 {
     switch (sel) {
@@ -373,20 +339,12 @@ void SettingsWidget::setSelected(Button sel)
                 toggleAdvancedSIPSettings();
             }
             pastAccount_ = lrc::api::profile::Type::SIP;
-            // notify photo booth that setting preview is previewed
-            if (pastButton_ != Button::accountSettingsButton && previewed_) {
-                ui->currentSIPAccountAvatar->setIsSettingsPreviewed(previewed_);
-            }
         } else {
             ui->stackedWidget->setCurrentWidget(ui->currentAccountSettingsScrollWidget);
             if (advancedSettingsDropped_) {
                 toggleAdvancedSettings();
             }
             pastAccount_ = lrc::api::profile::Type::RING;
-            // notify photo booth that setting preview is previewed
-            if (pastButton_ != Button::accountSettingsButton && previewed_) {
-                ui->currentAccountAvatar->setIsSettingsPreviewed(previewed_);
-            }
         }
 
         break;
@@ -427,7 +385,6 @@ void SettingsWidget::setSelected(Button sel)
 
     pastButton_ = sel;
 }
-
 // called to update current settings information when navigating to settingsWidget
 void SettingsWidget::updateAccountInfoDisplayed()
 {
@@ -1058,6 +1015,14 @@ void SettingsWidget::populateAVSettings()
     connect(ui->outputComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
         this, &SettingsWidget::outputDevIndexChangedSlot);
 
+    previewRenderer_->setParent(ui->previewWidgetContainer);
+    previewRenderer_->setGeometry(ui->previewWidgetContainer->rect());
+    previewRenderer_->setCurrentConainerGeo(ui->previewWidgetContainer->width(), ui->previewWidgetContainer->height());
+    previewRenderer_->resetBoarder();
+    previewRenderer_->setPhotoMode(false);
+    previewRenderer_->setNeedToCentre(true);
+    previewRenderer_->show();
+
     // video
     videoDeviceEventHandlerAndMediaSettingSetUp();
 
@@ -1089,6 +1054,7 @@ void SettingsWidget::slotDeviceBoxCurrentIndexChanged(int index)
     LRCInstance::avModel().setCurrentVideoCaptureDevice(device);
     LRCInstance::avModel().setDefaultDevice(device);
     setFormatListForDevice(device);
+    emit videoDeviceChanged(device, true);
     startPreviewing(true);
 }
 
@@ -1099,38 +1065,21 @@ void SettingsWidget::slotFormatBoxCurrentIndexChanged(int index)
     auto decive = LRCInstance::avModel().getCurrentVideoCaptureDevice();
     auto currentSettings = LRCInstance::avModel().getDeviceSettings(decive);
     lrc::api::video::Settings settings{ {}, decive, rate, resolution };
-    ui->videoWidget->connectRendering();
+    previewRenderer_->connectRendering();
     LRCInstance::avModel().setDeviceSettings(settings);
 }
 
 void SettingsWidget::startPreviewing(bool isDeviceChanged)
 {
-    ui->videoWidget->disconnectRendering();
-    ui->videoWidget->connectPreviewOnlyRendering();
-    ui->videoWidget->setIsFullPreview(true);
-
-    bool isPhotoBoothConnected;
-    if (LRCInstance::getCurrentAccountInfo().profileInfo.type == lrc::api::profile::Type::SIP) {
-        isPhotoBoothConnected = ui->currentSIPAccountAvatar->isPhotoBoothConnected();
-    } else {
-        isPhotoBoothConnected = ui->currentAccountAvatar->isPhotoBoothConnected();
-    }
-
-    if (!LRCInstance::getActiveCalls().size() || isDeviceChanged) {
+    if (!LRCInstance::getActiveCalls().size() || isDeviceChanged || LRCInstance::getIfCurrentSelectedCallIsAudioOnly()) {
         // if no active calls, or device is changed -> reactive preview
+        previewRenderer_->connectRendering();
         QtConcurrent::run(
             [this] {
                 LRCInstance::avModel().stopPreview();
                 LRCInstance::avModel().startPreview();
             });
-    }
-    else if (pastButton_ != Button::mediaSettingsButton && isPhotoBoothConnected) {
-        // if photo booth is opened before
-        emit settingWidgetPhotoBoothTosettingWidgetPreviewSignal(Utils::VideoWidgetSwapType::SettingsWidgetPhotoBoothToSettingsWidgetPreview);
-        previewed_ = true;
-    } else {
-        emit switchCallWidgetToSettingsWidgetPreview(Utils::VideoWidgetSwapType::CallWidgetToSettingsWidgetPreview);
-        previewed_ = true;
+        isPreviewed_ = true;
     }
     ui->previewUnavailableLabel->hide();
     ui->videoLayoutWidget->show();
@@ -1138,9 +1087,10 @@ void SettingsWidget::startPreviewing(bool isDeviceChanged)
 
 void SettingsWidget::stopPreviewing()
 {
-    if (!LRCInstance::getActiveCalls().size()) {
+    if (!LRCInstance::getActiveCalls().size() || LRCInstance::getIfCurrentSelectedCallIsAudioOnly()) {
         QtConcurrent::run( [this] { LRCInstance::avModel().stopPreview(); });
     }
+    isPreviewed_ = false;
 }
 
 void SettingsWidget::toggleVideoSettings(bool enabled)
@@ -1221,44 +1171,6 @@ void SettingsWidget::stopAudioMeter(bool blocking)
     blocking ? f() : QtConcurrent::run(f);
 }
 
-void SettingsWidget::connectStartedRenderingToPreview()
-{
-    ui->videoWidget->rendererStartedWithoutDistantRender();
-}
-
-void SettingsWidget::connectStartedRenderingToPhotoBooth()
-{
-    if (LRCInstance::getCurrentAccountInfo().profileInfo.type == lrc::api::profile::Type::SIP) {
-        ui->currentSIPAccountAvatar->connectRendering();
-    } else {
-        ui->currentAccountAvatar->connectRendering();
-    }
-}
-
-void SettingsWidget::disconnectPreviewRendering()
-{
-    ui->videoWidget->disconnectRendering();
-}
-
-void SettingsWidget::disconnectPhotoBoothRendering()
-{
-    if (LRCInstance::getCurrentAccountInfo().profileInfo.type == lrc::api::profile::Type::SIP) {
-        ui->currentSIPAccountAvatar->disconnectRendering();
-    } else {
-        ui->currentAccountAvatar->disconnectRendering();
-    }
-}
-
-void SettingsWidget::photoBoothEnterReceived(Utils::VideoWidgetSwapType Type)
-{
-    emit switchCallWidgetToSettingsWidgetPhotoBooth(Type);
-}
-
-void SettingsWidget::photoBoothLeaveReceived(Utils::VideoWidgetSwapType Type)
-{
-    emit switchSettingsWidgetPhotoBoothToCallWidget(Type);
-}
-
 void SettingsWidget::resetPhotoBoothStateWhenSettingChanged(Button type)
 {
     bool stopPhotoboothPreview = false;
@@ -1377,18 +1289,12 @@ void SettingsWidget::videoDeviceEventHandlerAndMediaSettingSetUp()
     if (shouldRestart) {
         // if we are in photo booth open state and in account setting widget,
         // reset the photo booth video
+        emit videoDeviceChanged(LRCInstance::avModel().getDefaultDeviceName(), true);
         photoBooth->startBooth(true);
     } else if (shouldReinitializePreview && (ui->avSettings->isVisible() || LRCInstance::getActiveCalls().size())) {
         // if shouldReinitializePreview && has active calls -> videoInputDeviceLoseConnection to refersh video input
-        if (LRCInstance::getActiveCalls().size() && !ui->avSettings->isVisible()) {
-            emit videoInputDeviceConnectionLost(Utils::VideoWidgetSwapType::VideoInputDeviceConnectionLost);
-            QtConcurrent::run(
-                [this] {
-                    LRCInstance::avModel().stopPreview();
-                    LRCInstance::avModel().startPreview();
-                });
-            return;
-		}
-        startPreviewing(true);
+        emit videoDeviceChanged(LRCInstance::avModel().getDefaultDeviceName(), ui->avSettings->isVisible());
+        if(ui->avSettings->isVisible())
+            startPreviewing(true);
     }
 }
diff --git a/settingswidget.h b/settingswidget.h
index 541385d..5188fc1 100644
--- a/settingswidget.h
+++ b/settingswidget.h
@@ -30,6 +30,7 @@
 #include "bannedlistmodel.h"
 #include "linkdevicedialog.h"
 #include "photoboothwidget.h"
+#include "previewrender.h"
 
 #include "api/datatransfermodel.h"
 #include "typedefs.h"
@@ -46,28 +47,14 @@ public:
     explicit SettingsWidget(QWidget* parent = nullptr);
     ~SettingsWidget();
 
-    void connectStartedRenderingToPreview();
-    void connectStartedRenderingToPhotoBooth();
-    void disconnectPreviewRendering();
-    void disconnectPhotoBoothRendering();
-
     // NavWidget
     virtual void navigated(bool to);
     virtual void updateCustomUI();
 public slots:
     virtual void slotAccountListChanged();
 
-    void photoBoothEnterReceived(Utils::VideoWidgetSwapType Type);
-    void photoBoothLeaveReceived(Utils::VideoWidgetSwapType Type);
-
 signals:
-    void switchCallWidgetToSettingsWidgetPreview(Utils::VideoWidgetSwapType type);
-    void switchCallWidgetToSettingsWidgetPhotoBooth(Utils::VideoWidgetSwapType type);
-    void switchSettingsWidgetPreviewToCallWidget(Utils::VideoWidgetSwapType type);
-    void switchSettingsWidgetPhotoBoothToCallWidget(Utils::VideoWidgetSwapType type);
-    void settingWidgetPhotoBoothTosettingWidgetPreviewSignal(Utils::VideoWidgetSwapType type);
-    void settingWidgetPreviewTosettingWidgetPhotoBoothSignal(Utils::VideoWidgetSwapType type);
-    void videoInputDeviceConnectionLost(Utils::VideoWidgetSwapType type);
+    void videoDeviceChanged(const std::string&, bool avSettingOrAccountSettingVisible = false);
 
 private:
     Ui::SettingsWidget* ui;
@@ -125,9 +112,10 @@ private:
     int avatarSIPSize_;
     bool regNameBtn_ = false;
     const int itemHeight_ = 55;
-    bool previewed_ {false};
     int previousDeviceSize_ { static_cast<int>(LRCInstance::avModel().getDevices().size()) };
     bool deviceWasEmpty_ { false };
+    PreviewRenderWidget* previewRenderer_;
+    bool isPreviewed_ { false };
 
     QMovie* lookupSpinnerMovie_;
     QPixmap statusSuccessPixmap_;
@@ -168,7 +156,6 @@ private slots:
     void videoDeviceEventHandlerAndMediaSettingSetUp();
 
 public:
-    bool getIsPreviewed() { return previewed_; }
     Button getPreviousButton() { return pastButton_; }
 
 };
diff --git a/settingswidget.ui b/settingswidget.ui
index 9c86afd..5db9b39 100644
--- a/settingswidget.ui
+++ b/settingswidget.ui
@@ -1416,8 +1416,8 @@
                  <rect>
                   <x>0</x>
                   <y>0</y>
-                  <width>749</width>
-                  <height>1387</height>
+                  <width>706</width>
+                  <height>1398</height>
                  </rect>
                 </property>
                 <property name="styleSheet">
@@ -2740,7 +2740,7 @@
                   <x>0</x>
                   <y>0</y>
                   <width>683</width>
-                  <height>864</height>
+                  <height>874</height>
                  </rect>
                 </property>
                 <layout class="QHBoxLayout" name="horizontalLayoutsip_12" stretch="0">
@@ -4077,7 +4077,7 @@
                            <enum>Qt::Horizontal</enum>
                           </property>
                           <property name="sizeType">
-                           <enum>QSizePolicy::MinimumExpanding</enum>
+                           <enum>QSizePolicy::Expanding</enum>
                           </property>
                           <property name="sizeHint" stdset="0">
                            <size>
@@ -4088,7 +4088,7 @@
                          </spacer>
                         </item>
                         <item>
-                         <widget class="VideoWidget" name="videoWidget" native="true">
+                         <widget class="QWidget" name="previewWidgetContainer" native="true">
                           <property name="enabled">
                            <bool>true</bool>
                           </property>
@@ -4100,13 +4100,13 @@
                           </property>
                           <property name="minimumSize">
                            <size>
-                            <width>510</width>
+                            <width>400</width>
                             <height>224</height>
                            </size>
                           </property>
                           <property name="maximumSize">
                            <size>
-                            <width>16777215</width>
+                            <width>400</width>
                             <height>16777215</height>
                            </size>
                           </property>
@@ -4124,7 +4124,7 @@
                            <enum>Qt::Horizontal</enum>
                           </property>
                           <property name="sizeType">
-                           <enum>QSizePolicy::MinimumExpanding</enum>
+                           <enum>QSizePolicy::Expanding</enum>
                           </property>
                           <property name="sizeHint" stdset="0">
                            <size>
@@ -4232,12 +4232,6 @@
    <header>photoboothwidget.h</header>
    <container>1</container>
   </customwidget>
-  <customwidget>
-   <class>VideoWidget</class>
-   <extends>QWidget</extends>
-   <header>videowidget.h</header>
-   <container>1</container>
-  </customwidget>
   <customwidget>
    <class>AdvancedSettingsWidget</class>
    <extends>QWidget</extends>
diff --git a/stylesheet.css b/stylesheet.css
index 7e74fbf..113c775 100644
--- a/stylesheet.css
+++ b/stylesheet.css
@@ -54,6 +54,10 @@ QWidget#smartListOuterWidget {
     background-color: rgb(255, 255, 255);
 }
 
+QWidget#previewContainer {
+    background-color: black;
+}
+
 QPushButton#btnConversations, QPushButton#btnInvites {
     border-radius: 0px;
     border-top-left-radius: 15px;
diff --git a/utils.cpp b/utils.cpp
index 7cbb452..00ea955 100644
--- a/utils.cpp
+++ b/utils.cpp
@@ -30,6 +30,7 @@
 #endif
 
 //Qt
+#include <QBitmap>
 #include <QObject>
 #include <QErrorMessage>
 #include <QPainter>
@@ -261,6 +262,47 @@ Utils::getCirclePhoto(const QImage original, int sizePhoto)
     return target;
 }
 
+QImage
+Utils::getRoundedEdgePhoto(const QImage original, int widthPhoto, int heightPhoto, int roundness)
+{
+    // First, create a transparent image with the same size
+    QImage target(widthPhoto, heightPhoto, QImage::Format_ARGB32_Premultiplied);
+    target.fill(Qt::transparent);
+
+    //Second, create a painter onto that image
+    QPainter painter(&target);
+    painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
+    painter.setBrush(QBrush(original));
+    // set brush to the image that we want to draw
+    // Note that, the Qbrush is in default texture mode
+
+    //Third, scale the original image into the size of the image we created
+    auto scaledPhoto = original
+            .scaled(widthPhoto, heightPhoto, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation)
+            .convertToFormat(QImage::Format_ARGB32_Premultiplied);
+    painter.drawRoundedRect(0, 0, widthPhoto, heightPhoto, roundness, roundness);
+    painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
+    // Source-In mode and Draw the image onto the transperant image
+    painter.drawImage(0, 0, scaledPhoto, 0, 0);
+    return target;
+}
+
+void
+Utils::drawBlackCircularImageOntoLabel(QLabel* containerWidget)
+{
+    // Widget is black, fill image with white
+    // draw a black cycle onto it
+    QImage target(containerWidget->width(), containerWidget->height(), QImage::Format_ARGB32_Premultiplied);
+    target.fill(Qt::white);
+
+    QPainter painter(&target);
+    painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
+    painter.setBrush(QBrush(Qt::black));
+    painter.drawEllipse(containerWidget->x(), containerWidget->y(), containerWidget->width(), containerWidget->height());
+    painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
+    containerWidget->setPixmap(QPixmap::fromImage(target));
+}
+
 void
 Utils::setStackWidget(QStackedWidget* stack, QWidget* widget)
 {
diff --git a/utils.h b/utils.h
index c02cdac..b5e641e 100644
--- a/utils.h
+++ b/utils.h
@@ -25,6 +25,7 @@
 
 #include <QString>
 #include <QImage>
+#include <QLabel>
 #include <QStackedWidget>
 #include <QTextDocument>
 #include <QItemDelegate>
@@ -35,10 +36,8 @@
 #ifdef Q_OS_WIN
 #include <windows.h>
 #include <ciso646>
-#undef OUT
-#undef IN
 #undef ERROR
-#else //LINUX
+#else
 #define LPCWSTR char*
 #endif
 
@@ -67,6 +66,7 @@ void setStackWidget(QStackedWidget *stack, QWidget *widget);
 void showSystemNotification(QWidget* widget, const QString& message, long delay = 5000);
 void showSystemNotification(QWidget* widget, const QString& sender, const QString& message, long delay = 5000);
 QSize getRealSize(QScreen* screen);
+void drawBlackCircularImageOntoLabel(QLabel* containerWidget);
 
 // updates
 void cleanUpdateFiles();
@@ -92,6 +92,7 @@ bool isContactValid(const std::string& contactUid, const lrc::api::ConversationM
 
 // image
 QImage getCirclePhoto(const QImage original, int sizePhoto);
+QImage getRoundedEdgePhoto(const QImage original, int widthPhoto, int heightPhoto, int roundness);
 QImage conversationPhoto(const std::string& convUid, const lrc::api::account::Info& accountInfo);
 QColor getAvatarColor(const QString& canonicalUri);
 QImage fallbackAvatar(const QSize size, const QString& canonicalUriStr, const QString& letterStr = QString());
@@ -116,18 +117,6 @@ void swapQListWidgetItems(QListWidget* list, bool down = true);
 // Byte to human readable size
 QString humanFileSize(qint64 fileSize);
 
-// Video widget change enum
-enum class VideoWidgetSwapType
-{
-    CallWidgetToSettingsWidgetPreview,
-    CallWidgetToSettingsWidgetPhotoBooth,
-    SettingsWidgetPreviewToCallWidget,
-    SettingsWidgetPhotoBoothToCallWidget,
-    SettingsWidgetPhotoBoothToSettingsWidgetPreview,
-    SettingsWidgetPreviewToSettingsWidgetPhotoBooth,
-    VideoInputDeviceConnectionLost
-};
-
 // device plug or unplug enum
 enum class DevicePlugStatus
 {
diff --git a/videoview.cpp b/videoview.cpp
index cb45868..714d26e 100644
--- a/videoview.cpp
+++ b/videoview.cpp
@@ -69,7 +69,13 @@ VideoView::VideoView(QWidget* parent)
         emit this->setChatVisibility(visible);
         connect(this, SIGNAL(toggleFullScreenClicked()), ui->videoWidget, SLOT(slotToggleFullScreenClicked()));
     });
+
     audioOnlyAvatar_ = new CallAudioOnlyAvatarOverlay(this);
+    previewRenderer_ = PreviewRenderWidget::attachPreview();
+
+    moveAnim_ = new QPropertyAnimation(previewRenderer_, "geometry");
+    moveAnim_->setDuration(100);
+    moveAnim_->setEasingCurve(QEasingCurve::InOutQuad);
 }
 
 VideoView::~VideoView()
@@ -82,42 +88,12 @@ VideoView::~VideoView()
 void
 VideoView::resizeEvent(QResizeEvent* event)
 {
-    int marginWidth = ui->videoWidget->getPreviewMargin();
-    QRect& previewRect = ui->videoWidget->getPreviewRect();
-    int deltaW = event->size().width() - event->oldSize().width();
-    int deltaH = event->size().height() - event->oldSize().height();
-
-    QPoint previewCenter = ui->videoWidget->getPreviewRect().center();
-    int cx = (event->oldSize().width()) / 2;
-    int cy = (event->oldSize().height()) / 2;
-    QPoint center = QPoint(cx, cy);
-
-    // first we check if we want to displace the preview
-    if (previewRect.x() + deltaW > 0 && previewRect.y() + deltaH > 0) {
-        // then we check which way
-        if (center.x() - previewCenter.x() < 0 && center.y() - previewCenter.y() < 0)
-            ui->videoWidget->getPreviewRect().translate(deltaW, deltaH);
-        else if (center.x() - previewCenter.x() > 0 && center.y() - previewCenter.y() < 0)
-            ui->videoWidget->getPreviewRect().translate(0, deltaH);
-        else if (center.x() - previewCenter.x() < 0 && center.y() - previewCenter.y() > 0)
-            ui->videoWidget->getPreviewRect().translate(deltaW, 0);
-    }
-
-    if (previewRect.left() <= 0)
-        previewRect.moveLeft(marginWidth);
-    previewRect.moveRight(width() - marginWidth);
-
-    if (previewRect.right() >= width())
-        previewRect.moveRight(width() - marginWidth);
-
-    if (previewRect.top() <= 0)
-        previewRect.moveTop(marginWidth);
-    previewRect.moveBottom(height() - marginWidth);
-
-    if (previewRect.bottom() >= height())
-        previewRect.moveBottom(height() - marginWidth);
-
-    ui->videoWidget->resetPreview();
+    moveAnim_->stop();
+    previewRenderer_->setCurrentConainerGeo(event->size().width(), event->size().height());
+    previewRenderer_->resetPreview();
+    // force preview to repaint since the geo may be changed to hide
+    // the preview renderer
+    previewRenderer_->forceRepaint();
 
     audioOnlyAvatar_->resize(this->size());
 
@@ -274,10 +250,17 @@ VideoView::showContextMenu(const QPoint& pos)
         }
         connect(deviceAction, &QAction::triggered,
             [this, deviceName, thisCallId]() {
+                previewRenderer_->hide();
+                previewRenderer_->setCurrentConainerGeo(this->width(), this->height());
+                // since there is the possiblity of image not reloaded properly
+                // after rendering reconnect
+                previewRenderer_->triggerResetPreviewAfterImageReloaded();
+                previewRenderer_->connectRendering();
+                ui->videoWidget->connectDistantRendering();
+
                 auto decive = deviceName.toStdString();
                 LRCInstance::avModel().switchInputTo(decive);
                 LRCInstance::avModel().setCurrentVideoCaptureDevice(decive);
-                ui->videoWidget->connectRendering();
             });
     }
 
@@ -367,19 +350,20 @@ VideoView::pushRenderer(const std::string& callId, bool isSIP)
     callStatusChangedConnection_ = QObject::connect(callModel, &lrc::api::NewCallModel::callStatusChanged,
         this, &VideoView::slotCallStatusChanged);
 
-    ui->videoWidget->connectRendering();
-    ui->videoWidget->setPreviewDisplay(call.type != lrc::api::call::Type::CONFERENCE);
+    previewRenderer_->connectRendering();
+    ui->videoWidget->connectDistantRendering();
 }
 
 void
 VideoView::mousePressEvent(QMouseEvent* event)
 {
     QPoint clickPosition = event->pos();
-    if (ui->videoWidget->getPreviewRect().contains(clickPosition)) {
-        QLine distance = QLine(clickPosition, ui->videoWidget->getPreviewRect().bottomRight());
-            originMouseDisplacement_ = event->pos() - ui->videoWidget->getPreviewRect().topLeft();
-            QApplication::setOverrideCursor(Qt::SizeAllCursor);
-            draggingPreview_ = true;
+    if (previewRenderer_->geometry().contains(clickPosition)) {
+        QLine distance = QLine(clickPosition, previewRenderer_->geometry().bottomRight());
+        originMouseDisplacement_ = event->pos() - previewRenderer_->geometry().topLeft();
+        QApplication::setOverrideCursor(Qt::SizeAllCursor);
+        draggingPreview_ = true;
+        moveAnim_->stop();
     }
 }
 
@@ -389,27 +373,35 @@ VideoView::mouseReleaseEvent(QMouseEvent* event)
     Q_UNUSED(event)
     if (draggingPreview_) {
         //Check preview's current central position
-        QRect& previewRect = ui->videoWidget->getPreviewRect();
-        auto previewCentral = previewRect.center();
+        auto previewCentral = previewRenderer_->geometry().center();
         auto videoViewRect = ui->videoWidget->rect();
         auto videoWidgetCentral = videoViewRect.center();
+        auto previewInitialWidth = previewRenderer_->width();
+        auto previewInitialHeight = previewRenderer_->height();
+        moveAnim_->setStartValue(previewRenderer_->geometry());
         if (previewCentral.x() >= videoWidgetCentral.x()) {
             if (previewCentral.y() >= videoWidgetCentral.y()) {
                 //Move preview to bottom right
-                ui->videoWidget->movePreview(VideoWidget::TargetPointPreview::bottomRight);
+
+                moveAnim_->setEndValue(QRect(this->width() - previewMargin_ - previewInitialWidth, this->height() - previewMargin_ - previewInitialHeight,
+                                             previewInitialWidth, previewInitialHeight));
             } else {
                 //Move preview to top right
-                ui->videoWidget->movePreview(VideoWidget::TargetPointPreview::topRight);
+                moveAnim_->setEndValue(QRect(this->width() - previewMargin_ - previewInitialWidth, previewMargin_,
+                                             previewInitialWidth, previewInitialHeight));
             }
         } else {
             if (previewCentral.y() >= videoWidgetCentral.y()) {
                 //Move preview to bottom left
-                ui->videoWidget->movePreview(VideoWidget::TargetPointPreview::bottomLeft);
+                moveAnim_->setEndValue(QRect(previewMargin_, this->height() - previewMargin_ - previewInitialHeight,
+                                             previewInitialWidth, previewInitialHeight));
             } else {
                 //Move preview to top left
-                ui->videoWidget->movePreview(VideoWidget::TargetPointPreview::topLeft);
+                moveAnim_->setEndValue(QRect(previewMargin_, previewMargin_,
+                                             previewInitialWidth, previewInitialHeight));
             }
         }
+        moveAnim_->start();
     }
 
     draggingPreview_ = false;
@@ -426,7 +418,7 @@ VideoView::mouseMoveEvent(QMouseEvent* event)
         fadeTimer_.start(startfadeOverlayTime_);
     }
 
-    QRect& previewRect = ui->videoWidget->getPreviewRect();
+    QRect previewRect = previewRenderer_->geometry();
     if (draggingPreview_) {
         if (previewRect.left() > 0
             && previewRect.top() > 0
@@ -448,7 +440,8 @@ VideoView::mouseMoveEvent(QMouseEvent* event)
         }
     }
 
-    QLine distance = QLine(previewRect.topLeft(), event->pos());
+    previewRenderer_->setGeometry(previewRect);
+    previewRenderer_->forceRepaint();
 }
 
 void
@@ -492,22 +485,6 @@ VideoView::slotHoldStatusChanged(bool pauseLabelStatus)
     audioOnlyAvatar_->respondToPauseLabel(pauseLabelStatus);
 }
 
-void
-VideoView::disconnectRendering()
-{
-    ui->videoWidget->disconnectRendering();
-}
-
-void
-VideoView::connectRendering(bool started)
-{
-    if (started) {
-        ui->videoWidget->slotRendererStarted();
-    } else {
-        ui->videoWidget->connectRendering();
-    }
-}
-
 void
 VideoView::keyPressEvent(QKeyEvent* event)
 {
@@ -530,3 +507,9 @@ VideoView::keyReleaseEvent(QKeyEvent* event)
     }
     QWidget::keyReleaseEvent(event);
 }
+
+void
+VideoView::reconnectRenderingVideoDeviceChanged()
+{
+    ui->videoWidget->connectDistantRendering();
+}
diff --git a/videoview.h b/videoview.h
index 1d8c779..de5fc7c 100644
--- a/videoview.h
+++ b/videoview.h
@@ -20,11 +20,12 @@
 
 #include "callaudioonlyavataroverlay.h"
 #include "videooverlay.h"
+#include "previewrender.h"
 
 #include "api/conversationmodel.h"
 
-#include <QMouseEvent>
 #include <QKeyEvent>
+#include <QMouseEvent>
 #include <QPropertyAnimation>
 #include <QTimer>
 #include <QWidget>
@@ -44,8 +45,7 @@ public:
     void simulateShowChatview(bool checked);
     void setCurrentCalleeName(const QString& CalleeDisplayName);
     void resetVideoOverlay(bool isAudioMuted, bool isVideoMuted, bool isRecording, bool isHolding, bool isAudioOnly, const std::string& accountId, const lrc::api::conversation::Info& convInfo);
-    void disconnectRendering();
-    void connectRendering(bool started = false);
+    void reconnectRenderingVideoDeviceChanged();
 
 protected:
     void resizeEvent(QResizeEvent* event);
@@ -59,8 +59,8 @@ protected:
     void mousePressEvent(QMouseEvent* event);
     void mouseReleaseEvent(QMouseEvent* event);
     void mouseMoveEvent(QMouseEvent* event);
-    void keyPressEvent(QKeyEvent *event);
-    void keyReleaseEvent(QKeyEvent *event);
+    void keyPressEvent(QKeyEvent* event);
+    void keyReleaseEvent(QKeyEvent* event);
 
 private slots:
     void slotCallStatusChanged(const std::string& callId);
@@ -71,9 +71,11 @@ private slots:
 
 private:
     Ui::VideoView* ui;
+    PreviewRenderWidget* previewRenderer_;
     VideoOverlay* overlay_;
     CallAudioOnlyAvatarOverlay* audioOnlyAvatar_;
     QPropertyAnimation* fadeAnim_;
+    QPropertyAnimation* moveAnim_;
     QTimer fadeTimer_;
     QWidget* oldParent_;
     QSize oldSize_;
@@ -102,6 +104,7 @@ private:
     // https://bugreports.qt.io/browse/QTBUG-65981
     // https://bugreports.qt.io/browse/QTBUG-66803
     constexpr static qreal maxOverlayOpacity_ = 0.9999999999980000442;
+    constexpr static int previewMargin_ = 15;
 
 private:
     void toggleFullScreen();
@@ -112,5 +115,4 @@ signals:
     void videoSettingsClicked();
     void toggleFullScreenClicked();
     void closing(const std::string& callid);
-
 };
diff --git a/videowidget.cpp b/videowidget.cpp
index 7c36f41..a8e9d36 100644
--- a/videowidget.cpp
+++ b/videowidget.cpp
@@ -22,46 +22,40 @@
 
 #include "utils.h"
 
-VideoWidget::VideoWidget(QWidget* parent) :
-    QWidget(parent)
-  , isPreviewDisplayed_(true)
-  , fullPreview_(false)
+VideoWidget::VideoWidget(QWidget* parent)
+    : QWidget(parent)
 {
     QPalette pal(palette());
     pal.setColor(QPalette::Background, Qt::black);
     this->setAutoFillBackground(true);
     this->setPalette(pal);
-
-    previewPlace_ = bottomRight;
 }
 
 VideoWidget::~VideoWidget()
 {}
 
 void
-VideoWidget::slotRendererStarted(const std::string& id)
+VideoWidget::slotDistantRendererStarted(const std::string& id)
 {
     Q_UNUSED(id);
 
-    QObject::disconnect(rendererConnections_.started);
+    QObject::disconnect(rendererDistantConnections_.started);
 
     this->show();
 
-    resetPreview_ = true;
-
-    QObject::disconnect(rendererConnections_.updated);
-    rendererConnections_.updated = connect(
+    QObject::disconnect(rendererDistantConnections_.updated);
+    rendererDistantConnections_.updated = connect(
         &LRCInstance::avModel(),
         &lrc::api::AVModel::frameUpdated,
         this,
-        &VideoWidget::slotUpdateFullView);
+        &VideoWidget::slotUpdateDistantView);
 
-    QObject::disconnect(rendererConnections_.stopped);
-    rendererConnections_.stopped = connect(
+    QObject::disconnect(rendererDistantConnections_.stopped);
+    rendererDistantConnections_.stopped = connect(
         &LRCInstance::avModel(),
         &lrc::api::AVModel::rendererStopped,
         this,
-        &VideoWidget::slotStopFullView);
+        &VideoWidget::slotStopDistantView);
 }
 
 void
@@ -75,12 +69,7 @@ VideoWidget::renderFrame(const std::string& id)
             QMutexLocker lock(&mutex_);
             auto tmp  = renderer->currentFrame();
             if (tmp.storage.size()) {
-                using namespace lrc::api::video;
-                if (id == PREVIEW_RENDERER_ID) {
-                    previewFrame_ = tmp;
-                } else {
-                    distantFrame_ = tmp;
-                }
+                distantFrame_ = tmp;
             }
         }
         update();
@@ -123,288 +112,51 @@ VideoWidget::paintEvent(QPaintEvent* e)
             );
         }
     }
-    if ((previewRenderer_ && isPreviewDisplayed_) || (photoMode_ && hasFrame_)) {
-        QMutexLocker lock(&mutex_);
-        if (previewFrame_.storage.size() != 0
-            && previewFrame_.storage.size() ==
-            (unsigned int)(previewRenderer_->size().height() * previewRenderer_->size().width() * 4)) {
-            framePreview_ = std::move(previewFrame_.storage);
-            previewImage_.reset(
-                new QImage((uchar*)framePreview_.data(),
-                    previewRenderer_->size().width(),
-                    previewRenderer_->size().height(),
-                    QImage::Format_ARGB32_Premultiplied)
-            );
-            hasFrame_ = true;
-        }
-        if (previewImage_) {
-            if (resetPreview_) {
-                auto previewHeight = fullPreview_ ? height() : height() / 6;
-                auto previewWidth = fullPreview_ ? width() : width() / 6;
-                QImage scaledPreview;
-                if (photoMode_)
-                    scaledPreview = Utils::getCirclePhoto(*previewImage_, previewHeight);
-                else
-                    scaledPreview = previewImage_->scaled(previewWidth, previewHeight, Qt::KeepAspectRatio);
-                auto xDiff = (previewWidth - scaledPreview.width()) / 2;
-                auto yDiff = (previewHeight - scaledPreview.height()) / 2;
-                auto xPos = fullPreview_ ? xDiff : width() - scaledPreview.width() - previewMargin_;
-                auto yPos = fullPreview_ ? yDiff : height() - scaledPreview.height() - previewMargin_;
-                previewGeometry_.setRect(xPos, yPos, scaledPreview.width(), scaledPreview.height());
-                updatePreviewPos();
-                if (!fullPreview_) {
-                    QBrush brush(scaledPreview);
-                    brush.setTransform(QTransform::fromTranslate(previewGeometry_.x(), previewGeometry_.y()));
-                    QPainterPath previewPath;
-                    previewPath.addRoundRect(previewGeometry_, 25);
-                    painter.fillPath(previewPath, brush);
-                }
-                resetPreview_ = false;
-            }
-
-            QImage scaledPreview;
-            if (photoMode_) {
-                scaledPreview = Utils::getCirclePhoto(*previewImage_, previewGeometry_.height());
-            } else {
-                scaledPreview = previewImage_->scaled(previewGeometry_.width(),
-                                                      previewGeometry_.height(),
-                                                      Qt::KeepAspectRatio);
-            }
-            previewGeometry_.setWidth(scaledPreview.width());
-            previewGeometry_.setHeight(scaledPreview.height());
-            if (!fullPreview_){
-                QBrush brush(scaledPreview);
-                brush.setTransform(QTransform::fromTranslate(previewGeometry_.x(), previewGeometry_.y()));
-                QPainterPath previewPath;
-                previewPath.addRoundRect(previewGeometry_, 25);
-                painter.fillPath(previewPath, brush);
-            } else {
-                painter.drawImage(previewGeometry_, scaledPreview);
-            }
-        }
-    } else if (photoMode_) {
-        paintBackgroundColor(&painter, Qt::black);
-    }
     painter.end();
 }
 
 void
-VideoWidget::paintBackgroundColor(QPainter* painter, QColor color)
-{
-    QImage black(1, 1, QImage::Format_ARGB32);
-    black.fill(color);
-    QImage scaledPreview = Utils::getCirclePhoto(black, height());
-    previewGeometry_.setWidth(scaledPreview.width());
-    previewGeometry_.setHeight(scaledPreview.height());
-    painter->drawImage(previewGeometry_, scaledPreview);
-}
-
-void
-VideoWidget::updatePreviewPos()
-{
-    if (fullPreview_)
-        return;
-    switch (previewPlace_) {
-    case topRight:
-        previewGeometry_.moveTopRight(QPoint(width() - previewMargin_, previewMargin_));
-        break;
-    case topLeft:
-        previewGeometry_.moveTopLeft(QPoint(previewMargin_, previewMargin_));
-        break;
-    case bottomRight:
-        previewGeometry_.moveBottomRight(QPoint(width() - previewMargin_, height() - previewMargin_));
-        break;
-    case bottomLeft:
-        previewGeometry_.moveBottomLeft(QPoint(previewMargin_, height() - previewMargin_));
-        break;
-    case top:
-        previewGeometry_.moveTop(previewMargin_);
-        break;
-    case right:
-        previewGeometry_.moveRight(previewMargin_);
-        break;
-    case bottom:
-        previewGeometry_.moveBottom(previewMargin_);
-        break;
-    case left:
-        previewGeometry_.moveLeft(previewMargin_);
-        break;
-
-    default:
-        break;
-    }
-}
-
-void
-VideoWidget::movePreview(TargetPointPreview typeOfMove)
+VideoWidget::connectDistantRendering()
 {
-    resetPreview();
-    switch (typeOfMove)
-    {
-    case topRight:
-        previewPlace_ = topRight;
-        break;
-    case topLeft:
-        previewPlace_ = topLeft;
-        break;
-    case bottomRight:
-        previewPlace_ = bottomRight;
-        break;
-    case bottomLeft:
-        previewPlace_ = bottomLeft;
-        break;
-    case top:
-        previewPlace_ = top;
-        break;
-    case right:
-        previewPlace_ = right;
-        break;
-    case bottom:
-        previewPlace_ = bottom;
-        break;
-    case left:
-        previewPlace_ = left;
-        break;
-
-        default:
-        break;
-
-    }
-}
-
-void
-VideoWidget::connectRendering()
-{
-    rendererConnections_.started = connect(
+    QObject::disconnect(rendererDistantConnections_.started);
+    rendererDistantConnections_.started = connect(
         &LRCInstance::avModel(),
         SIGNAL(rendererStarted(const std::string&)),
         this,
-        SLOT(slotRendererStarted(const std::string&))
+        SLOT(slotDistantRendererStarted(const std::string&))
     );
 }
 
-void
-VideoWidget::connectPreviewOnlyRendering()
-{
-    rendererConnections_.started = connect(
-        &LRCInstance::avModel(),
-        &lrc::api::AVModel::rendererStarted,
-        [this]() {
-            this->rendererStartedWithoutDistantRender();
-        });
-}
-
-void
-VideoWidget::setPreviewDisplay(bool display)
-{
-    isPreviewDisplayed_ = display;
-}
-
-void
-VideoWidget::setIsFullPreview(bool full)
-{
-    fullPreview_ = full;
-}
-
-QImage
-VideoWidget::takePhoto()
-{
-    if (previewImage_) {
-        return previewImage_.get()->copy();
-    }
-    return QImage();
-}
-
-void
-VideoWidget::setPhotoMode(bool isPhotoMode)
-{
-
-    photoMode_ = isPhotoMode;
-    auto color = isPhotoMode ? Qt::transparent : Qt::black;
-
-    QPalette pal(palette());
-    pal.setColor(QPalette::Background, color);
-    setAutoFillBackground(true);
-    setPalette(pal);
-}
-
 void
 VideoWidget::disconnectRendering()
 {
-    QObject::disconnect(rendererConnections_.started);
-    QObject::disconnect(rendererConnections_.stopped);
-    QObject::disconnect(rendererConnections_.updated);
-}
-
-void
-VideoWidget::rendererStartedWithoutDistantRender()
-{
-    // connect only local preview rendering
-    QObject::disconnect(rendererConnections_.started);
-
-    this->show();
-
-    resetPreview_ = true;
-
-    QObject::disconnect(rendererConnections_.updated);
-    rendererConnections_.updated = connect(
-        &LRCInstance::avModel(),
-        &lrc::api::AVModel::frameUpdated,
-        this,
-        &VideoWidget::slotUpdatePreview);
-
-    QObject::disconnect(rendererConnections_.stopped);
-    rendererConnections_.stopped = connect(
-        &LRCInstance::avModel(),
-        &lrc::api::AVModel::rendererStopped,
-        this,
-        &VideoWidget::slotStopFullView);
+    QObject::disconnect(rendererDistantConnections_.started);
+    QObject::disconnect(rendererDistantConnections_.stopped);
+    QObject::disconnect(rendererDistantConnections_.updated);
 }
 
 void
-VideoWidget::slotUpdatePreview(const std::string& id)
+VideoWidget::slotUpdateDistantView(const std::string& id)
 {
-    auto avModel = &LRCInstance::avModel();
-    auto renderer = &avModel->getRenderer(id);
-    if (!renderer->isRendering()) {
+    if (id == lrc::api::video::PREVIEW_RENDERER_ID) {
         return;
     }
-    using namespace lrc::api::video;
-    if (id == PREVIEW_RENDERER_ID) {
-        previewRenderer_ = const_cast<Renderer*>(renderer);
-        renderFrame(id);
-    }
-}
-
-void
-VideoWidget::slotUpdateFullView(const std::string& id)
-{
     auto avModel = &LRCInstance::avModel();
     auto renderer = &avModel->getRenderer(id);
     if (!renderer->isRendering()) {
         return;
     }
-    using namespace lrc::api::video;
-    if (id == PREVIEW_RENDERER_ID) {
-        previewRenderer_ = const_cast<Renderer*>(renderer);
-    } else {
-        distantRenderer_ = const_cast<Renderer*>(renderer);
-    }
+    distantRenderer_ = const_cast<lrc::api::video::Renderer*>(renderer);
     renderFrame(id);
 }
 
 void
-VideoWidget::slotStopFullView(const std::string& id)
+VideoWidget::slotStopDistantView(const std::string& id)
 {
-    QObject::disconnect(rendererConnections_.updated);
+    Q_UNUSED(id);
+    QObject::disconnect(rendererDistantConnections_.updated);
+    QObject::disconnect(rendererDistantConnections_.stopped);
     using namespace lrc::api::video;
-    if (id == PREVIEW_RENDERER_ID) {
-        previewRenderer_ = nullptr;
-    } else {
-        distantRenderer_ = nullptr;
-    }
-    if (!previewRenderer_ && !distantRenderer_) {
-        QObject::disconnect(rendererConnections_.stopped);
-        repaint();
-    }
+    distantRenderer_ = nullptr;
+    repaint();
 }
diff --git a/videowidget.h b/videowidget.h
index dffed8e..45e34f0 100644
--- a/videowidget.h
+++ b/videowidget.h
@@ -37,54 +37,23 @@ class VideoWidget : public QWidget
 public:
     explicit VideoWidget(QWidget* parent = 0);
     ~VideoWidget();
-    void connectRendering();
-    void connectPreviewOnlyRendering();
-    void setPreviewDisplay(bool display);
-    void setIsFullPreview(bool full);
-    inline void setResetPreview(bool reset) { resetPreview_ = reset; hasFrame_=false; }
-    void setPhotoMode(bool isPhotoMode);
-    QImage takePhoto();
-    int getPreviewMargin(){ return previewMargin_; }
-    void resetPreview() { resetPreview_ = true; }
+    void connectDistantRendering();
     void disconnectRendering();
-    void rendererStartedWithoutDistantRender();
 
 protected:
     void paintEvent(QPaintEvent* e);
 
 public slots:
     void slotToggleFullScreenClicked();
-    void slotRendererStarted(const std::string& id = {});
-    void slotUpdatePreview(const std::string& id = {});
-    void slotUpdateFullView(const std::string& id = {});
-    void slotStopFullView(const std::string& id = {});
+    void slotDistantRendererStarted(const std::string& id = {});
+    void slotUpdateDistantView(const std::string& id = {});
+    void slotStopDistantView(const std::string& id = {});
     void renderFrame(const std::string& id);
-    inline QRect& getPreviewRect(){ return previewGeometry_; }
-
-public:
-    enum TargetPointPreview {
-        topRight,
-        topLeft,
-        bottomRight,
-        bottomLeft,
-        left,
-        right,
-        top,
-        bottom
-    };
-    void movePreview(TargetPointPreview typeOfMove);
 
 private:
-    struct rendererConnections {
+    struct rendererDistantConnections {
         QMetaObject::Connection started, stopped, updated;
-    } rendererConnections_;
-
-    void paintBackgroundColor(QPainter* painter, QColor color);
-
-    video::Renderer* previewRenderer_;
-    video::Frame previewFrame_;
-    std::unique_ptr<QImage> previewImage_;
-    std::vector<uint8_t> framePreview_;
+    } rendererDistantConnections_;
 
     video::Renderer* distantRenderer_;
     video::Frame distantFrame_;
@@ -92,20 +61,4 @@ private:
     std::vector<uint8_t> frameDistant_;
 
     QMutex mutex_;
-
-    bool isPreviewDisplayed_;
-    bool fullPreview_;
-    QRect previewGeometry_;
-    bool resetPreview_ = false;
-    bool photoMode_ = false;
-    bool hasFrame_ = false;
-    TargetPointPreview previewPlace_;
-
-    constexpr static int previewMargin_ = 15;
-
-
-
-private:
-    void updatePreviewPos();
-
 };
-- 
GitLab