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
qplatformmediaformatinfo.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 <QtCore/qdebug.h>
7#include <QtCore/qloggingcategory.h>
8#include <QtMultimedia/private/qmultimedia_ranges_p.h>
9
10#include <set>
11
13
14Q_STATIC_LOGGING_CATEGORY(lcMediaFormatInfo, "qt.multimedia.mediaformatinfo", QtWarningMsg)
15
16QPlatformMediaFormatInfo::QPlatformMediaFormatInfo() = default;
17
18QPlatformMediaFormatInfo::~QPlatformMediaFormatInfo() = default;
19
20QList<QMediaFormat::FileFormat> QPlatformMediaFormatInfo::supportedFileFormats(const QMediaFormat &constraints, QMediaFormat::ConversionMode m) const
21{
22 std::set<QMediaFormat::FileFormat> formats;
23
24 const auto &codecMap = (m == QMediaFormat::Encode) ? encoders : decoders;
25 for (const auto &m : codecMap) {
26 if (constraints.audioCodec() != QMediaFormat::AudioCodec::Unspecified && !m.audio.contains(constraints.audioCodec()))
27 continue;
28 if (constraints.videoCodec() != QMediaFormat::VideoCodec::Unspecified && !m.video.contains(constraints.videoCodec()))
29 continue;
30 formats.insert(m.format);
31 }
32 return { formats.begin(), formats.end() };
33}
34
35QList<QMediaFormat::AudioCodec> QPlatformMediaFormatInfo::supportedAudioCodecs(const QMediaFormat &constraints, QMediaFormat::ConversionMode m) const
36{
37 std::set<QMediaFormat::AudioCodec> codecs;
38
39 const auto &codecMap = (m == QMediaFormat::Encode) ? encoders : decoders;
40 for (const auto &m : codecMap) {
41 if (constraints.fileFormat() != QMediaFormat::UnspecifiedFormat && m.format != constraints.fileFormat())
42 continue;
43 if (constraints.videoCodec() != QMediaFormat::VideoCodec::Unspecified && !m.video.contains(constraints.videoCodec()))
44 continue;
45 for (const auto &c : m.audio)
46 codecs.insert(c);
47 }
48
49 return { codecs.begin(), codecs.end() };
50}
51
52QList<QMediaFormat::VideoCodec> QPlatformMediaFormatInfo::supportedVideoCodecs(const QMediaFormat &constraints, QMediaFormat::ConversionMode m) const
53{
54 std::set<QMediaFormat::VideoCodec> codecs;
55
56 const auto &codecMap = (m == QMediaFormat::Encode) ? encoders : decoders;
57 for (const auto &m : codecMap) {
58 if (constraints.fileFormat() != QMediaFormat::UnspecifiedFormat && m.format != constraints.fileFormat())
59 continue;
60 if (constraints.audioCodec() != QMediaFormat::AudioCodec::Unspecified && !m.audio.contains(constraints.audioCodec()))
61 continue;
62 for (const auto &c : m.video)
63 codecs.insert(c);
64 }
65 return { codecs.begin(), codecs.end() };
66}
67
68bool QPlatformMediaFormatInfo::isSupported(const QMediaFormat &format, QMediaFormat::ConversionMode m) const
69{
70 const auto &codecMap = (m == QMediaFormat::Encode) ? encoders : decoders;
71
72 for (const auto &m : codecMap) {
73 if (m.format != format.fileFormat())
74 continue;
75 if (format.audioCodec() != QMediaFormat::AudioCodec::Unspecified && !m.audio.contains(format.audioCodec()))
76 continue;
77 if (format.videoCodec() != QMediaFormat::VideoCodec::Unspecified && !m.video.contains(format.videoCodec()))
78 continue;
79 return true;
80 }
81 return false;
82}
83
84void QPlatformMediaFormatInfo::fixupCodecMaps()
85{
86 // Remove codecs that are not supported in the given container format. This is needed because some backends report
87 // codecs that are not actually supported in a given container format or that are rather edge cases.
88
89 using FileFormat = QMediaFormat::FileFormat;
90 using AudioCodec = QMediaFormat::AudioCodec;
91 using VideoCodec = QMediaFormat::VideoCodec;
92 namespace ranges = QtMultimediaPrivate::ranges;
93
94 auto fixupMap = [](CodecMap &cm) {
95 auto removeInvalidAudio = [&](auto predicate) {
96 cm.audio.removeIf([&](AudioCodec c) {
97 if (predicate(c)) {
98 qCDebug(lcMediaFormatInfo)
99 << "Removing audio codec" << c << "unsupported in" << cm.format;
100 return true;
101 }
102 return false;
103 });
104 };
105
106 auto removeInvalidVideo = [&](auto predicate) {
107 cm.video.removeIf([&](VideoCodec c) {
108 if (predicate(c)) {
109 qCDebug(lcMediaFormatInfo)
110 << "Removing video codec" << c << "unsupported in" << cm.format;
111 return true;
112 }
113 return false;
114 });
115 };
116
117 auto fixupSingleCodecAudioContainer = [&](AudioCodec singleCodec) {
118 removeInvalidAudio([&](AudioCodec c) {
119 return c != singleCodec;
120 });
121 removeInvalidVideo([](VideoCodec) {
122 return true;
123 });
124 };
125
126 switch (cm.format) {
127 case FileFormat::WebM:
128 removeInvalidVideo([](VideoCodec c) {
129 return !ranges::contains(
130 std::array{ VideoCodec::VP8, VideoCodec::VP9, VideoCodec::AV1 }, c);
131 });
132 removeInvalidAudio([](AudioCodec c) {
133 return !ranges::contains(std::array{ AudioCodec::Vorbis, AudioCodec::Opus }, c);
134 });
135 break;
136 case FileFormat::Ogg:
137 removeInvalidVideo([](VideoCodec c) {
138 return c != VideoCodec::Theora;
139 });
140 removeInvalidAudio([](AudioCodec c) {
141 return !ranges::contains(
142 std::array{ AudioCodec::Vorbis, AudioCodec::Opus, AudioCodec::FLAC }, c);
143 });
144 break;
145 case FileFormat::MPEG4:
146 case FileFormat::QuickTime:
147 removeInvalidVideo([](VideoCodec c) {
148 return ranges::contains(std::array{ VideoCodec::VP8, VideoCodec::VP9,
149 VideoCodec::Theora, VideoCodec::WMV },
150 c);
151 });
152 removeInvalidAudio([](AudioCodec c) {
153 return ranges::contains(
154 std::array{ AudioCodec::Vorbis, AudioCodec::Opus, AudioCodec::WMA }, c);
155 });
156 break;
157 case FileFormat::WMV:
158 // Caveat: WMV files are ASF Containers with WMV video codec and WMA audio codec.
159 removeInvalidVideo([](VideoCodec c) {
160 return c != VideoCodec::WMV;
161 });
162 removeInvalidAudio([](AudioCodec c) {
163 return c != AudioCodec::WMA;
164 });
165 break;
166 case FileFormat::Wave:
167 fixupSingleCodecAudioContainer(AudioCodec::Wave);
168 break;
169 case FileFormat::MP3:
170 fixupSingleCodecAudioContainer(AudioCodec::MP3);
171 break;
172 case FileFormat::WMA:
173 // Caveat: WMA files are ASF Containers with WMA audio codec.
174 fixupSingleCodecAudioContainer(AudioCodec::WMA);
175 break;
176 case FileFormat::AAC:
177 fixupSingleCodecAudioContainer(AudioCodec::AAC);
178 break;
179 case FileFormat::FLAC:
180 fixupSingleCodecAudioContainer(AudioCodec::FLAC);
181 break;
182 case FileFormat::Mpeg4Audio:
183 removeInvalidVideo([](VideoCodec) {
184 return true;
185 });
186 break;
187 default:
188 break;
189 }
190 };
191
192 for (auto &cm : encoders)
193 fixupMap(cm);
194 for (auto &cm : decoders)
195 fixupMap(cm);
196
197 auto isEmpty = [](const CodecMap &cm) {
198 return cm.audio.isEmpty() && cm.video.isEmpty();
199 };
200 encoders.removeIf(isEmpty);
201 decoders.removeIf(isEmpty);
202}
203
204QDebug operator<<(QDebug dbg, const QPlatformMediaFormatInfo::CodecMap &m)
205{
206 const QDebugStateSaver saver(dbg);
207 dbg.nospace() << "CodecMap(" << QMediaFormat::fileFormatName(m.format);
208 if (!m.video.isEmpty()) {
209 dbg << ", video: [";
210 for (int i = 0; i < m.video.size(); ++i) {
211 if (i)
212 dbg << ", ";
213 dbg << QMediaFormat::videoCodecName(m.video[i]);
214 }
215 dbg << ']';
216 }
217 if (!m.audio.isEmpty()) {
218 dbg << ", audio: [";
219 for (int i = 0; i < m.audio.size(); ++i) {
220 if (i)
221 dbg << ", ";
222 dbg << QMediaFormat::audioCodecName(m.audio[i]);
223 }
224 dbg << ']';
225 }
226 dbg << ')';
227 return dbg;
228}
229
230QT_END_NAMESPACE
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)