Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qdmabufvideobuffer.cpp
Go to the documentation of this file.
1
// Copyright (C) 2026 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
"qdmabufvideobuffer_p.h"
5
6
#
include
<
QtMultimedia
/
private
/
qvideotexturehelper_p
.
h
>
7
#
include
<
QtMultimedia
/
private
/
qrhivaluemapper_p
.
h
>
8
#
include
<
QtGui
/
rhi
/
qrhi
.
h
>
9
#
include
<
QtCore
/
qloggingcategory
.
h
>
10
11
#
if
QT_CONFIG
(
opengl
)
&&
QT_CONFIG
(
egl
)
12
#
include
<
QtMultimedia
/
private
/
qdmabuftextureimporter_p
.
h
>
13
#
endif
14
15
#
include
<
cerrno
>
16
#
include
<
cstring
>
17
#
include
<
fcntl
.
h
>
18
#
include
<
unistd
.
h
>
19
#
include
<
sys
/
mman
.
h
>
20
21
static_assert
(QT_CONFIG(linux_dmabuf));
22
23
QT_BEGIN_NAMESPACE
24
25
Q_STATIC_LOGGING_CATEGORY
(qLcDmaBufVideoBuffer,
"qt.multimedia.dmabufvideobuffer"
);
26
27
namespace
QtMultimediaPrivate
{
28
29
#
if
QT_CONFIG
(
opengl
)
&&
QT_CONFIG
(
egl
)
30
static
QRhiValueMapper
<
DmaBufEglContext
>
g_eglContexts
;
31
#
endif
32
33
QDmaBufVideoBuffer
::
QDmaBufVideoBuffer
(
QVideoFrameFormat
::
PixelFormat
format
,
QSize
size
,
34
QSpan
<
const
DmaBufPlane
>
planes
,
35
std
::
shared_ptr
<
void
>
keepAlive
)
36
:
QHwVideoBuffer
(
QVideoFrame
::
NoHandle
),
37
m_format
(
format
),
38
m_size
(
size
),
39
m_planeCount
(
std
::
clamp
(0,
int
(
planes
.
size
()), 4)),
40
m_keepAlive
(
std
::
move
(
keepAlive
))
41
{
42
Q_ASSERT
(!
planes
.
empty
() &&
planes
.
size
() <= 4);
43
44
for
(
int
i
= 0;
i
<
m_planeCount
; ++
i
) {
45
m_planes
[
i
] =
planes
[
i
];
46
47
// Take our own, independent reference: the producer may close its
48
// fd at any point while this buffer is still alive.
49
if
(
m_planes
[
i
].
fd
>= 0) {
50
const
int
dupped
= ::
fcntl
(
m_planes
[
i
].
fd
, F_DUPFD_CLOEXEC, 0);
51
if
(
dupped
< 0) {
52
qCWarning
(
qLcDmaBufVideoBuffer
) <<
"Failed to dup DMABUF fd for plane"
<<
i
<<
':'
53
<<
qt_error_string
(errno);
54
m_planes
[
i
].
fd
= -1;
55
}
else
{
56
m_planes
[
i
].
fd
=
dupped
;
57
}
58
}
59
}
60
}
61
62
QDmaBufVideoBuffer
::~
QDmaBufVideoBuffer
()
63
{
64
Q_ASSERT
(
m_mapMode
==
QVideoFrame
::
NotMapped
);
65
66
for
(
int
i
= 0;
i
<
m_planeCount
; ++
i
) {
67
if
(
m_planes
[
i
].
fd
>= 0)
68
::
close
(
m_planes
[
i
].
fd
);
69
}
70
}
71
72
QVideoFrameTexturesUPtr
QDmaBufVideoBuffer
::
mapTextures
(
QRhi
&
rhi
,
73
QVideoFrameTexturesUPtr
&
oldTextures
)
74
{
75
Q_UNUSED
(
oldTextures
);
76
Q_ASSERT
(
rhi
.
thread
()->
isCurrentThread
());
77
78
if
(
rhi
.
backend
() !=
QRhi
::
OpenGLES2
)
79
return
{};
80
81
#
if
QT_CONFIG
(
opengl
)
&&
QT_CONFIG
(
egl
)
82
// DmaBufEglContext is bound to the GL context associated with a QRhi;
83
// textures are (re-)imported on the RHI render thread, so this is
84
// created lazily here (rather than in the constructor, which may run on
85
// a different thread) and cached per-rhi.
86
DmaBufEglContext
&
eglContext
=
g_eglContexts
.
getOrCreate
(
rhi
, [&] {
87
return
DmaBufEglContext
(&
rhi
);
88
});
89
90
if
(!
eglContext
.
isValid
()) {
91
qCDebug
(
qLcDmaBufVideoBuffer
) <<
"DmaBufEglContext is not valid, falling back to CPU path"
;
92
return
{};
93
}
94
95
auto
handles
=
importDmaBufTextures
(
rhi
,
eglContext
,
QSpan
(
m_planes
.
data
(),
m_planeCount
),
96
m_format
,
m_size
,
m_keepAlive
);
97
if
(!
handles
) {
98
if
(
handles
.
error
() ==
FailureSeverity
::
unrecoverable
) {
99
qCWarning
(
qLcDmaBufVideoBuffer
)
100
<<
"Unrecoverable EGL import failure, disabling texture import for this buffer"
;
101
eglContext
.
invalidate
();
102
}
103
return
{};
104
}
105
106
return
QVideoTextureHelper
::
createTexturesFromHandles
(
std
::
move
(*
handles
),
rhi
,
m_format
,
107
m_size
);
108
#
else
// QT_CONFIG(opengl) && QT_CONFIG(egl)
109
qCDebug
(
qLcDmaBufVideoBuffer
)
110
<<
"DMABUF texture import is not supported in this build, falling back to CPU path"
;
111
return
{};
112
#
endif
// QT_CONFIG(opengl) && QT_CONFIG(egl)
113
}
114
115
QAbstractVideoBuffer
::
MapData
QDmaBufVideoBuffer
::
map
(
QVideoFrame
::
MapMode
mode
)
116
{
117
MapData
mapData
;
118
119
// The producer (driver/compositor) owns write access to the DMABUF.
120
if
(
mode
!=
QVideoFrame
::
ReadOnly
||
m_mapMode
!=
QVideoFrame
::
NotMapped
)
121
return
mapData
;
122
123
auto
*
desc
=
QVideoTextureHelper
::
textureDescription
(
m_format
);
124
if
(!
desc
)
125
return
mapData
;
126
127
QVarLengthArray
<
std
::
pair
<
int
,
std
::
pair
<
void
*,
size_t
>>, 4>
mappedByFd
;
128
129
for
(
int
i
= 0;
i
<
m_planeCount
; ++
i
) {
130
const
DmaBufPlane
&
plane
=
m_planes
[
i
];
131
132
void
*
base
=
nullptr
;
133
for
(
const
auto
&
entry
:
mappedByFd
) {
134
if
(
entry
.
first
==
plane
.
fd
) {
135
base
=
entry
.
second
.
first
;
136
break
;
137
}
138
}
139
140
if
(!
base
) {
141
// Determine the size of the DMABUF via lseek (dma-buf file
142
// objects implement llseek to report their size), then mmap it
143
// read-only in one go; individual planes just index into this
144
// mapping via their offset.
145
const
off_t
len
= ::
lseek
(
plane
.
fd
, 0, SEEK_END);
146
if
(
len
<= 0) {
147
qCWarning
(
qLcDmaBufVideoBuffer
) <<
"Could not determine DMABUF size for plane"
<<
i
;
148
for
(
const
auto
&
entry
:
mappedByFd
)
149
::
munmap
(
entry
.
second
.
first
,
entry
.
second
.
second
);
150
return
{};
151
}
152
153
void
*
mapped
= ::
mmap
(
nullptr
,
size_t
(
len
), PROT_READ, MAP_SHARED,
plane
.
fd
, 0);
154
if
(
mapped
==
MAP_FAILED
) {
155
qCWarning
(
qLcDmaBufVideoBuffer
)
156
<<
"mmap failed for plane"
<<
i
<<
':'
<<
qt_error_string
(errno);
157
for
(
const
auto
&
entry
:
mappedByFd
)
158
::
munmap
(
entry
.
second
.
first
,
entry
.
second
.
second
);
159
return
{};
160
}
161
162
mappedByFd
.
push_back
({
plane
.
fd
, {
mapped
,
size_t
(
len
) } });
163
base
=
mapped
;
164
}
165
166
mapData
.
data
[
i
] =
static_cast
<
uchar
*>(
base
) +
plane
.
offset
;
167
mapData
.
bytesPerLine
[
i
] =
int
(
plane
.
pitch
);
168
mapData
.
dataSize
[
i
] =
int
(
plane
.
pitch
) *
desc
->
heightForPlane
(
m_size
.
height
(),
i
);
169
}
170
171
mapData
.
planeCount
=
m_planeCount
;
172
173
m_mappedRegions
.
clear
();
174
for
(
const
auto
&
entry
:
mappedByFd
)
175
m_mappedRegions
.
push_back
(
entry
.
second
);
176
177
m_mapMode
=
mode
;
178
return
mapData
;
179
}
180
181
void
QDmaBufVideoBuffer
::
unmap
()
182
{
183
for
(
const
auto
&
region
:
m_mappedRegions
)
184
::
munmap
(
region
.
first
,
region
.
second
);
185
m_mappedRegions
.
clear
();
186
187
m_mapMode
=
QVideoFrame
::
NotMapped
;
188
}
189
190
}
// namespace QtMultimediaPrivate
191
192
QT_END_NAMESPACE
QtMultimediaPrivate::impl
Definition
qaudiosystem_p.h:257
Q_STATIC_LOGGING_CATEGORY
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)
MAP_FAILED
#define MAP_FAILED
Definition
qresource.cpp:1189
qtmultimedia
src
multimedia
video
qdmabufvideobuffer.cpp
Generated on
for Qt by
1.16.1