Qt 6.x
The Qt SDK
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
5
6#include "qgstutils_p.h"
7
9
11{
12 const char *name = structure.name().data();
13
14 if (!name || strncmp(name, "audio/", 6))
16 name += 6;
17 if (!strcmp(name, "mpeg")) {
18 auto version = structure["mpegversion"].toInt();
19 if (version == 1) {
20 auto layer = structure["layer"];
21 if (!layer.isNull())
23 }
24 if (version == 4)
26 } else if (!strcmp(name, "x-ac3")) {
28 } else if (!strcmp(name, "x-eac3")) {
30 } else if (!strcmp(name, "x-flac")) {
32 } else if (!strcmp(name, "x-alac")) {
34 } else if (!strcmp(name, "x-true-hd")) {
36 } else if (!strcmp(name, "x-vorbis")) {
38 } else if (!strcmp(name, "x-opus")) {
40 } else if (!strcmp(name, "x-wav")) {
42 } else if (!strcmp(name, "x-wma")) {
44 }
46}
47
49{
50 const char *name = structure.name().data();
51
52 if (!name || strncmp(name, "video/", 6))
54 name += 6;
55
56 if (!strcmp(name, "mpeg")) {
57 auto version = structure["mpegversion"].toInt();
58 if (version == 1)
60 else if (version == 2)
62 else if (version == 4)
64 } else if (!strcmp(name, "x-h264")) {
66#if GST_CHECK_VERSION(1, 17, 0) // x265enc seems to be broken on 1.16 at least
67 } else if (!strcmp(name, "x-h265")) {
69#endif
70 } else if (!strcmp(name, "x-vp8")) {
72 } else if (!strcmp(name, "x-vp9")) {
74 } else if (!strcmp(name, "x-av1")) {
76 } else if (!strcmp(name, "x-theora")) {
78 } else if (!strcmp(name, "x-jpeg")) {
80 } else if (!strcmp(name, "x-wmv")) {
82 }
84}
85
87{
88 const char *name = structure.name().data();
89
90 if (!strcmp(name, "video/x-ms-asf")) {
92 } else if (!strcmp(name, "video/x-msvideo")) {
94 } else if (!strcmp(name, "video/x-matroska")) {
96 } else if (!strcmp(name, "video/quicktime")) {
97 auto variant = structure["variant"].toString();
98 if (!variant)
100 else if (!strcmp(variant, "iso"))
102 } else if (!strcmp(name, "video/ogg")) {
104 } else if (!strcmp(name, "video/webm")) {
106 } else if (!strcmp(name, "audio/x-m4a")) {
108 } else if (!strcmp(name, "audio/x-wav")) {
110 } else if (!strcmp(name, "audio/mpeg")) {
111 auto mpegversion = structure["mpegversion"].toInt();
112 if (mpegversion == 1) {
113 auto layer = structure["layer"];
114 if (!layer.isNull())
116 }
117 }
119}
120
121
123{
124 const char *name = structure.name().data();
125
126 if (!strcmp(name, "image/jpeg")) {
127 return QImageCapture::JPEG;
128 } else if (!strcmp(name, "image/png")) {
129 return QImageCapture::PNG;
130 } else if (!strcmp(name, "image/webp")) {
131 return QImageCapture::WebP;
132 } else if (!strcmp(name, "image/tiff")) {
133 return QImageCapture::Tiff;
134 }
136}
137
139{
142
143 GstPadDirection padDirection = decode ? GST_PAD_SINK : GST_PAD_SRC;
144
145 GList *elementList = gst_element_factory_list_get_elements(decode ? GST_ELEMENT_FACTORY_TYPE_DECODER : GST_ELEMENT_FACTORY_TYPE_ENCODER,
146 GST_RANK_MARGINAL);
147
148 GList *element = elementList;
149 while (element) {
150 GstElementFactory *factory = (GstElementFactory *)element->data;
151 element = element->next;
152
153 const GList *padTemplates = gst_element_factory_get_static_pad_templates(factory);
154 while (padTemplates) {
155 GstStaticPadTemplate *padTemplate = (GstStaticPadTemplate *)padTemplates->data;
156 padTemplates = padTemplates->next;
157
158 if (padTemplate->direction == padDirection) {
159 auto caps = QGstCaps(gst_static_caps_get(&padTemplate->static_caps), QGstCaps::HasRef);
160
161 for (int i = 0; i < caps.size(); i++) {
162 QGstStructure structure = caps.at(i);
165 audio.append(a);
168 video.append(v);
169 }
170 }
171 }
172 }
173 gst_plugin_feature_list_free(elementList);
174 return {audio, video};
175}
176
177
179 QList<QMediaFormat::AudioCodec> supportedAudioCodecs,
180 QList<QMediaFormat::VideoCodec> supportedVideoCodecs)
181{
183
184 GstPadDirection padDirection = demuxer ? GST_PAD_SINK : GST_PAD_SRC;
185
186 GList *elementList = gst_element_factory_list_get_elements(demuxer ? GST_ELEMENT_FACTORY_TYPE_DEMUXER : GST_ELEMENT_FACTORY_TYPE_MUXER,
187 GST_RANK_MARGINAL);
188 GList *element = elementList;
189 while (element) {
190 GstElementFactory *factory = (GstElementFactory *)element->data;
191 element = element->next;
192
194
195 const GList *padTemplates = gst_element_factory_get_static_pad_templates(factory);
196 while (padTemplates) {
197 GstStaticPadTemplate *padTemplate = (GstStaticPadTemplate *)padTemplates->data;
198 padTemplates = padTemplates->next;
199
200 if (padTemplate->direction == padDirection) {
201 auto caps = QGstCaps(gst_static_caps_get(&padTemplate->static_caps), QGstCaps::HasRef);
202
203 for (int i = 0; i < caps.size(); i++) {
204 QGstStructure structure = caps.at(i);
205 auto fmt = fileFormatForCaps(structure);
207 fileFormats.append(fmt);
208 }
209 }
210 }
211 if (fileFormats.isEmpty())
212 continue;
213
216
217 padTemplates = gst_element_factory_get_static_pad_templates(factory);
218 while (padTemplates) {
219 GstStaticPadTemplate *padTemplate = (GstStaticPadTemplate *)padTemplates->data;
220 padTemplates = padTemplates->next;
221
222 // check the other side for supported inputs/outputs
223 if (padTemplate->direction != padDirection) {
224 auto caps = QGstCaps(gst_static_caps_get(&padTemplate->static_caps), QGstCaps::HasRef);
225
226 bool acceptsRawAudio = false;
227 for (int i = 0; i < caps.size(); i++) {
228 QGstStructure structure = caps.at(i);
229 if (structure.name() == "audio/x-raw")
230 acceptsRawAudio = true;
231 auto audio = audioCodecForCaps(structure);
233 audioCodecs.append(audio);
234 auto video = videoCodecForCaps(structure);
236 videoCodecs.append(video);
237 }
238 if (acceptsRawAudio && fileFormats.size() == 1) {
239 switch (fileFormats.at(0)) {
241 default:
242 break;
245 break;
248 break;
251 break;
252 }
253 }
254 }
255 }
256 if (!audioCodecs.isEmpty() || !videoCodecs.isEmpty()) {
257 for (auto f : std::as_const(fileFormats)) {
258 muxers.append({f, audioCodecs, videoCodecs});
259 if (f == QMediaFormat::MPEG4 && !fileFormats.contains(QMediaFormat::Mpeg4Audio)) {
260 muxers.append({QMediaFormat::Mpeg4Audio, audioCodecs, {}});
263 } else if (f == QMediaFormat::WMV && !fileFormats.contains(QMediaFormat::WMA)) {
264 muxers.append({QMediaFormat::WMA, audioCodecs, {}});
265 }
266 }
267 }
268 }
269 gst_plugin_feature_list_free(elementList);
270 return muxers;
271}
272
274{
276
277 GList *elementList = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_ENCODER,
278 GST_RANK_MARGINAL);
279
280 GList *element = elementList;
281 while (element) {
282 GstElementFactory *factory = (GstElementFactory *)element->data;
283 element = element->next;
284
285 const GList *padTemplates = gst_element_factory_get_static_pad_templates(factory);
286 while (padTemplates) {
287 GstStaticPadTemplate *padTemplate = (GstStaticPadTemplate *)padTemplates->data;
288 padTemplates = padTemplates->next;
289
290 if (padTemplate->direction == GST_PAD_SRC) {
291 QGstCaps caps = QGstCaps(gst_static_caps_get(&padTemplate->static_caps), QGstCaps::HasRef);
292
293 for (int i = 0; i < caps.size(); i++) {
294 QGstStructure structure = caps.at(i);
297// qDebug() << structure.toString() << f;
298 formats.insert(f);
299 }
300 }
301 }
302 }
303 }
304 gst_plugin_feature_list_free(elementList);
305 return formats.values();
306}
307
308#if 0
309static void dumpAudioCodecs(const QList<QMediaFormat::AudioCodec> &codecList)
310{
311 qDebug() << "Audio codecs:";
312 for (const auto &c : codecList)
313 qDebug() << " " << QMediaFormat::audioCodecName(c);
314}
315
316static void dumpVideoCodecs(const QList<QMediaFormat::VideoCodec> &codecList)
317{
318 qDebug() << "Video codecs:";
319 for (const auto &c : codecList)
320 qDebug() << " " << QMediaFormat::videoCodecName(c);
321}
322
323static void dumpMuxers(const QList<QPlatformMediaFormatInfo::CodecMap> &muxerList)
324{
325 for (const auto &m : muxerList) {
326 qDebug() << " " << QMediaFormat::fileFormatName(m.format);
327 qDebug() << " Audio";
328 for (const auto &a : m.audio)
329 qDebug() << " " << QMediaFormat::audioCodecName(a);
330 qDebug() << " Video";
331 for (const auto &v : m.video)
332 qDebug() << " " << QMediaFormat::videoCodecName(v);
333 }
334
335}
336#endif
337
339{
340 auto codecs = getCodecsList(/*decode = */ true);
341 decoders = getMuxerList(true, codecs.first, codecs.second);
342
343 codecs = getCodecsList(/*decode = */ false);
344 encoders = getMuxerList(/* demuxer = */false, codecs.first, codecs.second);
345// dumpAudioCodecs(codecs.first);
346// dumpVideoCodecs(codecs.second);
347// dumpMuxers(encoders);
348
350}
351
353
355{
356 auto format = f.fileFormat();
358
359 const char *capsForFormat[QMediaFormat::LastFileFormat + 1] = {
360 "video/x-ms-asf", // WMV
361 "video/x-msvideo", // AVI
362 "video/x-matroska", // Matroska
363 "video/quicktime, variant=(string)iso", // MPEG4
364 "video/ogg", // Ogg
365 "video/quicktime", // QuickTime
366 "video/webm", // WebM
367 "video/quicktime, variant=(string)iso", // Mpeg4Audio is the same is mp4...
368 "video/quicktime, variant=(string)iso", // AAC is also an MP4 container
369 "video/x-ms-asf", // WMA, same as WMV
370 "audio/mpeg, mpegversion=(int)1, layer=(int)3", // MP3
371 "audio/x-flac", // FLAC
372 "audio/x-wav" // Wave
373 };
374 return QGstCaps(gst_caps_from_string(capsForFormat[format]), QGstCaps::HasRef);
375}
376
378{
379 auto codec = f.audioCodec();
381 return {};
382
383 const char *capsForCodec[(int)QMediaFormat::AudioCodec::LastAudioCodec + 1] = {
384 "audio/mpeg, mpegversion=(int)1, layer=(int)3", // MP3
385 "audio/mpeg, mpegversion=(int)4", // AAC
386 "audio/x-ac3", // AC3
387 "audio/x-eac3", // EAC3
388 "audio/x-flac", // FLAC
389 "audio/x-true-hd", // DolbyTrueHD
390 "audio/x-opus", // Opus
391 "audio/x-vorbis", // Vorbis
392 "audio/x-raw", // WAVE
393 "audio/x-wma", // WMA
394 "audio/x-alac", // ALAC
395 };
396 return QGstCaps(gst_caps_from_string(capsForCodec[(int)codec]), QGstCaps::HasRef);
397}
398
400{
401 auto codec = f.videoCodec();
403 return {};
404
405 const char *capsForCodec[(int)QMediaFormat::VideoCodec::LastVideoCodec + 1] = {
406 "video/mpeg, mpegversion=(int)1", // MPEG1,
407 "video/mpeg, mpegversion=(int)2", // MPEG2,
408 "video/mpeg, mpegversion=(int)4", // MPEG4,
409 "video/x-h264", // H264,
410 "video/x-h265", // H265,
411 "video/x-vp8", // VP8,
412 "video/x-vp9", // VP9,
413 "video/x-av1", // AV1,
414 "video/x-theora", // Theora,
415 "audio/x-wmv", // WMV
416 "video/x-jpeg", // MotionJPEG,
417 };
418 return QGstCaps(gst_caps_from_string(capsForCodec[(int)codec]), QGstCaps::HasRef);
419}
420
constexpr const_pointer data() const noexcept
@ HasRef
Definition qgst_p.h:163
int size() const
Definition qgst_p.h:200
QGstStructure at(int index) const
Definition qgst_p.h:201
QByteArrayView name() const
Definition qgst_p.h:142
QByteArray toString() const
Definition qgst_p.h:150
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:
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
bool isEmpty() const noexcept
Definition qlist.h:390
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
void append(parameter_type t)
Definition qlist.h:441
\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
Definition qset.h:18
EGLint EGLint * formats
Combined button and popup list for selecting options.
std::pair< T1, T2 > QPair
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:160
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:44