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
qffmpeghwaccel_vaapi.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 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
5
7
8#include <QtMultimedia/private/qmultimedia_drm_support_p.h>
9#include <QtMultimedia/private/qvideotexturehelper_p.h>
10
11#include <QtGui/qguiapplication.h>
12#include <QtGui/qopenglfunctions.h>
13#include <QtGui/qpa/qplatformnativeinterface.h>
14
15#include <QtCore/qloggingcategory.h>
16
17extern "C" {
18#include <libavutil/hwcontext_vaapi.h>
19}
20
21#include <va/va.h>
22#include <va/va_drmcommon.h>
23
24#include <unistd.h>
25
26static_assert(QT_CONFIG(vaapi));
27
29
30Q_STATIC_LOGGING_CATEGORY(qLHWAccelVAAPI, "qt.multimedia.ffmpeg.hwaccelvaapi");
31
32namespace QFFmpeg {
33
35
36constexpr bool VAExportUseLayers = false;
37
40{
41 qCDebug(qLHWAccelVAAPI) << ">>>> Creating VAAPI HW accelerator";
42
43 if (!eglContext.isValid()) {
44 this->rhi = nullptr;
45 return;
46 }
47
48 // everything ok, indicate that we can do zero copy
49 this->rhi = rhi;
50}
51
53
56 QVideoFrameTexturesHandlesUPtr /*oldHandles*/)
57{
58 // qCDebug(qLHWAccelVAAPI) << "VAAPIAccel::createTextureHandles";
59 if (frame->format != AV_PIX_FMT_VAAPI || !eglContext.eglDisplay()) {
60 qCDebug(qLHWAccelVAAPI) << "format/egl error" << frame->format << eglContext.eglDisplay();
61 return nullptr;
62 }
63
64 if (!frame->hw_frames_ctx)
65 return nullptr;
66
67 auto *ctx = avFrameDeviceContext(frame);
68 if (!ctx)
69 return nullptr;
70
71 auto *vaCtx = (AVVAAPIDeviceContext *)ctx->hwctx;
72 auto vaDisplay = vaCtx->display;
73 if (!vaDisplay) {
74 qCDebug(qLHWAccelVAAPI) << " no VADisplay, disabling";
75 return nullptr;
76 }
77
78 VASurfaceID vaSurface = (uintptr_t)frame->data[3];
79
80 VADRMPRIMESurfaceDescriptor prime = {};
81 if (vaExportSurfaceHandle(vaDisplay, vaSurface, VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
82 VA_EXPORT_SURFACE_READ_ONLY
83 | (VAExportUseLayers ? VA_EXPORT_SURFACE_SEPARATE_LAYERS
84 : VA_EXPORT_SURFACE_COMPOSED_LAYERS),
85 &prime)
86 != VA_STATUS_SUCCESS) {
87 qWarning() << "vaExportSurfaceHandle failed";
88 return nullptr;
89 }
90
91 // Make sure all fd's in 'prime' are closed when we return from this function
92 QScopeGuard closeObjectsGuard([&prime]() {
93 for (uint32_t i = 0; i < prime.num_objects; ++i)
94 close(prime.objects[i].fd);
95 });
96
97 // ### Check that prime.fourcc is what we expect
98 vaSyncSurface(vaDisplay, vaSurface);
99
100// qCDebug(qLHWAccelVAAPI) << "VAAPIAccel: vaSufraceDesc: width/height" << prime.width << prime.height << "num objects"
101// << prime.num_objects << "num layers" << prime.num_layers;
102
103 AVPixelFormat fmt = HWAccel::format(frame);
104 bool needsConversion;
105 auto qtFormat = QFFmpegVideoBuffer::toQtPixelFormat(fmt, &needsConversion);
106 QSpan<const DRMFormat> drm_formats = QtMultimediaPrivate::dmaBufFourccFromPixelFormat(qtFormat);
107 if (drm_formats.empty() || needsConversion) {
108 qWarning() << "can't use DMA transfer for pixel format" << fmt << qtFormat;
109 return nullptr;
110 }
111
112 auto *desc = QVideoTextureHelper::textureDescription(qtFormat);
113 int nPlanes = int(drm_formats.size());
114 Q_ASSERT(nPlanes == desc->nplanes);
115 nPlanes = desc->nplanes;
116// qCDebug(qLHWAccelVAAPI) << "VAAPIAccel: nPlanes" << nPlanes;
117
118 DmaBufPlane planes[4];
119 for (int i = 0; i < nPlanes; ++i) {
120 const int layer = VAExportUseLayers ? i : 0;
121 const int plane = VAExportUseLayers ? 0 : i;
122
123 if constexpr (VAExportUseLayers) {
124 if (prime.layers[i].drm_format != quint32(drm_formats[i])) {
125 qWarning() << "expected DRM format check failed expected" << Qt::hex
126 << quint32(drm_formats[i]) << "got" << prime.layers[i].drm_format;
127 }
128 }
129
130 planes[i].fd = prime.objects[prime.layers[layer].object_index[plane]].fd;
131 planes[i].offset = prime.layers[layer].offset[plane];
132 planes[i].pitch = prime.layers[layer].pitch[plane];
133 planes[i].drmFormat = drm_formats[i];
134 planes[i].modifier =
135 prime.objects[prime.layers[layer].object_index[plane]].drm_format_modifier;
136 }
137
138 auto textureHandles =
139 importDmaBufTextures(*rhi, eglContext, QSpan(planes, nPlanes), qtFormat,
140 QSize(frame->width, frame->height), shared_from_this());
141 if (!textureHandles) {
142 if (textureHandles.error() == FailureSeverity::unrecoverable) {
143 qWarning() << "VAAPI driver:" << vaQueryVendorString(vaDisplay);
144 this->rhi = nullptr; // Disabling texture conversion here to fix QTBUG-112312
145 }
146 return nullptr;
147 }
148
149 return std::move(*textureHandles);
150}
151
152} // namespace QFFmpeg
153
154QT_END_NAMESPACE
QVideoFrameTexturesHandlesUPtr createTextureHandles(AVFrame *frame, QVideoFrameTexturesHandlesUPtr oldHandles) override
QT_MANGLE_NAMESPACE(QMacScreenCaptureStreamDelegate) QMacScreenCaptureStreamDelegate
constexpr bool VAExportUseLayers
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)