From b1f294f58c9b78fb299c44f9f5b919f42c1aa119 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Thu, 16 Mar 2017 12:09:02 +0100 Subject: [PATCH] feat(src/components/camera/Camera): deal with multi-threads --- .../src/components/calls/CallsListModel.cpp | 4 +- .../src/components/camera/Camera.cpp | 94 +++++++++---------- .../src/components/camera/Camera.hpp | 20 ++-- .../src/components/core/CoreManager.cpp | 33 +++---- 4 files changed, 71 insertions(+), 80 deletions(-) diff --git a/linphone-desktop/src/components/calls/CallsListModel.cpp b/linphone-desktop/src/components/calls/CallsListModel.cpp index 12493eea2..3e90d16cc 100644 --- a/linphone-desktop/src/components/calls/CallsListModel.cpp +++ b/linphone-desktop/src/components/calls/CallsListModel.cpp @@ -74,9 +74,7 @@ CallsListModel::CallsListModel (QObject *parent) : QAbstractListModel(parent) { default: break; } - }, - // Necessary to avoid a segfault if a video stream exists. - Qt::DirectConnection + } ); } diff --git a/linphone-desktop/src/components/camera/Camera.cpp b/linphone-desktop/src/components/camera/Camera.cpp index 0415015ad..d944004a1 100644 --- a/linphone-desktop/src/components/camera/Camera.cpp +++ b/linphone-desktop/src/components/camera/Camera.cpp @@ -64,21 +64,13 @@ struct ContextInfo { // ----------------------------------------------------------------------------- -inline void setWindowId (const Camera &camera) { - ContextInfo *context_info = camera.m_context_info; - - qInfo() << QStringLiteral("Set context info (width: %1, height: %2, is_preview: %3).") - .arg(context_info->width).arg(context_info->height).arg(camera.m_is_preview); - - if (camera.m_is_preview) - CoreManager::getInstance()->getCore()->setNativePreviewWindowId(context_info); - else - camera.m_call->getLinphoneCall()->setNativeVideoWindowId(context_info); +CameraRenderer::CameraRenderer () { + m_context_info = new ContextInfo(); } -// ----------------------------------------------------------------------------- - -CameraRenderer::CameraRenderer (const Camera *camera) : m_camera(camera) {} +CameraRenderer::~CameraRenderer () { + delete m_context_info; +} QOpenGLFramebufferObject *CameraRenderer::createFramebufferObject (const QSize &size) { QOpenGLFramebufferObjectFormat format; @@ -86,23 +78,21 @@ QOpenGLFramebufferObject *CameraRenderer::createFramebufferObject (const QSize & format.setInternalTextureFormat(GL_RGBA8); format.setSamples(4); - ContextInfo *context_info = m_camera->m_context_info; - context_info->width = size.width(); - context_info->height = size.height(); + m_context_info->width = size.width(); + m_context_info->height = size.height(); + m_context_info->functions = MSFunctions::getInstance()->getFunctions(); - setWindowId(*m_camera); + m_need_sync = true; return new QOpenGLFramebufferObject(size, format); } void CameraRenderer::render () { + if (!m_linphone_call) + return; + CameraStateBinder state(this); - QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); - - f->glClearColor(0.f, 0.f, 0.f, 0.f); - f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // Draw with ms filter. { QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); @@ -116,7 +106,7 @@ void CameraRenderer::render () { core->lockVideoRender(); ms_functions->bind(f); - m_camera->getCall()->getLinphoneCall()->oglRender(m_camera->m_is_preview); + m_linphone_call->oglRender(m_is_preview); ms_functions->bind(nullptr); core->unlockVideoRender(); @@ -132,6 +122,31 @@ void CameraRenderer::render () { void CameraRenderer::synchronize (QQuickFramebufferObject *item) { m_window = item->window(); + + if (!m_need_sync) { + Camera *camera = qobject_cast(item); + + shared_ptr linphone_call = camera->getCall()->getLinphoneCall(); + bool is_preview = camera->m_is_preview; + + if (m_linphone_call == linphone_call && m_is_preview == is_preview) + return; + + m_linphone_call = linphone_call; + m_is_preview = is_preview; + } + + m_need_sync = false; + + qInfo() << QStringLiteral("Set context info (width: %1, height: %2, is_preview: %3).") + .arg(m_context_info->width).arg(m_context_info->height).arg(m_is_preview); + + void *window_id = const_cast(m_context_info); + + if (m_is_preview) + CoreManager::getInstance()->getCore()->setNativePreviewWindowId(window_id); + else + m_linphone_call->setNativeVideoWindowId(window_id); } // ----------------------------------------------------------------------------- @@ -142,41 +157,23 @@ Camera::Camera (QQuickItem *parent) : QQuickFramebufferObject(parent) { // The fbo content must be y-mirrored because the ms rendering is y-inverted. setMirrorVertically(true); - - m_context_info = new ContextInfo(); - m_context_info->functions = MSFunctions::getInstance()->getFunctions(); } Camera::~Camera () { + CoreManager *core = CoreManager::getInstance(); + + core->lockVideoRender(); + if (m_is_preview) CoreManager::getInstance()->getCore()->setNativePreviewWindowId(nullptr); else m_call->getLinphoneCall()->setNativeVideoWindowId(nullptr); - delete m_context_info; + core->unlockVideoRender(); } QQuickFramebufferObject::Renderer *Camera::createRenderer () const { - m_renderer = new CameraRenderer(this); - return m_renderer; -} - -// ----------------------------------------------------------------------------- - -void Camera::takeScreenshot () { - m_screenshot = m_renderer->framebufferObject()->toImage(); -} - -void Camera::saveScreenshot (const QString &path) { - QString formatted_path = path.startsWith("file://") ? path.mid(sizeof("file://") - 1) : path; - QFileInfo info(formatted_path); - QString extension = info.suffix(); - - m_screenshot.save( - formatted_path, - extension.size() > 0 ? ::Utils::qStringToLinphoneString(extension).c_str() : "jpg", - 100 - ); + return new CameraRenderer(); } // ----------------------------------------------------------------------------- @@ -193,8 +190,7 @@ CallModel *Camera::getCall () const { void Camera::setCall (CallModel *call) { if (m_call != call) { - if ((m_call = call)) - setWindowId(*this); + m_call = call; emit callChanged(m_call); } diff --git a/linphone-desktop/src/components/camera/Camera.hpp b/linphone-desktop/src/components/camera/Camera.hpp index e0db60615..3e27624f7 100644 --- a/linphone-desktop/src/components/camera/Camera.hpp +++ b/linphone-desktop/src/components/camera/Camera.hpp @@ -23,7 +23,6 @@ #ifndef CAMERA_H_ #define CAMERA_H_ -#include #include #include @@ -38,8 +37,8 @@ class CameraRenderer : public QQuickFramebufferObject::Renderer { friend class Camera; public: - CameraRenderer (const Camera *camera); - ~CameraRenderer () = default; + CameraRenderer (); + ~CameraRenderer (); protected: QOpenGLFramebufferObject *createFramebufferObject (const QSize &size) override; @@ -47,7 +46,12 @@ protected: void synchronize (QQuickFramebufferObject *item) override; private: - const Camera *m_camera; + ContextInfo *m_context_info; + bool m_need_sync = false; + + bool m_is_preview = false; + shared_ptr m_linphone_call; + QQuickWindow *m_window; }; @@ -55,7 +59,6 @@ private: class Camera : public QQuickFramebufferObject { friend class CameraRenderer; - friend void setWindowId (const Camera &camera); Q_OBJECT; @@ -68,9 +71,6 @@ public: QQuickFramebufferObject::Renderer *createRenderer () const override; - Q_INVOKABLE void takeScreenshot (); - Q_INVOKABLE void saveScreenshot (const QString &path); - signals: void callChanged (CallModel *call); void isPreviewChanged (bool is_preview); @@ -84,10 +84,6 @@ private: bool m_is_preview = false; CallModel *m_call = nullptr; - ContextInfo *m_context_info; - QImage m_screenshot; - - mutable CameraRenderer *m_renderer; }; #endif // CAMERA_H_ diff --git a/linphone-desktop/src/components/core/CoreManager.cpp b/linphone-desktop/src/components/core/CoreManager.cpp index bbf254c3d..3ba412ec3 100644 --- a/linphone-desktop/src/components/core/CoreManager.cpp +++ b/linphone-desktop/src/components/core/CoreManager.cpp @@ -55,25 +55,26 @@ void CoreManager::enableHandlers () { } void CoreManager::init (QObject *parent, const QString &config_path) { - if (!m_instance) { - m_instance = new CoreManager(parent, config_path); + if (m_instance) + return; - m_instance->m_calls_list_model = new CallsListModel(m_instance); - m_instance->m_contacts_list_model = new ContactsListModel(m_instance); - m_instance->m_sip_addresses_model = new SipAddressesModel(m_instance); - m_instance->m_settings_model = new SettingsModel(m_instance); + m_instance = new CoreManager(parent, config_path); - QTimer *timer = m_instance->m_cbs_timer = new QTimer(m_instance); - timer->setInterval(20); + m_instance->m_calls_list_model = new CallsListModel(m_instance); + m_instance->m_contacts_list_model = new ContactsListModel(m_instance); + m_instance->m_sip_addresses_model = new SipAddressesModel(m_instance); + m_instance->m_settings_model = new SettingsModel(m_instance); - QObject::connect( - timer, &QTimer::timeout, m_instance, []() { - m_instance->m_mutex_video_render.lock(); - m_instance->m_core->iterate(); - m_instance->m_mutex_video_render.unlock(); - } - ); - } + QTimer *timer = m_instance->m_cbs_timer = new QTimer(m_instance); + timer->setInterval(20); + + QObject::connect( + timer, &QTimer::timeout, m_instance, []() { + m_instance->lockVideoRender(); + m_instance->m_core->iterate(); + m_instance->unlockVideoRender(); + } + ); } VcardModel *CoreManager::createDetachedVcardModel () {