Commit b1f294f5 authored by Ronan Abhamon's avatar Ronan Abhamon

feat(src/components/camera/Camera): deal with multi-threads

parent 9b13de10
...@@ -74,9 +74,7 @@ CallsListModel::CallsListModel (QObject *parent) : QAbstractListModel(parent) { ...@@ -74,9 +74,7 @@ CallsListModel::CallsListModel (QObject *parent) : QAbstractListModel(parent) {
default: default:
break; break;
} }
}, }
// Necessary to avoid a segfault if a video stream exists.
Qt::DirectConnection
); );
} }
......
...@@ -64,21 +64,13 @@ struct ContextInfo { ...@@ -64,21 +64,13 @@ struct ContextInfo {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
inline void setWindowId (const Camera &camera) { CameraRenderer::CameraRenderer () {
ContextInfo *context_info = camera.m_context_info; m_context_info = new ContextInfo();
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 () {
delete m_context_info;
CameraRenderer::CameraRenderer (const Camera *camera) : m_camera(camera) {} }
QOpenGLFramebufferObject *CameraRenderer::createFramebufferObject (const QSize &size) { QOpenGLFramebufferObject *CameraRenderer::createFramebufferObject (const QSize &size) {
QOpenGLFramebufferObjectFormat format; QOpenGLFramebufferObjectFormat format;
...@@ -86,22 +78,20 @@ QOpenGLFramebufferObject *CameraRenderer::createFramebufferObject (const QSize & ...@@ -86,22 +78,20 @@ QOpenGLFramebufferObject *CameraRenderer::createFramebufferObject (const QSize &
format.setInternalTextureFormat(GL_RGBA8); format.setInternalTextureFormat(GL_RGBA8);
format.setSamples(4); format.setSamples(4);
ContextInfo *context_info = m_camera->m_context_info; m_context_info->width = size.width();
context_info->width = size.width(); m_context_info->height = size.height();
context_info->height = size.height(); m_context_info->functions = MSFunctions::getInstance()->getFunctions();
setWindowId(*m_camera); m_need_sync = true;
return new QOpenGLFramebufferObject(size, format); return new QOpenGLFramebufferObject(size, format);
} }
void CameraRenderer::render () { void CameraRenderer::render () {
CameraStateBinder state(this); if (!m_linphone_call)
return;
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
f->glClearColor(0.f, 0.f, 0.f, 0.f); CameraStateBinder state(this);
f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Draw with ms filter. // Draw with ms filter.
{ {
...@@ -116,7 +106,7 @@ void CameraRenderer::render () { ...@@ -116,7 +106,7 @@ void CameraRenderer::render () {
core->lockVideoRender(); core->lockVideoRender();
ms_functions->bind(f); 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); ms_functions->bind(nullptr);
core->unlockVideoRender(); core->unlockVideoRender();
...@@ -132,6 +122,31 @@ void CameraRenderer::render () { ...@@ -132,6 +122,31 @@ void CameraRenderer::render () {
void CameraRenderer::synchronize (QQuickFramebufferObject *item) { void CameraRenderer::synchronize (QQuickFramebufferObject *item) {
m_window = item->window(); 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) { ...@@ -142,41 +157,23 @@ Camera::Camera (QQuickItem *parent) : QQuickFramebufferObject(parent) {
// The fbo content must be y-mirrored because the ms rendering is y-inverted. // The fbo content must be y-mirrored because the ms rendering is y-inverted.
setMirrorVertically(true); setMirrorVertically(true);
m_context_info = new ContextInfo();
m_context_info->functions = MSFunctions::getInstance()->getFunctions();
} }
Camera::~Camera () { Camera::~Camera () {
CoreManager *core = CoreManager::getInstance();
core->lockVideoRender();
if (m_is_preview) if (m_is_preview)
CoreManager::getInstance()->getCore()->setNativePreviewWindowId(nullptr); CoreManager::getInstance()->getCore()->setNativePreviewWindowId(nullptr);
else else
m_call->getLinphoneCall()->setNativeVideoWindowId(nullptr); m_call->getLinphoneCall()->setNativeVideoWindowId(nullptr);
delete m_context_info; core->unlockVideoRender();
} }
QQuickFramebufferObject::Renderer *Camera::createRenderer () const { QQuickFramebufferObject::Renderer *Camera::createRenderer () const {
m_renderer = new CameraRenderer(this); return new CameraRenderer();
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
);
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
...@@ -193,8 +190,7 @@ CallModel *Camera::getCall () const { ...@@ -193,8 +190,7 @@ CallModel *Camera::getCall () const {
void Camera::setCall (CallModel *call) { void Camera::setCall (CallModel *call) {
if (m_call != call) { if (m_call != call) {
if ((m_call = call)) m_call = call;
setWindowId(*this);
emit callChanged(m_call); emit callChanged(m_call);
} }
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#ifndef CAMERA_H_ #ifndef CAMERA_H_
#define CAMERA_H_ #define CAMERA_H_
#include <QImage>
#include <QOpenGLFramebufferObject> #include <QOpenGLFramebufferObject>
#include <QQuickFramebufferObject> #include <QQuickFramebufferObject>
...@@ -38,8 +37,8 @@ class CameraRenderer : public QQuickFramebufferObject::Renderer { ...@@ -38,8 +37,8 @@ class CameraRenderer : public QQuickFramebufferObject::Renderer {
friend class Camera; friend class Camera;
public: public:
CameraRenderer (const Camera *camera); CameraRenderer ();
~CameraRenderer () = default; ~CameraRenderer ();
protected: protected:
QOpenGLFramebufferObject *createFramebufferObject (const QSize &size) override; QOpenGLFramebufferObject *createFramebufferObject (const QSize &size) override;
...@@ -47,7 +46,12 @@ protected: ...@@ -47,7 +46,12 @@ protected:
void synchronize (QQuickFramebufferObject *item) override; void synchronize (QQuickFramebufferObject *item) override;
private: 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; QQuickWindow *m_window;
}; };
...@@ -55,7 +59,6 @@ private: ...@@ -55,7 +59,6 @@ private:
class Camera : public QQuickFramebufferObject { class Camera : public QQuickFramebufferObject {
friend class CameraRenderer; friend class CameraRenderer;
friend void setWindowId (const Camera &camera);
Q_OBJECT; Q_OBJECT;
...@@ -68,9 +71,6 @@ public: ...@@ -68,9 +71,6 @@ public:
QQuickFramebufferObject::Renderer *createRenderer () const override; QQuickFramebufferObject::Renderer *createRenderer () const override;
Q_INVOKABLE void takeScreenshot ();
Q_INVOKABLE void saveScreenshot (const QString &path);
signals: signals:
void callChanged (CallModel *call); void callChanged (CallModel *call);
void isPreviewChanged (bool is_preview); void isPreviewChanged (bool is_preview);
...@@ -84,10 +84,6 @@ private: ...@@ -84,10 +84,6 @@ private:
bool m_is_preview = false; bool m_is_preview = false;
CallModel *m_call = nullptr; CallModel *m_call = nullptr;
ContextInfo *m_context_info;
QImage m_screenshot;
mutable CameraRenderer *m_renderer;
}; };
#endif // CAMERA_H_ #endif // CAMERA_H_
...@@ -55,25 +55,26 @@ void CoreManager::enableHandlers () { ...@@ -55,25 +55,26 @@ void CoreManager::enableHandlers () {
} }
void CoreManager::init (QObject *parent, const QString &config_path) { void CoreManager::init (QObject *parent, const QString &config_path) {
if (!m_instance) { if (m_instance)
m_instance = new CoreManager(parent, config_path); return;
m_instance->m_calls_list_model = new CallsListModel(m_instance); m_instance = new CoreManager(parent, config_path);
m_instance->m_contacts_list_model = new ContactsListModel(m_instance);
m_instance->m_sip_addresses_model = new SipAddressesModel(m_instance); m_instance->m_calls_list_model = new CallsListModel(m_instance);
m_instance->m_settings_model = new SettingsModel(m_instance); m_instance->m_contacts_list_model = new ContactsListModel(m_instance);
m_instance->m_sip_addresses_model = new SipAddressesModel(m_instance);
QTimer *timer = m_instance->m_cbs_timer = new QTimer(m_instance); m_instance->m_settings_model = new SettingsModel(m_instance);
timer->setInterval(20);
QTimer *timer = m_instance->m_cbs_timer = new QTimer(m_instance);
QObject::connect( timer->setInterval(20);
timer, &QTimer::timeout, m_instance, []() {
m_instance->m_mutex_video_render.lock(); QObject::connect(
m_instance->m_core->iterate(); timer, &QTimer::timeout, m_instance, []() {
m_instance->m_mutex_video_render.unlock(); m_instance->lockVideoRender();
} m_instance->m_core->iterate();
); m_instance->unlockVideoRender();
} }
);
} }
VcardModel *CoreManager::createDetachedVcardModel () { VcardModel *CoreManager::createDetachedVcardModel () {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment