Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qgstreamerformatinfo.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
6
7#include <gst/gst.h>
8
10
12{
13 const char *name = structure.name().data();
14
15 if (!name || strncmp(name, "audio/", 6))
17 name += 6;
18 if (!strcmp(name, "mpeg")) {
19 auto version = structure["mpegversion"].toInt();
20 if (version == 1) {
21 auto layer = structure["layer"];
22 if (!layer.isNull())
24 }
25 if (version == 4)
27 } else if (!strcmp(name, "x-ac3")) {
29 } else if (!strcmp(name, "x-eac3")) {
31 } else if (!strcmp(name, "x-flac")) {
33 } else if (!strcmp(name, "x-alac")) {
35 } else if (!strcmp(name, "x-true-hd")) {
37 } else if (!strcmp(name, "x-vorbis")) {
39 } else if (!strcmp(name, "x-opus")) {
41 } else if (!strcmp(name, "x-wav")) {
43 } else if (!strcmp(name, "x-wma")) {
45 }
47}
48
50{
51 const char *name = structure.name().data();
52
53 if (!name || strncmp(name, "video/", 6))
55 name += 6;
56
57 if (!strcmp(name, "mpeg")) {
58 auto version = structure["mpegversion"].toInt();
59 if (version == 1)
61 else if (version == 2)
63 else if (version == 4)
65 } else if (!strcmp(name, "x-h264")) {
67#if GST_CHECK_VERSION(1, 17, 0) // x265enc seems to be broken on 1.16 at least
68 } else if (!strcmp(name, "x-h265")) {
70#endif
71 } else if (!strcmp(name, "x-vp8")) {
73 } else if (!strcmp(name, "x-vp9")) {
75 } else if (!strcmp(name, "x-av1")) {
77 } else if (!strcmp(name, "x-theora")) {
79 } else if (!strcmp(name, "x-jpeg")) {
81 } else if (!strcmp(name, "x-wmv")) {
83 }
85}
86
88{
89 const char *name = structure.name().data();
90
91 if (!strcmp(name, "video/x-ms-asf")) {
93 } else if (!strcmp(name, "video/x-msvideo")) {
95 } else if (!strcmp(name, "video/x-matroska")) {
97 } else if (!strcmp(name, "video/quicktime")) {
98 auto variant = structure["variant"].toString();
99 if (!variant)
101 else if (!strcmp(variant, "iso"))
103 } else if (!strcmp(name, "video/ogg")) {
105 } else if (!strcmp(name, "video/webm")) {
107 } else if (!strcmp(name, "audio/x-m4a")) {
109 } else if (!strcmp(name, "audio/x-wav")) {
111 } else if (!strcmp(name, "audio/mpeg")) {
112 auto mpegversion = structure["mpegversion"].toInt();
113 if (mpegversion == 1) {
114 auto layer = structure["layer"];
115 if (!layer.isNull())
117 }
118 }
120}
121
122
124{
125 const char *name = structure.name().data();
126
127 if (!strcmp(name, "image/jpeg")) {
128 return QImageCapture::JPEG;
129 } else if (!strcmp(name, "image/png")) {
130 return QImageCapture::PNG;
131 } else if (!strcmp(name, "image/webp")) {
132 return QImageCapture::WebP;
133 } else if (!strcmp(name, "image/tiff")) {
134 return QImageCapture::Tiff;
135 }
137}
138
139static QPair<QList<QMediaFormat::AudioCodec>, QList<QMediaFormat::VideoCodec>> getCodecsList(bool decode)
140{
141 QList<QMediaFormat::AudioCodec> audio;
142 QList<QMediaFormat::VideoCodec> video;
143
144 GstPadDirection padDirection = decode ? GST_PAD_SINK : GST_PAD_SRC;
145
146 GList *elementList = gst_element_factory_list_get_elements(decode ? GST_ELEMENT_FACTORY_TYPE_DECODER : GST_ELEMENT_FACTORY_TYPE_ENCODER,
147 GST_RANK_MARGINAL);
148
149 for (GstElementFactory *factory :
151 for (GstStaticPadTemplate *padTemplate :
153 gst_element_factory_get_static_pad_templates(factory))) {
154 if (padTemplate->direction == padDirection) {
155 auto caps = QGstCaps(gst_static_caps_get(&padTemplate->static_caps), QGstCaps::HasRef);
156
157 for (int i = 0; i < caps.size(); i++) {
158 QGstStructure structure = caps.at(i);
160 if (a != QMediaFormat::AudioCodec::Unspecified && !audio.contains(a))
161 audio.append(a);
163 if (v != QMediaFormat::VideoCodec::Unspecified && !video.contains(v))
164 video.append(v);
165 }
166 }
167 }
168 }
169 gst_plugin_feature_list_free(elementList);
170 return {audio, video};
171}
172
173
174QList<QGstreamerFormatInfo::CodecMap> QGstreamerFormatInfo::getMuxerList(bool demuxer,
175 QList<QMediaFormat::AudioCodec> supportedAudioCodecs,
176 QList<QMediaFormat::VideoCodec> supportedVideoCodecs)
177{
178 QList<QGstreamerFormatInfo::CodecMap> muxers;
179
180 GstPadDirection padDirection = demuxer ? GST_PAD_SINK : GST_PAD_SRC;
181
182 GList *elementList = gst_element_factory_list_get_elements(
183 demuxer ? GST_ELEMENT_FACTORY_TYPE_DEMUXER : GST_ELEMENT_FACTORY_TYPE_MUXER,
184 GST_RANK_MARGINAL);
185
186 for (GstElementFactory *factory :
188 QList<QMediaFormat::FileFormat> fileFormats;
189
190 for (GstStaticPadTemplate *padTemplate :
192 gst_element_factory_get_static_pad_templates(factory))) {
193
194 if (padTemplate->direction == padDirection) {
195 auto caps = QGstCaps(gst_static_caps_get(&padTemplate->static_caps), QGstCaps::HasRef);
196
197 for (int i = 0; i < caps.size(); i++) {
198 QGstStructure structure = caps.at(i);
199 auto fmt = fileFormatForCaps(structure);
201 fileFormats.append(fmt);
202 }
203 }
204 }
205 if (fileFormats.isEmpty())
206 continue;
207
208 QList<QMediaFormat::AudioCodec> audioCodecs;
209 QList<QMediaFormat::VideoCodec> videoCodecs;
210
211 for (GstStaticPadTemplate *padTemplate :
213 gst_element_factory_get_static_pad_templates(factory))) {
214
215 // check the other side for supported inputs/outputs
216 if (padTemplate->direction != padDirection) {
217 auto caps = QGstCaps(gst_static_caps_get(&padTemplate->static_caps), QGstCaps::HasRef);
218
219 bool acceptsRawAudio = false;
220 for (int i = 0; i < caps.size(); i++) {
221 QGstStructure structure = caps.at(i);
222 if (structure.name() == "audio/x-raw")
223 acceptsRawAudio = true;
224 auto audio = audioCodecForCaps(structure);
226 audioCodecs.append(audio);
227 auto video = videoCodecForCaps(structure);
229 videoCodecs.append(video);
230 }
231 if (acceptsRawAudio && fileFormats.size() == 1) {
232 switch (fileFormats.at(0)) {
234 default:
235 break;
237 audioCodecs.append(QMediaFormat::AudioCodec::MP3);
238 break;
240 audioCodecs.append(QMediaFormat::AudioCodec::FLAC);
241 break;
243 audioCodecs.append(QMediaFormat::AudioCodec::Wave);
244 break;
245 }
246 }
247 }
248 }
249 if (!audioCodecs.isEmpty() || !videoCodecs.isEmpty()) {
250 for (auto f : std::as_const(fileFormats)) {
251 muxers.append({f, audioCodecs, videoCodecs});
252 if (f == QMediaFormat::MPEG4 && !fileFormats.contains(QMediaFormat::Mpeg4Audio)) {
253 muxers.append({QMediaFormat::Mpeg4Audio, audioCodecs, {}});
254 if (audioCodecs.contains(QMediaFormat::AudioCodec::AAC))
255 muxers.append({QMediaFormat::AAC, { QMediaFormat::AudioCodec::AAC }, {}});
256 } else if (f == QMediaFormat::WMV && !fileFormats.contains(QMediaFormat::WMA)) {
257 muxers.append({QMediaFormat::WMA, audioCodecs, {}});
258 }
259 }
260 }
261 }
262 gst_plugin_feature_list_free(elementList);
263 return muxers;
264}
265
266static QList<QImageCapture::FileFormat> getImageFormatList()
267{
268 QSet<QImageCapture::FileFormat> formats;
269
270 GList *elementList = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_ENCODER,
271 GST_RANK_MARGINAL);
272
273 for (GstElementFactory *factory :
275
276 for (GstStaticPadTemplate *padTemplate :
278 gst_element_factory_get_static_pad_templates(factory))) {
279 if (padTemplate->direction == GST_PAD_SRC) {
280 QGstCaps caps = QGstCaps(gst_static_caps_get(&padTemplate->static_caps), QGstCaps::HasRef);
281
282 for (int i = 0; i < caps.size(); i++) {
283 QGstStructure structure = caps.at(i);
286// qDebug() << structure.toString() << f;
287 formats.insert(f);
288 }
289 }
290 }
291 }
292 }
293 gst_plugin_feature_list_free(elementList);
294 return formats.values();
295}
296
297#if 0
298static void dumpAudioCodecs(const QList<QMediaFormat::AudioCodec> &codecList)
299{
300 qDebug() << "Audio codecs:";
301 for (const auto &c : codecList)
302 qDebug() << " " << QMediaFormat::audioCodecName(c);
303}
304
305static void dumpVideoCodecs(const QList<QMediaFormat::VideoCodec> &codecList)
306{
307 qDebug() << "Video codecs:";
308 for (const auto &c : codecList)
309 qDebug() << " " << QMediaFormat::videoCodecName(c);
310}
311
312static void dumpMuxers(const QList<QPlatformMediaFormatInfo::CodecMap> &muxerList)
313{
314 for (const auto &m : muxerList) {
315 qDebug() << " " << QMediaFormat::fileFormatName(m.format);
316 qDebug() << " Audio";
317 for (const auto &a : m.audio)
318 qDebug() << " " << QMediaFormat::audioCodecName(a);
319 qDebug() << " Video";
320 for (const auto &v : m.video)
321 qDebug() << " " << QMediaFormat::videoCodecName(v);
322 }
323
324}
325#endif
326
328{
329 auto codecs = getCodecsList(/*decode = */ true);
330 decoders = getMuxerList(true, codecs.first, codecs.second);
331
332 codecs = getCodecsList(/*decode = */ false);
333 encoders = getMuxerList(/* demuxer = */false, codecs.first, codecs.second);
334// dumpAudioCodecs(codecs.first);
335// dumpVideoCodecs(codecs.second);
336// dumpMuxers(encoders);
337
339}
340
342
344{
345 auto format = f.fileFormat();
347
348 const char *capsForFormat[QMediaFormat::LastFileFormat + 1] = {
349 "video/x-ms-asf", // WMV
350 "video/x-msvideo", // AVI
351 "video/x-matroska", // Matroska
352 "video/quicktime, variant=(string)iso", // MPEG4
353 "video/ogg", // Ogg
354 "video/quicktime", // QuickTime
355 "video/webm", // WebM
356 "video/quicktime, variant=(string)iso", // Mpeg4Audio is the same is mp4...
357 "video/quicktime, variant=(string)iso", // AAC is also an MP4 container
358 "video/x-ms-asf", // WMA, same as WMV
359 "audio/mpeg, mpegversion=(int)1, layer=(int)3", // MP3
360 "audio/x-flac", // FLAC
361 "audio/x-wav" // Wave
362 };
363 return QGstCaps(gst_caps_from_string(capsForFormat[format]), QGstCaps::HasRef);
364}
365
367{
368 auto codec = f.audioCodec();
370 return {};
371
372 const char *capsForCodec[(int)QMediaFormat::AudioCodec::LastAudioCodec + 1] = {
373 "audio/mpeg, mpegversion=(int)1, layer=(int)3", // MP3
374 "audio/mpeg, mpegversion=(int)4", // AAC
375 "audio/x-ac3", // AC3
376 "audio/x-eac3", // EAC3
377 "audio/x-flac", // FLAC
378 "audio/x-true-hd", // DolbyTrueHD
379 "audio/x-opus", // Opus
380 "audio/x-vorbis", // Vorbis
381 "audio/x-raw", // WAVE
382 "audio/x-wma", // WMA
383 "audio/x-alac", // ALAC
384 };
385 return QGstCaps(gst_caps_from_string(capsForCodec[(int)codec]), QGstCaps::HasRef);
386}
387
389{
390 auto codec = f.videoCodec();
392 return {};
393
394 const char *capsForCodec[(int)QMediaFormat::VideoCodec::LastVideoCodec + 1] = {
395 "video/mpeg, mpegversion=(int)1", // MPEG1,
396 "video/mpeg, mpegversion=(int)2", // MPEG2,
397 "video/mpeg, mpegversion=(int)4", // MPEG4,
398 "video/x-h264", // H264,
399 "video/x-h265", // H265,
400 "video/x-vp8", // VP8,
401 "video/x-vp9", // VP9,
402 "video/x-av1", // AV1,
403 "video/x-theora", // Theora,
404 "audio/x-wmv", // WMV
405 "video/x-jpeg", // MotionJPEG,
406 };
407 return QGstCaps(gst_caps_from_string(capsForCodec[(int)codec]), QGstCaps::HasRef);
408}
409
constexpr const_pointer data() const noexcept
int size() const
Definition qgst.cpp:516
QGstStructure at(int index) const
Definition qgst.cpp:521
QByteArrayView name() const
Definition qgst.cpp:175
QGstCaps formatCaps(const QMediaFormat &f) const
static QMediaFormat::FileFormat fileFormatForCaps(QGstStructure structure)
QGstCaps videoCaps(const QMediaFormat &f) const
static QImageCapture::FileFormat imageFormatForCaps(QGstStructure structure)
static QMediaFormat::VideoCodec videoCodecForCaps(QGstStructure structure)
QList< CodecMap > getMuxerList(bool demuxer, QList< QMediaFormat::AudioCodec > audioCodecs, QList< QMediaFormat::VideoCodec > videoCodecs)
QGstCaps audioCaps(const QMediaFormat &f) const
static QMediaFormat::AudioCodec audioCodecForCaps(QGstStructure structure)
FileFormat
Choose one of the following image formats:
\inmodule QtMultimedia
AudioCodec
\qmlproperty enumeration QtMultimedia::mediaFormat::fileFormat
FileFormat
Describes the container format used in a multimedia file or stream.
VideoCodec
\qmlproperty enumeration QtMultimedia::mediaFormat::audioCodec
static Q_INVOKABLE QString fileFormatName(FileFormat fileFormat)
\qmlmethod string QtMultimedia::mediaFormat::fileFormatName(fileFormat) Returns a string based name f...
QList< QMediaFormat::AudioCodec > supportedAudioCodecs(const QMediaFormat &constraints, QMediaFormat::ConversionMode m) const
QList< QMediaFormat::VideoCodec > supportedVideoCodecs(const QMediaFormat &constraints, QMediaFormat::ConversionMode m) const
QList< QImageCapture::FileFormat > imageFormats
EGLint EGLint * formats
Combined button and popup list for selecting options.
EGLOutputLayerEXT layer
QMediaFormat::AudioCodec codec
static QList< QImageCapture::FileFormat > getImageFormatList()
static QPair< QList< QMediaFormat::AudioCodec >, QList< QMediaFormat::VideoCodec > > getCodecsList(bool decode)
#define qDebug
[1]
Definition qlogging.h:164
GLsizei const GLfloat * v
[13]
const GLfloat * m
GLboolean GLboolean GLboolean GLboolean a
[7]
GLfloat GLfloat f
GLuint name
GLint GLsizei GLsizei GLenum format
const GLubyte * c
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define decode(x)
QVideoFrameFormat::PixelFormat fmt
QVariant variant
[1]
QItemEditorFactory * factory
bool contains(const AT &t) const noexcept
Definition qlist.h:45