diff --git a/src/avatarmanipulation.cpp b/src/avatarmanipulation.cpp
index 3ad61cca64c683c4eed69e0d2bc99adf6fca2e89..f3d343201340c8a301d0bf69b81c8a7ffc4e7608 100644
--- a/src/avatarmanipulation.cpp
+++ b/src/avatarmanipulation.cpp
@@ -118,7 +118,7 @@ avatar_manipulation_dispose(GObject *object)
 
     /* make sure we stop the preview and the video widget */
     if (priv->video_started_by_avatar_manipulation)
-        priv->avModel_->stopPreview(priv->avModel_->getDefaultDevice());
+        priv->avModel_->stopPreview("camera://" + priv->avModel_->getDefaultDevice());
     if (priv->video_widget) {
         gtk_container_remove(GTK_CONTAINER(priv->frame_video), priv->video_widget);
         priv->video_widget = NULL;
@@ -264,7 +264,7 @@ set_state(AvatarManipulation *self, AvatarManipulationState state)
 
             /* make sure video widget and camera is not running */
             if (priv->video_started_by_avatar_manipulation) {
-                priv->avModel_->stopPreview(priv->avModel_->getDefaultDevice());
+                priv->avModel_->stopPreview("camera://" + priv->avModel_->getDefaultDevice());
                 QObject::disconnect(priv->local_renderer_connection);
             }
             if (priv->video_widget) {
@@ -288,8 +288,7 @@ set_state(AvatarManipulation *self, AvatarManipulationState state)
             // local renderer, but set as "remote" so that it takes up the whole screen
             const lrc::api::video::Renderer* prenderer = nullptr;
             try {
-                prenderer = &priv->avModel_->getRenderer(
-                    lrc::api::video::PREVIEW_RENDERER_ID);
+                prenderer = &priv->avModel_->getRenderer("camera://" + priv->avModel_->getDefaultDevice());
             } catch (const std::out_of_range& e) {}
 
             priv->video_started_by_avatar_manipulation =
@@ -305,7 +304,7 @@ set_state(AvatarManipulation *self, AvatarManipulationState state)
                     &*priv->avModel_,
                     &lrc::api::AVModel::rendererStarted,
                     [=](const QString& id) {
-                        if (id != lrc::api::video::PREVIEW_RENDERER_ID)
+                        if (id.indexOf( priv->avModel_->getDefaultDevice()) == -1)
                             return;
                         try {
                             const auto* prenderer =
@@ -318,7 +317,7 @@ set_state(AvatarManipulation *self, AvatarManipulationState state)
                             g_warning("Cannot start preview");
                         }
                     });
-                priv->avModel_->startPreview(priv->avModel_->getDefaultDevice());
+                priv->avModel_->startPreview("camera://" + priv->avModel_->getDefaultDevice());
             }
 
             /* available actions: take snapshot, return*/
@@ -331,7 +330,7 @@ set_state(AvatarManipulation *self, AvatarManipulationState state)
         {
             /* make sure video widget and camera is not running */
             if (priv->video_started_by_avatar_manipulation)
-                priv->avModel_->stopPreview(priv->avModel_->getDefaultDevice());
+                priv->avModel_->stopPreview("camera://" + priv->avModel_->getDefaultDevice());
             if (priv->video_widget) {
                 gtk_container_remove(GTK_CONTAINER(priv->frame_video), priv->video_widget);
                 priv->video_widget = NULL;
diff --git a/src/chatview.cpp b/src/chatview.cpp
index ed1268360d7ad3dfb51ce1bdb728ef1f12b2e045..558f056b3b83c141301ff1d080330b79944ca780 100644
--- a/src/chatview.cpp
+++ b/src/chatview.cpp
@@ -436,7 +436,7 @@ on_record_closed(GtkPopover*, ChatView *self)
     priv->cpp->current_action_ = RecordAction::RECORD;
     if (priv->timer_duration) g_source_remove(priv->timer_duration);
     if (priv->is_video_record) {
-        priv->cpp->avModel_->stopPreview(priv->cpp->avModel_->getDefaultDevice());
+        priv->cpp->avModel_->stopPreview("camera://" + priv->cpp->avModel_->getDefaultDevice());
         QObject::disconnect(priv->local_renderer_connection);
     }
     priv->duration = 0;
@@ -484,7 +484,7 @@ chat_view_show_recorder(ChatView *self, int pt_x, int pt_y, bool is_video_record
 
     priv->is_video_record = is_video_record;
     if (is_video_record)
-      priv->cpp->avModel_->startPreview(priv->cpp->avModel_->getDefaultDevice());
+      priv->cpp->avModel_->startPreview("camera://" + priv->cpp->avModel_->getDefaultDevice());
     std::string css = is_video_record ? ".record-button { background: rgba(0, 0, 0, 0.2); border-radius: 50%; border: 0; transition: all 0.3s ease; } \
         .record-button:hover { background: rgba(0, 0, 0, 0.2); border-radius: 50%; border: 0; transition: all 0.3s ease; } \
         .label_time { color: white; }"
@@ -1287,7 +1287,7 @@ on_main_action_clicked(ChatView *self)
             }
             gtk_widget_destroy(priv->record_popover);
             priv->cpp->current_action_ = RecordAction::RECORD;
-            priv->cpp->avModel_->stopPreview(priv->cpp->avModel_->getDefaultDevice());
+            priv->cpp->avModel_->stopPreview("camera://" + priv->cpp->avModel_->getDefaultDevice());
             QObject::disconnect(priv->local_renderer_connection);
             break;
         }
@@ -1305,7 +1305,7 @@ init_video_widget(ChatView* self)
     const lrc::api::video::Renderer* prenderer = nullptr;
     try {
         prenderer = &priv->cpp->avModel_->getRenderer(
-            lrc::api::video::PREVIEW_RENDERER_ID);
+            "camera://" + priv->cpp->avModel_->getDefaultDevice());
     } catch (const std::out_of_range& e) {}
 
     priv->video_started_by_settings =
@@ -1322,7 +1322,7 @@ init_video_widget(ChatView* self)
             &*priv->cpp->avModel_,
             &lrc::api::AVModel::rendererStarted,
             [=](const QString& id) {
-                if (id != lrc::api::video::PREVIEW_RENDERER_ID
+                if (id.indexOf(priv->cpp->avModel_->getDefaultDevice()) == -1
                     || !priv->readyToRecord_)
                     return;
                 try {
diff --git a/src/currentcallview.cpp b/src/currentcallview.cpp
index 48a2feff5d34a5beef72e32c75b1ca00c9d10428..6e6c3d1f8844f016ebfcdcf3b300fa360831ba9b 100644
--- a/src/currentcallview.cpp
+++ b/src/currentcallview.cpp
@@ -1436,7 +1436,7 @@ CppImpl::setCallInfo()
         // local renderer
         const lrc::api::video::Renderer* previewRenderer =
              &avModel_->getRenderer(
-             lrc::api::video::PREVIEW_RENDERER_ID);
+             "camera://" + avModel_->getDefaultDevice());
         if (previewRenderer->isRendering()) {
             video_widget_add_new_renderer(VIDEO_WIDGET(widgets->video_widget),
                 avModel_, previewRenderer, VIDEO_RENDERER_LOCAL);
@@ -1478,11 +1478,11 @@ CppImpl::setCallInfo()
         &*avModel_,
         &lrc::api::AVModel::rendererStarted,
         [=](const QString& id) {
-            if (id == lrc::api::video::PREVIEW_RENDERER_ID) {
+            if (id.indexOf("://") != -1) {
                 try {
                     // local renderer
                     const lrc::api::video::Renderer* previewRenderer =
-                        &avModel_->getRenderer(lrc::api::video::PREVIEW_RENDERER_ID);
+                        &avModel_->getRenderer(id);
                     if (previewRenderer->isRendering()) {
                         video_widget_add_new_renderer(VIDEO_WIDGET(widgets->video_widget),
                             avModel_, previewRenderer, VIDEO_RENDERER_LOCAL);
diff --git a/src/mediasettingsview.cpp b/src/mediasettingsview.cpp
index 2ce842f0aa4daea4bd7c706e0f1fa5cd8fbf902e..01251f599408383c831ced1ce635ab5d1568e4c0 100644
--- a/src/mediasettingsview.cpp
+++ b/src/mediasettingsview.cpp
@@ -390,7 +390,7 @@ CppImpl::drawVideoDevices()
         gtk_widget_hide(widgets->video_resolution_row);
         gtk_widget_hide(widgets->video_framerate_row);
         if (widgets->video_widget)
-            avModel_->stopPreview(avModel_->getDefaultDevice());
+            avModel_->stopPreview("camera://" + avModel_->getDefaultDevice());
         return;
     }
     if (gtk_widget_get_visible(widgets->no_camera_row)) {
@@ -445,7 +445,7 @@ media_settings_view_dispose(GObject *object)
 
     /* make sure to stop the preview if this view is getting destroyed */
     if (priv->video_started_by_settings) {
-        priv->cpp->avModel_->stopPreview(priv->cpp->avModel_->getDefaultDevice());
+        priv->cpp->avModel_->stopPreview("camera://" + priv->cpp->avModel_->getDefaultDevice());
         priv->video_started_by_settings = FALSE;
     }
 
@@ -852,7 +852,7 @@ media_settings_view_show_preview(MediaSettingsView *self, gboolean show_preview)
                     &*priv->cpp->avModel_,
                     &lrc::api::AVModel::rendererStarted,
                     [=](const QString& id) {
-                        if (id != lrc::api::video::PREVIEW_RENDERER_ID)
+                        if (id.indexOf(priv->cpp->avModel_->getDefaultDevice()) == -1)
                             return;
                         const auto* prenderer = &priv->cpp->avModel_->getRenderer(id);
                         video_widget_add_new_renderer(
@@ -869,7 +869,7 @@ media_settings_view_show_preview(MediaSettingsView *self, gboolean show_preview)
         const lrc::api::video::Renderer* prenderer = nullptr;
         try {
             prenderer = &priv->cpp->avModel_->getRenderer(
-                lrc::api::video::PREVIEW_RENDERER_ID);
+                "camera://" + priv->cpp->avModel_->getDefaultDevice());
         } catch (const std::out_of_range& e) {
         }
         if (prenderer){
@@ -879,13 +879,13 @@ media_settings_view_show_preview(MediaSettingsView *self, gboolean show_preview)
                 prenderer, VIDEO_RENDERER_REMOTE);
         }
         else
-            priv->cpp->avModel_->startPreview(priv->cpp->avModel_->getDefaultDevice());
+            priv->cpp->avModel_->startPreview("camera://" + priv->cpp->avModel_->getDefaultDevice());
 
         priv->cpp->avModel_->startAudioDevice();
         priv->cpp->avModel_->setAudioMeterState(true);
     } else {
         if (priv->video_started_by_settings) {
-            priv->cpp->avModel_->stopPreview(priv->cpp->avModel_->getDefaultDevice());
+            priv->cpp->avModel_->stopPreview("camera://" + priv->cpp->avModel_->getDefaultDevice());
             QObject::disconnect(priv->local_renderer_connection);
             QObject::disconnect(priv->device_event_connection);
             priv->video_started_by_settings = FALSE;
diff --git a/src/video/video_widget.cpp b/src/video/video_widget.cpp
index 09e8900597d563a519927db1cc0f000c616810ec..d52308ca410914d0618b1c458de8b5447bc74ff7 100644
--- a/src/video/video_widget.cpp
+++ b/src/video/video_widget.cpp
@@ -141,6 +141,8 @@ public:
     VideoWidget* self = nullptr; // The GTK widget itself
     AccountInfoPointer const *accountInfo = nullptr;
     QString callId {};
+
+    std::vector<uint8_t> buffer;
 };
 
 }
@@ -990,7 +992,7 @@ free_pixels(guchar *pixels, gpointer)
 }
 
 static void
-clutter_render_image(VideoWidgetRenderer* wg_renderer)
+clutter_render_image(VideoWidgetRenderer* wg_renderer, VideoWidgetPrivate* priv)
 {
     auto actor = wg_renderer->actor;
     g_return_if_fail(CLUTTER_IS_ACTOR(actor));
@@ -1055,10 +1057,27 @@ clutter_render_image(VideoWidgetRenderer* wg_renderer)
         auto v_renderer = wg_renderer->v_renderer;
         if (!v_renderer)
             return;
-        auto frame_data = v_renderer->currentFrame().ptr;
-        if (!frame_data)
-            return;
+        auto frame = v_renderer->currentFrame();
+
+        auto size = 0;
+        unsigned int width = v_renderer->size().width();
+        unsigned int height = v_renderer->size().height();
+        if (v_renderer->useDirectRenderer()) {
+            size = frame.storage.size();
+        } else {
+            size = frame.size;
+        }
 
+        if (size != 0 && size == width * height * 4) {
+            if (v_renderer->useDirectRenderer()) {
+                priv->cpp->buffer = std::move(frame.storage);
+            } else {
+                priv->cpp->buffer.resize(size);
+                std::move(frame.ptr, frame.ptr + size, priv->cpp->buffer.begin());
+            }
+        } else {
+            return;
+        }
         image_new = clutter_image_new();
         g_return_if_fail(image_new);
 
@@ -1069,7 +1088,7 @@ clutter_render_image(VideoWidgetRenderer* wg_renderer)
         GError *error = nullptr;
         clutter_image_set_data(
             CLUTTER_IMAGE(image_new),
-            frame_data,
+            priv->cpp->buffer.data(),
             COGL_PIXEL_FORMAT_BGRA_8888,
             res.width(),
             res.height(),
@@ -1090,9 +1109,9 @@ clutter_render_image(VideoWidgetRenderer* wg_renderer)
 
             /* conversion from BGRA to RGB */
             for(int i = 0, j = 0 ; i < res.width() * res.height() * 4 ; i += 4, j += 3 ) {
-                pixbuf_frame_data[j + 0] = frame_data[i + 2];
-                pixbuf_frame_data[j + 1] = frame_data[i + 1];
-                pixbuf_frame_data[j + 2] = frame_data[i + 0];
+                pixbuf_frame_data[j + 0] = priv->cpp->buffer[i + 2];
+                pixbuf_frame_data[j + 1] = priv->cpp->buffer[i + 1];
+                pixbuf_frame_data[j + 2] = priv->cpp->buffer[i + 0];
             }
 
             if (wg_renderer->snapshot) {
@@ -1129,9 +1148,9 @@ check_frame_queue(VideoWidget *self)
         return TRUE;
 
     /* display renderer's frames */
-    if (priv->show_preview)
-        clutter_render_image(priv->local);
-    clutter_render_image(priv->remote);
+    if (priv->show_preview && priv->local)
+        clutter_render_image(priv->local, priv);
+    clutter_render_image(priv->remote, priv);
 
     // HACK: https://gitlab.gnome.org/GNOME/clutter-gtk/-/issues/11
     // Because the CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT change the ratio of the widget inside the actor
@@ -1194,6 +1213,7 @@ free_video_widget_renderer(VideoWidgetRenderer *renderer)
 {
     QObject::disconnect(renderer->render_stop);
     QObject::disconnect(renderer->render_start);
+    renderer_stop(renderer);
     if (renderer->snapshot)
         g_object_unref(renderer->snapshot);
     g_free(renderer);