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()->isCurrentThread() ? compositorContext
43 : createContext(shareContext: compositorContext);
44
45 if (!context)
46 return false;
47
48 surface = new QOffscreenSurface(nullptr, context);
49 surface->setFormat(context->format());
50 surface->create();
51 }
52
53 return context->makeCurrent(surface);
54}
55
56QOpenGLVideoBuffer::QOpenGLVideoBuffer(std::unique_ptr<QOpenGLFramebufferObject> fbo)
57 : QHwVideoBuffer(QVideoFrame::RhiTextureHandle), m_fbo(std::move(fbo))
58{
59 Q_ASSERT(m_fbo);
60}
61
62QOpenGLVideoBuffer::~QOpenGLVideoBuffer() = default;
63
64QAbstractVideoBuffer::MapData QOpenGLVideoBuffer::map(QVideoFrame::MapMode mode)
65{
66 return ensureImageBuffer().map(mode);
67}
68
69void QOpenGLVideoBuffer::unmap()
70{
71 if (m_imageBuffer)
72 m_imageBuffer->unmap();
73}
74
75quint64 QOpenGLVideoBuffer::textureHandle(QRhi &, int plane)
76{
77 Q_UNUSED(plane);
78 return m_fbo->texture();
79}
80
81QImageVideoBuffer &QOpenGLVideoBuffer::ensureImageBuffer()
82{
83 // Create image buffer if not yet created.
84 // This is protected by mapMutex in QVideoFrame::map.
85 if (!m_imageBuffer) {
86 if (!setCurrentOpenGLContext())
87 qWarning() << "Failed to set current OpenGL context";
88
89 m_imageBuffer = std::make_unique<QImageVideoBuffer>(args: m_fbo->toImage(flipped: false));
90 }
91
92 return *m_imageBuffer;
93}
94
95QT_END_NAMESPACE
96

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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