Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
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
/
qmultimedia_dmabuf_support_p
.
h
>
7
#
include
<
QtMultimedia
/
private
/
qvideotexturehelper_p
.
h
>
8
#
include
<
QtMultimedia
/
private
/
qrhivaluemapper_p
.
h
>
9
#
include
<
QtGui
/
rhi
/
qrhi
.
h
>
10
#
include
<
QtCore
/
qloggingcategory
.
h
>
11
#
include
<
QtCore
/
private
/
qcore_unix_p
.
h
>
12
13
#
if
QT_CONFIG
(
opengl
)
&&
QT_CONFIG
(
egl
)
14
#
include
<
QtMultimedia
/
private
/
qdmabuftextureimporter_p
.
h
>
15
#
endif
16
17
#
include
<
cerrno
>
18
#
include
<
cstring
>
19
#
include
<
system_error
>
20
#
include
<
fcntl
.
h
>
21
#
include
<
unistd
.
h
>
22
#
include
<
sys
/
mman
.
h
>
23
24
static_assert
(QT_CONFIG(linux_dmabuf));
25
26
QT_BEGIN_NAMESPACE
27
28
Q_STATIC_LOGGING_CATEGORY
(qLcDmaBufVideoBuffer,
"qt.multimedia.dmabufvideobuffer"
);
29
30
namespace
QtMultimediaPrivate
{
31
32
#
if
QT_CONFIG
(
opengl
)
&&
QT_CONFIG
(
egl
)
33
static
QRhiValueMapper
<
DmaBufEglContext
>
g_eglContexts
;
34
#
endif
35
36
namespace
{
37
38
q23::expected<QUniqueFileDescriptorHandle, std::error_code> dupFd(
int
fd)
39
{
40
QUniqueFileDescriptorHandle duped{ ::fcntl(fd, F_DUPFD_CLOEXEC, 0) };
41
if
(!duped)
42
return
q23::unexpected(std::error_code(errno, std::generic_category()));
43
return
duped;
44
}
45
46
q23::expected<DmaBufPlane, std::error_code> planeWithDupedFd(DmaBufPlane plane)
47
{
48
auto
duped = dupFd(plane.fd);
49
if
(!duped)
50
return
q23::unexpected(duped.error());
51
52
plane.fd = duped->release();
53
return
plane;
54
}
55
56
}
// namespace
57
58
QDmaBufVideoBuffer
::
QDmaBufVideoBuffer
(
QVideoFrameFormat
::
PixelFormat
format
,
QSize
size
,
59
QSpan
<
const
DmaBufPlane
>
planes
,
60
std
::
shared_ptr
<
void
>
keepAlive
,
DmaBufImportMode
importMode
)
61
:
m_format
(
format
),
m_size
(
size
),
m_keepAlive
(
std
::
move
(
keepAlive
)),
m_importMode
(
importMode
)
62
{
63
Q_ASSERT
(!
planes
.
empty
() &&
planes
.
size
() <= 4);
64
65
for
(
qsizetype
i
= 0;
i
<
planes
.
size
(); ++
i
) {
66
q23
::
expected
<
DmaBufPlane
,
std
::
error_code
>
plane
=
planeWithDupedFd
(
planes
[
i
]);
67
if
(!
plane
) {
68
qCWarning
(
qLcDmaBufVideoBuffer
)
69
<<
"Failed to dup DMABUF fd for plane"
<<
i
<<
':'
<<
plane
.
error
().
message
();
70
break
;
71
}
72
73
m_planes
.
push_back
(
std
::
move
(*
plane
));
74
}
75
}
76
77
QDmaBufVideoBuffer
::~
QDmaBufVideoBuffer
()
78
{
79
Q_ASSERT
(
m_mapMode
==
QVideoFrame
::
NotMapped
);
80
81
for
(
DmaBufPlane
&
plane
:
m_planes
) {
82
if
(
plane
.
fd
>= 0)
83
qt_safe_close
(
plane
.
fd
);
84
}
85
}
86
87
QVideoFrameTexturesUPtr
QDmaBufVideoBuffer
::
mapTextures
(
QRhi
&
rhi
)
88
{
89
Q_ASSERT
(
rhi
.
thread
()->
isCurrentThread
());
90
91
if
(
rhi
.
backend
() !=
QRhi
::
OpenGLES2
)
92
return
{};
93
94
#
if
QT_CONFIG
(
opengl
)
&&
QT_CONFIG
(
egl
)
95
// DmaBufEglContext is bound to the GL context associated with a QRhi;
96
// textures are (re-)imported on the RHI render thread, so this is
97
// created lazily here (rather than in the constructor, which may run on
98
// a different thread) and cached per-rhi.
99
DmaBufEglContext
&
eglContext
=
g_eglContexts
.
getOrCreate
(
rhi
, [&] {
100
return
DmaBufEglContext
(&
rhi
);
101
});
102
103
if
(!
eglContext
.
isValid
()) {
104
qCDebug
(
qLcDmaBufVideoBuffer
) <<
"DmaBufEglContext is not valid, falling back to CPU path"
;
105
return
{};
106
}
107
108
auto
handles
=
importDmaBufTextures
(
rhi
,
eglContext
,
m_planes
,
m_format
,
m_size
,
m_keepAlive
,
109
m_importMode
);
110
if
(!
handles
) {
111
if
(
handles
.
error
() ==
FailureSeverity
::
unrecoverable
) {
112
qCWarning
(
qLcDmaBufVideoBuffer
)
113
<<
"Unrecoverable EGL import failure, disabling texture import for this buffer"
;
114
eglContext
.
invalidate
();
115
}
116
return
{};
117
}
118
119
return
QVideoTextureHelper
::
createTexturesFromHandles
(
std
::
move
(*
handles
),
rhi
,
m_format
,
120
m_size
);
121
#
else
// QT_CONFIG(opengl) && QT_CONFIG(egl)
122
qCDebug
(
qLcDmaBufVideoBuffer
)
123
<<
"DMABUF texture import is not supported in this build, falling back to CPU path"
;
124
return
{};
125
#
endif
// QT_CONFIG(opengl) && QT_CONFIG(egl)
126
}
127
128
void
QDmaBufVideoBuffer
::
unmapRegions
(
QSpan
<
const
MappedRegion
>
regions
)
129
{
130
for
(
const
MappedRegion
&
region
:
regions
) {
131
dmaBufSyncRead
(
region
.
fd
.
get
(),
DmaBufCpuAccess
::
End
);
132
::
munmap
(
region
.
data
.
data
(),
region
.
data
.
size
());
133
}
134
}
135
136
QAbstractVideoBuffer
::
MapData
QDmaBufVideoBuffer
::
map
(
QVideoFrame
::
MapMode
mode
)
137
{
138
MapData
mapData
;
139
140
// The producer (driver/compositor) owns write access to the DMABUF.
141
if
(
mode
!=
QVideoFrame
::
ReadOnly
||
m_mapMode
!=
QVideoFrame
::
NotMapped
)
142
return
mapData
;
143
144
auto
*
desc
=
QVideoTextureHelper
::
textureDescription
(
m_format
);
145
if
(!
desc
)
146
return
mapData
;
147
148
for
(
qsizetype
i
= 0;
i
<
m_planes
.
size
(); ++
i
) {
149
const
DmaBufPlane
&
plane
=
m_planes
[
i
];
150
151
auto
fd
=
dupFd
(
plane
.
fd
);
152
if
(!
fd
) {
153
qCWarning
(
qLcDmaBufVideoBuffer
)
154
<<
"Failed to dup DMABUF fd for plane"
<<
i
<<
':'
<<
fd
.
error
().
message
();
155
unmapRegions
(
m_mappedRegions
);
156
m_mappedRegions
.
clear
();
157
return
{};
158
}
159
160
const
off_t
len
= ::
lseek
(
fd
->
get
(), 0, SEEK_END);
161
void
*
mapped
=
len
> 0 ? ::
mmap
(
nullptr
,
size_t
(
len
), PROT_READ, MAP_SHARED,
fd
->
get
(), 0)
162
:
MAP_FAILED
;
163
if
(
mapped
==
MAP_FAILED
) {
164
qCWarning
(
qLcDmaBufVideoBuffer
)
165
<<
"Could not map DMABUF for plane"
<<
i
<<
':'
<<
qt_error_string
(errno);
166
unmapRegions
(
m_mappedRegions
);
167
m_mappedRegions
.
clear
();
168
return
{};
169
}
170
171
dmaBufSyncRead
(
fd
->
get
(),
DmaBufCpuAccess
::
Begin
);
172
const
QSpan
<
std
::
byte
>
data
{
173
static_cast
<
std
::
byte
*>(
mapped
),
174
qsizetype
(
len
),
175
};
176
m_mappedRegions
.
push_back
({
177
std
::
move
(*
fd
),
178
data
,
179
});
180
181
mapData
.
data
[
i
] =
reinterpret_cast
<
uchar
*>(
data
.
data
()) +
plane
.
offset
;
182
mapData
.
bytesPerLine
[
i
] =
int
(
plane
.
pitch
);
183
mapData
.
dataSize
[
i
] =
int
(
plane
.
pitch
) *
desc
->
heightForPlane
(
m_size
.
height
(),
i
);
184
}
185
186
mapData
.
planeCount
=
m_planes
.
size
();
187
188
m_mapMode
=
mode
;
189
return
mapData
;
190
}
191
192
void
QDmaBufVideoBuffer
::
unmap
()
193
{
194
unmapRegions
(
m_mappedRegions
);
195
m_mappedRegions
.
clear
();
196
197
m_mapMode
=
QVideoFrame
::
NotMapped
;
198
}
199
200
}
// namespace QtMultimediaPrivate
201
202
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.18.0