Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
avfvideobuffer.mm
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
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 "avfvideobuffer_p.h"
5#include <rhi/qrhi.h>
6#include <CoreVideo/CVMetalTexture.h>
7#include <CoreVideo/CVMetalTextureCache.h>
8#include <QtGui/qopenglcontext.h>
9
10#include <private/qvideotexturehelper_p.h>
11#include "qavfhelpers_p.h"
12
13#import <AVFoundation/AVFoundation.h>
14#import <Metal/Metal.h>
15
17
19 : QAbstractVideoBuffer(sink->rhi() ? QVideoFrame::RhiTextureHandle : QVideoFrame::NoHandle, sink->rhi()),
20 sink(sink),
21 m_buffer(buffer)
22{
23// m_type = QVideoFrame::NoHandle;
24// qDebug() << "RHI" << m_rhi;
25 CVPixelBufferRetain(m_buffer);
26 const bool rhiIsOpenGL = sink && sink->rhi() && sink->rhi()->backend() == QRhi::OpenGLES2;
27 m_format = QAVFHelpers::videoFormatForImageBuffer(m_buffer, rhiIsOpenGL);
28}
29
31{
33 for (int i = 0; i < 3; ++i)
34 if (cvMetalTexture[i])
35 CFRelease(cvMetalTexture[i]);
36#if defined(Q_OS_MACOS)
37 if (cvOpenGLTexture)
38 CVOpenGLTextureRelease(cvOpenGLTexture);
39#elif defined(Q_OS_IOS)
40 if (cvOpenGLESTexture)
41 CFRelease(cvOpenGLESTexture);
42#endif
43 CVPixelBufferRelease(m_buffer);
44}
45
47{
49
50 if (m_mode == QVideoFrame::NotMapped) {
51 CVPixelBufferLockBaseAddress(m_buffer, mode == QVideoFrame::ReadOnly
52 ? kCVPixelBufferLock_ReadOnly
53 : 0);
54 m_mode = mode;
55 }
56
57 mapData.nPlanes = CVPixelBufferGetPlaneCount(m_buffer);
58 Q_ASSERT(mapData.nPlanes <= 3);
59
60 if (!mapData.nPlanes) {
61 // single plane
62 mapData.bytesPerLine[0] = CVPixelBufferGetBytesPerRow(m_buffer);
63 mapData.data[0] = static_cast<uchar*>(CVPixelBufferGetBaseAddress(m_buffer));
64 mapData.size[0] = CVPixelBufferGetDataSize(m_buffer);
65 mapData.nPlanes = mapData.data[0] ? 1 : 0;
66 return mapData;
67 }
68
69 // For a bi-planar or tri-planar format we have to set the parameters correctly:
70 for (int i = 0; i < mapData.nPlanes; ++i) {
71 mapData.bytesPerLine[i] = CVPixelBufferGetBytesPerRowOfPlane(m_buffer, i);
72 mapData.size[i] = mapData.bytesPerLine[i]*CVPixelBufferGetHeightOfPlane(m_buffer, i);
73 mapData.data[i] = static_cast<uchar*>(CVPixelBufferGetBaseAddressOfPlane(m_buffer, i));
74 }
75
76 return mapData;
77}
78
80{
81 if (m_mode != QVideoFrame::NotMapped) {
82 CVPixelBufferUnlockBaseAddress(m_buffer, m_mode == QVideoFrame::ReadOnly
83 ? kCVPixelBufferLock_ReadOnly
84 : 0);
86 }
87}
88
90{
91 switch (f) {
92 default:
94 return MTLPixelFormatInvalid;
96 return MTLPixelFormatRGBA8Unorm;
98 return MTLPixelFormatBGRA8Unorm;
99 case QRhiTexture::R8:
100 return MTLPixelFormatR8Unorm;
101 case QRhiTexture::RG8:
102 return MTLPixelFormatRG8Unorm;
103 case QRhiTexture::R16:
104 return MTLPixelFormatR16Unorm;
106 return MTLPixelFormatRG16Unorm;
107
109 return MTLPixelFormatRGBA16Float;
111 return MTLPixelFormatRGBA32Float;
113 return MTLPixelFormatR16Float;
115 return MTLPixelFormatR32Float;
116 }
117}
118
119
121{
122 auto *textureDescription = QVideoTextureHelper::textureDescription(m_format.pixelFormat());
123 int bufferPlanes = CVPixelBufferGetPlaneCount(m_buffer);
124// qDebug() << "texture handle" << plane << m_rhi << (m_rhi->backend() == QRhi::Metal) << bufferPlanes;
125 if (plane > 0 && plane >= bufferPlanes)
126 return 0;
127 if (!m_rhi)
128 return 0;
129 if (m_rhi->backend() == QRhi::Metal) {
130 if (!cvMetalTexture[plane]) {
131 size_t width = CVPixelBufferGetWidth(m_buffer);
132 size_t height = CVPixelBufferGetHeight(m_buffer);
133 width = textureDescription->widthForPlane(width, plane);
134 height = textureDescription->heightForPlane(height, plane);
135
136 // Create a CoreVideo pixel buffer backed Metal texture image from the texture cache.
137 QMutexLocker locker(sink->textureCacheMutex());
138 if (!metalCache && sink->cvMetalTextureCache)
139 metalCache = CVMetalTextureCacheRef(CFRetain(sink->cvMetalTextureCache));
140 if (!metalCache) {
141 qWarning("cannot create texture, Metal texture cache was released?");
142 return {};
143 }
144 auto ret = CVMetalTextureCacheCreateTextureFromImage(
145 kCFAllocatorDefault,
146 metalCache,
147 m_buffer, nil,
148 rhiTextureFormatToMetalFormat(textureDescription->textureFormat[plane]),
149 width, height,
150 plane,
151 &cvMetalTexture[plane]);
152
153 if (ret != kCVReturnSuccess)
154 qWarning() << "texture creation failed" << ret;
155// auto t = CVMetalTextureGetTexture(cvMetalTexture[plane]);
156// qDebug() << " metal texture is" << quint64(cvMetalTexture[plane]) << width << height;
157// qDebug() << " " << t.iosurfacePlane << t.pixelFormat << t.width << t.height;
158 }
159
160 // Get a Metal texture using the CoreVideo Metal texture reference.
161// qDebug() << " -> " << quint64(CVMetalTextureGetTexture(cvMetalTexture[plane]));
162 return cvMetalTexture[plane] ? quint64(CVMetalTextureGetTexture(cvMetalTexture[plane])) : 0;
163 } else if (m_rhi->backend() == QRhi::OpenGLES2) {
164#if QT_CONFIG(opengl)
165#ifdef Q_OS_MACOS
166 CVOpenGLTextureCacheFlush(sink->cvOpenGLTextureCache, 0);
167 // Create a CVPixelBuffer-backed OpenGL texture image from the texture cache.
168 const CVReturn cvret = CVOpenGLTextureCacheCreateTextureFromImage(
169 kCFAllocatorDefault,
170 sink->cvOpenGLTextureCache,
171 m_buffer,
172 nil,
173 &cvOpenGLTexture);
174 if (cvret != kCVReturnSuccess)
175 qWarning() << "OpenGL texture creation failed" << cvret;
176
177 Q_ASSERT(CVOpenGLTextureGetTarget(cvOpenGLTexture) == GL_TEXTURE_RECTANGLE);
178 // Get an OpenGL texture name from the CVPixelBuffer-backed OpenGL texture image.
179 return CVOpenGLTextureGetName(cvOpenGLTexture);
180#endif
181#ifdef Q_OS_IOS
182 CVOpenGLESTextureCacheFlush(sink->cvOpenGLESTextureCache, 0);
183 // Create a CVPixelBuffer-backed OpenGL texture image from the texture cache.
184 const CVReturn cvret = CVOpenGLESTextureCacheCreateTextureFromImage(
185 kCFAllocatorDefault,
186 sink->cvOpenGLESTextureCache,
187 m_buffer,
188 nil,
189 GL_TEXTURE_2D,
190 GL_RGBA,
191 CVPixelBufferGetWidth(m_buffer),
192 CVPixelBufferGetHeight(m_buffer),
193 GL_RGBA,
195 0,
196 &cvOpenGLESTexture);
197 if (cvret != kCVReturnSuccess)
198 qWarning() << "OpenGL ES texture creation failed" << cvret;
199
200 // Get an OpenGL texture name from the CVPixelBuffer-backed OpenGL texture image.
201 return CVOpenGLESTextureGetName(cvOpenGLESTexture);
202#endif
203#endif
204 }
205 return 0;
206}
static MTLPixelFormat rhiTextureFormatToMetalFormat(QRhiTexture::Format f)
void unmap()
Releases the memory mapped by the map() function.
MapData map(QVideoFrame::MapMode mode)
Independently maps the planes of a video buffer to memory.
AVFVideoBuffer(AVFVideoSinkInterface *sink, CVImageBufferRef buffer)
virtual quint64 textureHandle(QRhi *, int plane) const
Returns a texture handle to the data buffer.
The QAbstractVideoBuffer class is an abstraction for video data. \inmodule QtMultimedia.
\inmodule QtCore
Definition qmutex.h:313
Format
Specifies the texture format.
Definition qrhi.h:914
@ RGBA32F
Definition qrhi.h:926
@ RGBA16F
Definition qrhi.h:925
@ UnknownFormat
Definition qrhi.h:915
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
Definition qrhi.h:1804
Implementation backend() const
Definition qrhi.cpp:8651
@ Metal
Definition qrhi.h:1811
@ OpenGLES2
Definition qrhi.h:1809
QVideoFrameFormat::PixelFormat pixelFormat() const
Returns the pixel format of frames in a video stream.
The QVideoFrame class represents a frame of video data.
Definition qvideoframe.h:27
MapMode
Enumerates how a video buffer's data is mapped to system memory.
Definition qvideoframe.h:37
QVideoFrameFormat videoFormatForImageBuffer(CVImageBufferRef buffer, bool openGL=false)
const TextureDescription * textureDescription(QVideoFrameFormat::PixelFormat format)
#define qWarning
Definition qlogging.h:166
return ret
GLenum mode
GLint GLsizei GLsizei height
GLfloat GLfloat f
GLenum GLuint buffer
GLint GLsizei width
#define GL_TEXTURE_RECTANGLE
GLsizei GLenum GLboolean sink
static QAbstractVideoBuffer::MapData mapData(const camera_frame_nv12_t &frame, unsigned char *baseAddress)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define GL_UNSIGNED_BYTE
#define GL_RGBA
unsigned char uchar
Definition qtypes.h:32
unsigned long long quint64
Definition qtypes.h:61
QRhiTexture::Format textureFormat[maxPlanes]
int widthForPlane(int width, int plane) const
int heightForPlane(int height, int plane) const