blob: c3e739ffd434202857e12235a79072e4fa5e9dac (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qopenglvideobuffer_p.h"
#include <qoffscreensurface.h>
#include <qthread.h>
#include <private/qimagevideobuffer_p.h>
#include <QtOpenGL/private/qopenglcompositor_p.h>
#include <QtOpenGL/private/qopenglframebufferobject_p.h>
QT_BEGIN_NAMESPACE
static QOpenGLContext *createContext(QOpenGLContext *shareContext)
{
// Create an OpenGL context for the current thread. The lifetime of the context is tied to the
// lifetime of the current thread.
auto context = std::make_unique<QOpenGLContext>();
context->setShareContext(shareContext);
if (!context->create()) {
qWarning() << "Couldn't create an OpenGL context for QOpenGLVideoBuffer";
return nullptr;
}
QObject::connect(QThread::currentThread(), &QThread::finished,
context.get(), &QOpenGLContext::deleteLater);
return context.release();
}
static bool setCurrentOpenGLContext()
{
auto compositorContext = QOpenGLCompositor::instance()->context();
// A thread-local variable is used to avoid creating a new context if we're called on the same
// thread. The context lifetime is tied to the current thread lifetime (see createContext()).
static thread_local QOpenGLContext *context = nullptr;
static thread_local QOffscreenSurface *surface = nullptr;
if (!context) {
context = (compositorContext->thread() == QThread::currentThread())
? compositorContext
: createContext(compositorContext);
if (!context)
return false;
surface = new QOffscreenSurface(nullptr, context);
surface->setFormat(context->format());
surface->create();
}
return context->makeCurrent(surface);
}
QOpenGLVideoBuffer::QOpenGLVideoBuffer(std::unique_ptr<QOpenGLFramebufferObject> fbo)
: QAbstractVideoBuffer(QVideoFrame::RhiTextureHandle), m_fbo(std::move(fbo))
{
Q_ASSERT(m_fbo);
}
QOpenGLVideoBuffer::~QOpenGLVideoBuffer() { }
QVideoFrame::MapMode QOpenGLVideoBuffer::mapMode() const
{
return m_imageBuffer ? m_imageBuffer->mapMode() : QVideoFrame::NotMapped;
}
QAbstractVideoBuffer::MapData QOpenGLVideoBuffer::map(QVideoFrame::MapMode mode)
{
return ensureImageBuffer().map(mode);
}
void QOpenGLVideoBuffer::unmap()
{
if (m_imageBuffer)
m_imageBuffer->unmap();
}
quint64 QOpenGLVideoBuffer::textureHandle(QRhi *, int plane) const
{
Q_UNUSED(plane);
return m_fbo->texture();
}
QImageVideoBuffer &QOpenGLVideoBuffer::ensureImageBuffer()
{
// Create image buffer if not yet created.
// This is protected by mapMutex in QVideoFrame::map.
if (!m_imageBuffer) {
if (!setCurrentOpenGLContext())
qWarning() << "Failed to set current OpenGL context";
m_imageBuffer = std::make_unique<QImageVideoBuffer>(m_fbo->toImage(false));
}
return *m_imageBuffer;
}
QT_END_NAMESPACE
|