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

source code of qtmultimedia/src/plugins/multimedia/ffmpeg/qffmpegtextureconverter.cpp