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
qwindowsformatinfo.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
6#include <QtMultimedia/private/qcomtaskresource_p.h>
7#include <QtMultimedia/private/qwindowsmultimediautils_p.h>
8#include <QtGui/qimagewriter.h>
9#include <QtCore/qhash.h>
10#include <QtCore/qlist.h>
11#include <QtCore/qset.h>
12#include <QtCore/private/qcomptr_p.h>
13
14#include <mfapi.h>
15#include <mftransform.h>
16
18
19using namespace Qt::StringLiterals;
20
21namespace {
22
23template<typename T>
24using CheckedCodecs = QHash<std::pair<T, QMediaFormat::ConversionMode>, bool>;
25
26bool isSupportedMFT(const GUID &category, const MFT_REGISTER_TYPE_INFO &type, QMediaFormat::ConversionMode mode)
27{
28 UINT32 count = 0;
29 QComTaskResource<IMFActivate *> activate;
30 HRESULT hr = E_FAIL;
31
32 // MFTEnumEx may crash inside third-party drivers (e.g. D3D12Core.dll,
33 // RTWorkQ.dll) when enumerating hardware codecs. Wrap the call with SEH
34 // to prevent the crash from taking down the whole application.
35#ifdef Q_CC_MSVC
36 __try {
37#endif
38 hr = MFTEnumEx(
39 category,
40 MFT_ENUM_FLAG_ALL,
41 (mode == QMediaFormat::Encode) ? nullptr : &type, // Input type
42 (mode == QMediaFormat::Encode) ? &type : nullptr, // Output type
43 activate.address(),
44 &count
45 );
46#ifdef Q_CC_MSVC
47 } __except (EXCEPTION_EXECUTE_HANDLER) {
48 qWarning("MFTEnumEx crashed while enumerating codecs (SEH exception caught)");
49 return false;
50 }
51#endif
52
53 return SUCCEEDED(hr) && count > 0;
54}
55
56bool isSupportedCodec(QMediaFormat::AudioCodec codec, QMediaFormat::ConversionMode mode)
57{
58 return isSupportedMFT((mode == QMediaFormat::Encode) ? MFT_CATEGORY_AUDIO_ENCODER : MFT_CATEGORY_AUDIO_DECODER,
59 { MFMediaType_Audio, QWMF::audioFormatForCodec(codec) },
60 mode);
61}
62
63bool isSupportedCodec(QMediaFormat::VideoCodec codec, QMediaFormat::ConversionMode mode)
64{
65 return isSupportedMFT((mode == QMediaFormat::Encode) ? MFT_CATEGORY_VIDEO_ENCODER : MFT_CATEGORY_VIDEO_DECODER,
66 { MFMediaType_Video, QWMF::videoFormatForCodec(codec) },
67 mode);
68}
69
70template <typename T>
71bool isSupportedCodec(T codec, QMediaFormat::ConversionMode m, CheckedCodecs<T> &checkedCodecs)
72{
73 if (auto it = checkedCodecs.constFind(std::pair{codec, m}); it != checkedCodecs.constEnd())
74 return it.value();
75
76 const bool supported = isSupportedCodec(codec, m);
77
78 checkedCodecs.insert(std::pair{codec, m}, supported);
79 return supported;
80}
81
82}
83
85{
86 QList<QImageCapture::FileFormat> list;
87 const auto formats = QImageWriter::supportedImageFormats();
88
89 for (const auto &f : formats) {
90 auto format = QString::fromUtf8(f);
91 if (format.compare(u"jpg", Qt::CaseInsensitive) == 0)
92 list.append(QImageCapture::FileFormat::JPEG);
93 else if (format.compare(u"png", Qt::CaseInsensitive) == 0)
94 list.append(QImageCapture::FileFormat::PNG);
95 else if (format.compare(u"webp", Qt::CaseInsensitive) == 0)
96 list.append(QImageCapture::FileFormat::WebP);
97 else if (format.compare(u"tiff", Qt::CaseInsensitive) == 0)
98 list.append(QImageCapture::FileFormat::Tiff);
99 }
100
101 return list;
102}
103
104QWindowsFormatInfo::QWindowsFormatInfo()
105{
106 const QList<CodecMap> containerTable = {
107 { QMediaFormat::MPEG4,
108 { QMediaFormat::AudioCodec::AAC, QMediaFormat::AudioCodec::MP3, QMediaFormat::AudioCodec::ALAC, QMediaFormat::AudioCodec::AC3, QMediaFormat::AudioCodec::EAC3 },
109 { QMediaFormat::VideoCodec::H264, QMediaFormat::VideoCodec::H265, QMediaFormat::VideoCodec::MotionJPEG } },
110 { QMediaFormat::Matroska,
111 { QMediaFormat::AudioCodec::AAC, QMediaFormat::AudioCodec::MP3, QMediaFormat::AudioCodec::ALAC, QMediaFormat::AudioCodec::AC3, QMediaFormat::AudioCodec::EAC3, QMediaFormat::AudioCodec::FLAC, QMediaFormat::AudioCodec::Vorbis, QMediaFormat::AudioCodec::Opus },
112 { QMediaFormat::VideoCodec::H264, QMediaFormat::VideoCodec::H265, QMediaFormat::VideoCodec::VP8, QMediaFormat::VideoCodec::VP9, QMediaFormat::VideoCodec::MotionJPEG } },
113 { QMediaFormat::WebM,
114 { QMediaFormat::AudioCodec::Vorbis, QMediaFormat::AudioCodec::Opus },
115 { QMediaFormat::VideoCodec::VP8, QMediaFormat::VideoCodec::VP9 } },
116 { QMediaFormat::QuickTime,
117 { QMediaFormat::AudioCodec::AAC, QMediaFormat::AudioCodec::MP3, QMediaFormat::AudioCodec::ALAC, QMediaFormat::AudioCodec::AC3, QMediaFormat::AudioCodec::EAC3 },
118 { QMediaFormat::VideoCodec::H264, QMediaFormat::VideoCodec::H265, QMediaFormat::VideoCodec::MotionJPEG } },
119 { QMediaFormat::AAC,
120 { QMediaFormat::AudioCodec::AAC },
121 {} },
122 { QMediaFormat::MP3,
123 { QMediaFormat::AudioCodec::MP3 },
124 {} },
125 { QMediaFormat::FLAC,
126 { QMediaFormat::AudioCodec::FLAC },
127 {} },
128 { QMediaFormat::Mpeg4Audio,
129 { QMediaFormat::AudioCodec::AAC, QMediaFormat::AudioCodec::MP3, QMediaFormat::AudioCodec::ALAC, QMediaFormat::AudioCodec::AC3, QMediaFormat::AudioCodec::EAC3 },
130 {} },
131 { QMediaFormat::WMA,
132 { QMediaFormat::AudioCodec::WMA },
133 {} },
134 { QMediaFormat::WMV,
135 { QMediaFormat::AudioCodec::WMA },
136 { QMediaFormat::VideoCodec::WMV } }
137 };
138
139 const QSet<QMediaFormat::FileFormat> decoderFormats = {
140 QMediaFormat::MPEG4,
141 QMediaFormat::Matroska,
142 QMediaFormat::WebM,
143 QMediaFormat::QuickTime,
144 QMediaFormat::AAC,
145 QMediaFormat::MP3,
146 QMediaFormat::FLAC,
147 QMediaFormat::Mpeg4Audio,
148 QMediaFormat::WMA,
149 QMediaFormat::WMV,
150 };
151
152 const QSet<QMediaFormat::FileFormat> encoderFormats = {
153 QMediaFormat::MPEG4,
154 QMediaFormat::AAC,
155 QMediaFormat::MP3,
156 QMediaFormat::FLAC,
157 QMediaFormat::Mpeg4Audio,
158 QMediaFormat::WMA,
159 QMediaFormat::WMV,
160 };
161
162 CheckedCodecs<QMediaFormat::AudioCodec> checkedAudioCodecs;
163 CheckedCodecs<QMediaFormat::VideoCodec> checkedVideoCodecs;
164
165 auto ensureCodecs = [&] (CodecMap &codecs, QMediaFormat::ConversionMode mode) {
166 codecs.audio.removeIf([&] (auto codec) { return !isSupportedCodec(codec, mode, checkedAudioCodecs); });
167 codecs.video.removeIf([&] (auto codec) { return !isSupportedCodec(codec, mode, checkedVideoCodecs); });
168 return !codecs.video.empty() || !codecs.audio.empty();
169 };
170
171 for (const auto &codecMap : containerTable) {
172 if (decoderFormats.contains(codecMap.format)) {
173 auto m = codecMap;
174 if (ensureCodecs(m, QMediaFormat::Decode))
175 decoders.append(m);
176 }
177
178 if (encoderFormats.contains(codecMap.format)) {
179 auto m = codecMap;
180 if (ensureCodecs(m, QMediaFormat::Encode))
181 encoders.append(m);
182 }
183 }
184
185 imageFormats = getImageFormatList();
186
187 fixupCodecMaps();
188}
189
190QWindowsFormatInfo::~QWindowsFormatInfo()
191{
192}
193
194QT_END_NAMESPACE
Combined button and popup list for selecting options.
static QList< QImageCapture::FileFormat > getImageFormatList()