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

source code of qtmultimedia/src/plugins/multimedia/ffmpeg/qopenglvideobuffer.cpp