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
qffmpegtextureconverter.cpp
Go to the documentation of this file.
1// Copyright (C) 2024 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 <QtFFmpegMediaPluginImpl/private/qffmpegtextureconverter_p.h>
5
6#include <QtFFmpegMediaPluginImpl/private/qffmpeghwaccel_p.h>
7
8#include <rhi/qrhi.h>
9
10#include <q20type_traits.h>
11
12#if QT_CONFIG(vaapi)
13# include <QtFFmpegMediaPluginImpl/private/qffmpeghwaccel_vaapi_p.h>
14#endif
15
16#ifdef Q_OS_DARWIN
17# include <QtFFmpegMediaPluginImpl/private/qffmpeghwaccel_videotoolbox_p.h>
18#endif
19
20#ifdef Q_OS_WINDOWS
21# include <QtFFmpegMediaPluginImpl/private/qffmpeghwaccel_d3d11_p.h>
22#endif
23
24#ifdef Q_OS_ANDROID
25# include <QtFFmpegMediaPluginImpl/private/qffmpeghwaccel_mediacodec_p.h>
26#endif
27
29
30using namespace QFFmpeg;
31
32namespace {
33
34template <typename Converter>
35using ConverterTypeIdentity = q20::type_identity<Converter>;
36
37template <typename ConverterTypeHandler>
38void applyConverterTypeByPixelFormat(AVPixelFormat fmt, const QRhi &rhi,
39 ConverterTypeHandler &&handler)
40{
41 if (!TextureConverter::hwTextureConversionEnabled())
42 return;
43
44 switch (fmt) {
45#if QT_CONFIG(vaapi)
46 case AV_PIX_FMT_VAAPI:
47 handler(ConverterTypeIdentity<VAAPITextureConverter>{});
48 break;
49#endif
50#ifdef Q_OS_DARWIN
51 case AV_PIX_FMT_VIDEOTOOLBOX:
52 handler(ConverterTypeIdentity<VideoToolBoxTextureConverter>{});
53 break;
54#endif
55#ifdef Q_OS_WINDOWS
56 case AV_PIX_FMT_D3D11:
57 if (rhi.backend() == QRhi::Implementation::D3D11) {
58 if (rhi.driverInfo().deviceType != QRhiDriverInfo::CpuDevice)
59 handler(ConverterTypeIdentity<D3D11TextureConverter>{});
60 }
61 break;
62#endif
63#ifdef Q_OS_ANDROID
64 case AV_PIX_FMT_MEDIACODEC:
65 handler(ConverterTypeIdentity<MediaCodecTextureConverter>{});
66 break;
67#endif
68 default:
69 Q_UNUSED(handler)
70 Q_UNUSED(rhi)
71 break;
72 }
73}
74
75} // namespace
76
77TextureConverterBackend::~TextureConverterBackend() = default;
78
79TextureConverter::TextureConverter(QRhi &rhi) : m_rhi(rhi) { }
80
81bool TextureConverter::init(AVFrame &hwFrame)
82{
83 Q_ASSERT(hwFrame.hw_frames_ctx);
84 AVPixelFormat fmt = AVPixelFormat(hwFrame.format);
85 if (fmt != m_format)
86 updateBackend(fmt);
87 return !isNull();
88}
89
90QVideoFrameTexturesUPtr TextureConverter::createTextures(AVFrame &hwFrame,
91 QVideoFrameTexturesUPtr &oldTextures)
92{
93 if (isNull())
94 return nullptr;
95
96 Q_ASSERT(hwFrame.format == m_format);
97 return m_backend->createTextures(&hwFrame, oldTextures);
98}
99
100QVideoFrameTexturesHandlesUPtr
101TextureConverter::createTextureHandles(AVFrame &hwFrame, QVideoFrameTexturesHandlesUPtr oldHandles)
102{
103 if (isNull())
104 return nullptr;
105
106 Q_ASSERT(hwFrame.format == m_format);
107 return m_backend->createTextureHandles(&hwFrame, std::move(oldHandles));
108}
109
110void TextureConverter::updateBackend(AVPixelFormat fmt)
111{
112 m_backend = nullptr;
113 m_format = fmt; // should be saved even if m_backend is not created
114
115 applyConverterTypeByPixelFormat(m_format, m_rhi, [this](auto converterTypeIdentity) {
116 using ConverterType = typename decltype(converterTypeIdentity)::type;
117 m_backend = std::make_shared<ConverterType>(&m_rhi);
118 });
119}
120
121bool TextureConverter::hwTextureConversionEnabled()
122{
123 // HW texture conversions are not stable in specific cases, dependent on the hardware and OS.
124 // We need the env var for testing with no texture conversion on the user's side.
125 static const int disableHwConversion =
126 qEnvironmentVariableIntValue("QT_DISABLE_HW_TEXTURES_CONVERSION");
127
128 return !disableHwConversion;
129}
130
131void TextureConverter::applyDecoderPreset(const AVPixelFormat format, AVCodecContext &codecContext)
132{
133 if (!hwTextureConversionEnabled())
134 return;
135
136 Q_ASSERT(codecContext.codec && Codec(codecContext.codec).isDecoder());
137
138#ifdef Q_OS_WINDOWS
139 if (format == AV_PIX_FMT_D3D11)
140 D3D11TextureConverter::SetupDecoderTextures(&codecContext);
141#elif defined Q_OS_ANDROID
142 if (format == AV_PIX_FMT_MEDIACODEC)
143 MediaCodecTextureConverter::setupDecoderSurface(&codecContext);
144#else
145 Q_UNUSED(codecContext);
146 Q_UNUSED(format);
147#endif
148}
149
150bool TextureConverter::isBackendAvailable(AVFrame &hwFrame, const QRhi &rhi)
151{
152 bool result = false;
153 applyConverterTypeByPixelFormat(AVPixelFormat(hwFrame.format), rhi, [&result](auto) {
154 result = true;
155 });
156 return result;
157}
158
159QT_END_NAMESPACE