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
qwindowsmultimediautils.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
4
6
7#include <QtMultimedia/private/qcameradevice_p.h>
8#include <QtCore/qt_windows.h>
9#include <QtCore/qvarlengtharray.h>
10#include <QtCore/private/qflatmap_p.h>
11
12#include <mfapi.h>
13#include <mfidl.h>
14
15#include <cstring>
16
17static_assert(WINVER >= _WIN32_WINNT_WIN10, "Win10 required for newer audio formats.");
18
19QT_BEGIN_NAMESPACE
20
21namespace QWMF {
22
23namespace {
24
25struct GuidLess
26{
27 bool operator()(const GUID &lhs, const GUID &rhs) const
28 {
29 return std::memcmp(&lhs, &rhs, sizeof(GUID)) < 0;
30 }
31};
32
33} // namespace
34
36{
37 static const QVarLengthFlatMap<GUID, QVideoFrameFormat::PixelFormat, 13, GuidLess> map({
38#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
39 { MFVideoFormat_ARGB32, QVideoFrameFormat::Format_BGRA8888 },
40 { MFVideoFormat_RGB32, QVideoFrameFormat::Format_BGRX8888 },
41#else
42 { MFVideoFormat_ARGB32, QVideoFrameFormat::Format_ARGB8888 },
43 { MFVideoFormat_RGB32, QVideoFrameFormat::Format_XRGB8888 },
44#endif
45 { MFVideoFormat_AYUV, QVideoFrameFormat::Format_AYUV },
46 { MFVideoFormat_I420, QVideoFrameFormat::Format_YUV420P },
47 { MFVideoFormat_UYVY, QVideoFrameFormat::Format_UYVY },
48 { MFVideoFormat_YV12, QVideoFrameFormat::Format_YV12 },
49 { MFVideoFormat_NV12, QVideoFrameFormat::Format_NV12 },
50 { MFVideoFormat_YUY2, QVideoFrameFormat::Format_YUYV },
51 { MFVideoFormat_P010, QVideoFrameFormat::Format_P010 },
52 { MFVideoFormat_P016, QVideoFrameFormat::Format_P016 },
53 { MFVideoFormat_L8, QVideoFrameFormat::Format_Y8 },
54 { MFVideoFormat_L16, QVideoFrameFormat::Format_Y16 },
55 { MFVideoFormat_MJPG, QVideoFrameFormat::Format_Jpeg },
56 });
57
58 const auto it = map.find(subtype);
59 return it != map.end() ? it->second : QVideoFrameFormat::Format_Invalid;
60}
61
63{
64 switch (nominalRange) {
65 case MFNominalRange_0_255:
66 return QVideoFrameFormat::ColorRange_Full;
67 case MFNominalRange_16_235:
68 return QVideoFrameFormat::ColorRange_Video;
69 default:
70 return QVideoFrameFormat::ColorRange_Unknown;
71 }
72}
73
75{
76 switch (yuvMatrix) {
77 case MFVideoTransferMatrix_BT709:
78 return QVideoFrameFormat::ColorSpace_BT709;
79 case MFVideoTransferMatrix_BT601:
80 return QVideoFrameFormat::ColorSpace_BT601;
81 case MFVideoTransferMatrix_BT2020_10:
82 case MFVideoTransferMatrix_BT2020_12:
83 return QVideoFrameFormat::ColorSpace_BT2020;
84 default:
85 return QVideoFrameFormat::ColorSpace_Undefined;
86 }
87}
88
89GUID videoFormatForCodec(QMediaFormat::VideoCodec codec)
90{
91 switch (codec) {
92 case QMediaFormat::VideoCodec::MPEG1:
93 return MFVideoFormat_MPG1;
94 case QMediaFormat::VideoCodec::MPEG2:
95 return MFVideoFormat_MPEG2;
96 case QMediaFormat::VideoCodec::MPEG4:
97 return MFVideoFormat_MP4V;
98 case QMediaFormat::VideoCodec::H264:
99 return MFVideoFormat_H264;
100 case QMediaFormat::VideoCodec::H265:
101 return MFVideoFormat_H265;
102 case QMediaFormat::VideoCodec::VP8:
103 return MFVideoFormat_VP80;
104 case QMediaFormat::VideoCodec::VP9:
105 return MFVideoFormat_VP90;
106 case QMediaFormat::VideoCodec::AV1:
107 return MFVideoFormat_AV1;
108 case QMediaFormat::VideoCodec::WMV:
109 return MFVideoFormat_WMV3;
110 case QMediaFormat::VideoCodec::MotionJPEG:
111 return MFVideoFormat_MJPG;
112 default:
113 return MFVideoFormat_H264;
114 }
115}
116
118{
119 static const QVarLengthFlatMap<GUID, QMediaFormat::VideoCodec, 15, GuidLess> map({
120 { MFVideoFormat_MPG1, QMediaFormat::VideoCodec::MPEG1 },
121 { MFVideoFormat_MPEG2, QMediaFormat::VideoCodec::MPEG2 },
122 { MFVideoFormat_MP4V, QMediaFormat::VideoCodec::MPEG4 },
123 { MFVideoFormat_M4S2, QMediaFormat::VideoCodec::MPEG4 },
124 { MFVideoFormat_MP4S, QMediaFormat::VideoCodec::MPEG4 },
125 { MFVideoFormat_MP43, QMediaFormat::VideoCodec::MPEG4 },
126 { MFVideoFormat_H264, QMediaFormat::VideoCodec::H264 },
127 { MFVideoFormat_H265, QMediaFormat::VideoCodec::H265 },
128 { MFVideoFormat_VP80, QMediaFormat::VideoCodec::VP8 },
129 { MFVideoFormat_VP90, QMediaFormat::VideoCodec::VP9 },
130 { MFVideoFormat_AV1, QMediaFormat::VideoCodec::AV1 },
131 { MFVideoFormat_WMV1, QMediaFormat::VideoCodec::WMV },
132 { MFVideoFormat_WMV2, QMediaFormat::VideoCodec::WMV },
133 { MFVideoFormat_WMV3, QMediaFormat::VideoCodec::WMV },
134 { MFVideoFormat_MJPG, QMediaFormat::VideoCodec::MotionJPEG },
135 });
136
137 const auto it = map.find(format);
138 return it != map.end() ? it->second : QMediaFormat::VideoCodec::Unspecified;
139}
140
141GUID audioFormatForCodec(QMediaFormat::AudioCodec codec)
142{
143 switch (codec) {
144 case QMediaFormat::AudioCodec::MP3:
145 return MFAudioFormat_MP3;
146 case QMediaFormat::AudioCodec::AAC:
147 return MFAudioFormat_AAC;
148 case QMediaFormat::AudioCodec::ALAC:
149 return MFAudioFormat_ALAC;
150 case QMediaFormat::AudioCodec::FLAC:
151 return MFAudioFormat_FLAC;
152 case QMediaFormat::AudioCodec::Vorbis:
153 return MFAudioFormat_Vorbis;
154 case QMediaFormat::AudioCodec::Wave:
155 return MFAudioFormat_PCM;
156 case QMediaFormat::AudioCodec::Opus:
157 return MFAudioFormat_Opus;
158 case QMediaFormat::AudioCodec::AC3:
159 return MFAudioFormat_Dolby_AC3;
160 case QMediaFormat::AudioCodec::EAC3:
161 return MFAudioFormat_Dolby_DDPlus;
162 case QMediaFormat::AudioCodec::WMA:
163 return MFAudioFormat_WMAudioV9;
164 default:
165 return MFAudioFormat_AAC;
166 }
167}
168
170{
171 static const QVarLengthFlatMap<GUID, QMediaFormat::AudioCodec, 12, GuidLess> map({
172 { MFAudioFormat_MP3, QMediaFormat::AudioCodec::MP3 },
173 { MFAudioFormat_AAC, QMediaFormat::AudioCodec::AAC },
174 { MFAudioFormat_ALAC, QMediaFormat::AudioCodec::ALAC },
175 { MFAudioFormat_FLAC, QMediaFormat::AudioCodec::FLAC },
176 { MFAudioFormat_Vorbis, QMediaFormat::AudioCodec::Vorbis },
177 { MFAudioFormat_PCM, QMediaFormat::AudioCodec::Wave },
178 { MFAudioFormat_Opus, QMediaFormat::AudioCodec::Opus },
179 { MFAudioFormat_Dolby_AC3, QMediaFormat::AudioCodec::AC3 },
180 { MFAudioFormat_Dolby_DDPlus, QMediaFormat::AudioCodec::EAC3 },
181 { MFAudioFormat_WMAudioV8, QMediaFormat::AudioCodec::WMA },
182 { MFAudioFormat_WMAudioV9, QMediaFormat::AudioCodec::WMA },
183 { MFAudioFormat_WMAudio_Lossless, QMediaFormat::AudioCodec::WMA },
184 });
185
186 const auto it = map.find(format);
187 return it != map.end() ? it->second : QMediaFormat::AudioCodec::Unspecified;
188}
189
190std::optional<GUID> containerForVideoFileFormat(QMediaFormat::FileFormat format)
191{
192 switch (format) {
193 case QMediaFormat::FileFormat::MPEG4:
194 return MFTranscodeContainerType_MPEG4;
195 case QMediaFormat::FileFormat::WMV:
196 return MFTranscodeContainerType_ASF;
197 case QMediaFormat::FileFormat::AVI:
198 return MFTranscodeContainerType_AVI;
199 default:
200 return std::nullopt;
201 }
202}
203
204std::optional<GUID> containerForAudioFileFormat(QMediaFormat::FileFormat format)
205{
206 switch (format) {
207 case QMediaFormat::FileFormat::MP3:
208 return MFTranscodeContainerType_MP3;
209 case QMediaFormat::FileFormat::AAC:
210 return MFTranscodeContainerType_ADTS;
211 case QMediaFormat::FileFormat::Mpeg4Audio:
212 return MFTranscodeContainerType_MPEG4;
213 case QMediaFormat::FileFormat::WMA:
214 return MFTranscodeContainerType_ASF;
215 case QMediaFormat::FileFormat::FLAC:
216 return MFTranscodeContainerType_FLAC;
217 case QMediaFormat::FileFormat::Wave:
218 return MFTranscodeContainerType_WAVE;
219 default:
220 return std::nullopt;
221 }
222}
223
224std::optional<QCameraFormat> cameraFormatFromMediaType(IMFMediaType *mediaFormat)
225{
226 GUID subtype = GUID_NULL;
227 if (FAILED(mediaFormat->GetGUID(MF_MT_SUBTYPE, &subtype)))
228 return std::nullopt;
229
230 auto pixelFormat = pixelFormatFromMediaSubtype(subtype);
231 if (pixelFormat == QVideoFrameFormat::Format_Invalid)
232 return std::nullopt;
233
234 UINT32 nominalRange = 0;
235 auto colorRange = QVideoFrameFormat::ColorRange_Unknown;
236
237 if (SUCCEEDED(mediaFormat->GetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, &nominalRange)))
238 colorRange = colorRangeFromNominalRange(nominalRange);
239
240 UINT32 yuvMatrix = 0;
241 auto colorSpace = QVideoFrameFormat::ColorSpace_Undefined;
242
243 if (SUCCEEDED(mediaFormat->GetUINT32(MF_MT_YUV_MATRIX , &yuvMatrix)))
244 colorSpace = colorSpaceFromMatrix(yuvMatrix);
245
246 UINT32 width = 0u;
247 UINT32 height = 0u;
248 if (FAILED(MFGetAttributeSize(mediaFormat, MF_MT_FRAME_SIZE, &width, &height)))
249 return std::nullopt;
250 QSize resolution{ int(width), int(height) };
251
252 UINT32 num = 0u;
253 UINT32 den = 0u;
254 float minFr = 0.f;
255 float maxFr = 0.f;
256
257 if (SUCCEEDED(MFGetAttributeRatio(mediaFormat, MF_MT_FRAME_RATE_RANGE_MIN, &num, &den)))
258 minFr = float(num) / float(den);
259
260 if (SUCCEEDED(MFGetAttributeRatio(mediaFormat, MF_MT_FRAME_RATE_RANGE_MAX, &num, &den)))
261 maxFr = float(num) / float(den);
262
263 // The range attributes are optional: a source enumerating one media type per
264 // discrete frame rate states only MF_MT_FRAME_RATE.
265 if ((minFr == 0.f || maxFr == 0.f)
266 && SUCCEEDED(MFGetAttributeRatio(mediaFormat, MF_MT_FRAME_RATE, &num, &den))) {
267 const float frameRate = float(num) / float(den);
268 if (minFr == 0.f)
269 minFr = frameRate;
270 if (maxFr == 0.f)
271 maxFr = frameRate;
272 }
273
274 auto *f = new QCameraFormatPrivate{
275 QSharedData(), pixelFormat, resolution, minFr, maxFr, colorRange, colorSpace,
276 };
277 return f->create();
278}
279
280} // namespace QWMF
281
282QT_END_NAMESPACE
GUID audioFormatForCodec(QMediaFormat::AudioCodec codec)
QVideoFrameFormat::ColorRange colorRangeFromNominalRange(UINT32 nominalRange)
QMediaFormat::VideoCodec codecForVideoFormat(GUID format)
QMediaFormat::AudioCodec codecForAudioFormat(GUID format)
QVideoFrameFormat::PixelFormat pixelFormatFromMediaSubtype(const GUID &subtype)
std::optional< GUID > containerForVideoFileFormat(QMediaFormat::FileFormat format)
GUID videoFormatForCodec(QMediaFormat::VideoCodec codec)
QVideoFrameFormat::ColorSpace colorSpaceFromMatrix(UINT32 yuvMatrix)
std::optional< QCameraFormat > cameraFormatFromMediaType(IMFMediaType *mediaFormat)
std::optional< GUID > containerForAudioFileFormat(QMediaFormat::FileFormat format)