Revision control

+ // Copyright (C) 2026 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 "qvivantevideobuffer_p.h"
+
+ #include <QtMultimedia/private/qrhivaluemapper_p.h>
+ #include <QtMultimedia/private/qvideotexturehelper_p.h>
+ #include <QtMultimedia/private/qvivantetextureimporter_p.h>
+ #include <QtGui/rhi/qrhi.h>
+ #include <QtCore/qloggingcategory.h>
+
+ static_assert(QT_CONFIG(gpu_vivante));
+
+ QT_BEGIN_NAMESPACE
+
+ Q_STATIC_LOGGING_CATEGORY(qLcVivanteVideoBuffer, "qt.multimedia.vivantevideobuffer");
+
+ namespace QtMultimediaPrivate {
+
+ static QRhiValueMapper<VivanteContext> g_vivanteContexts;
+ VivanteContext &vivanteContextForRhi(QRhi &rhi)
+ {
+ return g_vivanteContexts.getOrCreate(rhi, [&] {
+ return VivanteContext(&rhi);
+ });
+ }
+
+ QVivanteVideoBuffer::QVivanteVideoBuffer(QVideoFrameFormat::PixelFormat format, QSize size,
+ quint32 physicalAddress, void *logicalAddr,
+ GLenum vivFormatToken, std::shared_ptr<void> keepAlive,
+ VivanteCpuView cpuView)
+ : m_format(format),
+ m_size(size),
+ m_physicalAddress(physicalAddress),
+ m_logicalAddr(logicalAddr),
+ m_vivFormatToken(vivFormatToken),
+ m_cpuView(cpuView),
+ m_keepAlive(std::move(keepAlive))
+ {
+ }
+
+ QVivanteVideoBuffer::~QVivanteVideoBuffer()
+ {
+ Q_ASSERT(m_mapMode == QVideoFrame::NotMapped);
+ }
+
+ QVideoFrameTexturesUPtr QVivanteVideoBuffer::mapTextures(QRhi &rhi)
+ {
+ Q_ASSERT(rhi.thread()->isCurrentThread());
+
+ if (rhi.backend() != QRhi::OpenGLES2)
+ return {};
+
+ VivanteContext &context = vivanteContextForRhi(rhi);
+
+ if (!context.isValid()) {
+ qCDebug(qLcVivanteVideoBuffer) << "VivanteContext is not valid, falling back to CPU path";
+ return {};
+ }
+
+ auto handles = importVivanteTexture(rhi, context, m_physicalAddress, m_logicalAddr, m_size,
+ m_vivFormatToken, m_keepAlive);
+ if (!handles) {
+ qCWarning(qLcVivanteVideoBuffer) << "Vivante direct-texture import failed";
+ return {};
+ }
+
+ return QVideoTextureHelper::createTexturesFromHandles(std::move(*handles), rhi, m_format,
+ m_size);
+ }
+
+ QAbstractVideoBuffer::MapData QVivanteVideoBuffer::map(QVideoFrame::MapMode mode)
+ {
+ MapData mapData;
+
+ // The producer (VPU/driver) owns write access to the phys-mem buffer.
+ if (mode != QVideoFrame::ReadOnly || m_mapMode != QVideoFrame::NotMapped)
+ return mapData;
+
+ if (!m_cpuView.data) {
+ qCDebug(qLcVivanteVideoBuffer) << "No CPU-mapped view available for this buffer";
+ return mapData;
+ }
+
+ // The caller must have already CPU-mapped the phys-mem buffer (e.g. via gst_buffer_map())
+ // and passed the pointer in as VivanteCpuView; just hand that view back out.
+ mapData.planeCount = 1;
+ mapData.data[0] = m_cpuView.data;
+ mapData.bytesPerLine[0] = m_cpuView.bytesPerLine;
+ mapData.dataSize[0] = m_cpuView.dataSize;
+
+ m_mapMode = mode;
+ return mapData;
+ }
+
+ void QVivanteVideoBuffer::unmap()
+ {
+ // Nothing to release: the CPU-mapped view is owned by the caller (see
+ // VivanteCpuView / m_keepAlive), not by this object.
+ m_mapMode = QVideoFrame::NotMapped;
+ }
+
+ } // namespace QtMultimediaPrivate
+
+ QT_END_NAMESPACE