mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-05-07 14:44:01 +00:00
feat(src/components/camera/Camera): deal with multi-threads
This commit is contained in:
parent
9b13de1084
commit
b1f294f58c
4 changed files with 71 additions and 80 deletions
|
|
@ -74,9 +74,7 @@ CallsListModel::CallsListModel (QObject *parent) : QAbstractListModel(parent) {
|
|||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
// Necessary to avoid a segfault if a video stream exists.
|
||||
Qt::DirectConnection
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Camera *>(item);
|
||||
|
||||
shared_ptr<linphone::Call> 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<ContextInfo *>(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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
#ifndef CAMERA_H_
|
||||
#define CAMERA_H_
|
||||
|
||||
#include <QImage>
|
||||
#include <QOpenGLFramebufferObject>
|
||||
#include <QQuickFramebufferObject>
|
||||
|
||||
|
|
@ -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<linphone::Call> 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_
|
||||
|
|
|
|||
|
|
@ -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 () {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue