summaryrefslogtreecommitdiffstats
path: root/src/multimedia/platform/gstreamer
diff options
context:
space:
mode:
Diffstat (limited to 'src/multimedia/platform/gstreamer')
-rw-r--r--src/multimedia/platform/gstreamer/common/common.pri2
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstcodecsinfo.cpp273
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstcodecsinfo_p.h96
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstutils_p.h4
-rw-r--r--src/multimedia/platform/gstreamer/mediacapture/qgstreamercapturesession.cpp40
-rw-r--r--src/multimedia/platform/gstreamer/mediacapture/qgstreamerrecordercontrol.cpp9
-rw-r--r--src/multimedia/platform/gstreamer/qgstreamerformatsinfo.cpp367
-rw-r--r--src/multimedia/platform/gstreamer/qgstreamerformatsinfo_p.h31
8 files changed, 297 insertions, 525 deletions
diff --git a/src/multimedia/platform/gstreamer/common/common.pri b/src/multimedia/platform/gstreamer/common/common.pri
index b57cf4d00..54167b557 100644
--- a/src/multimedia/platform/gstreamer/common/common.pri
+++ b/src/multimedia/platform/gstreamer/common/common.pri
@@ -7,7 +7,6 @@ HEADERS += \
$$PWD/qgstreamerbufferprobe_p.h \
$$PWD/qgstreamervideorendererinterface_p.h \
$$PWD/qgstreamervideorenderer_p.h \
- $$PWD/qgstcodecsinfo_p.h \
$$PWD/qgstreamervideowindow_p.h \
$$PWD/qgstreamervideooverlay_p.h \
$$PWD/qgstreamerplayersession_p.h \
@@ -24,7 +23,6 @@ SOURCES += \
$$PWD/qgstreamerbufferprobe.cpp \
$$PWD/qgstreamervideorendererinterface.cpp \
$$PWD/qgstreamervideorenderer.cpp \
- $$PWD/qgstcodecsinfo.cpp \
$$PWD/qgstreamervideowindow.cpp \
$$PWD/qgstreamervideooverlay.cpp \
$$PWD/qgstreamerplayersession.cpp \
diff --git a/src/multimedia/platform/gstreamer/common/qgstcodecsinfo.cpp b/src/multimedia/platform/gstreamer/common/qgstcodecsinfo.cpp
deleted file mode 100644
index 06e034198..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstcodecsinfo.cpp
+++ /dev/null
@@ -1,273 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qgstcodecsinfo_p.h"
-#include "qgstutils_p.h"
-#include <QtCore/qset.h>
-
-#include <gst/pbutils/pbutils.h>
-
-static QSet<QString> streamTypes(GstElementFactory *factory, GstPadDirection direction)
-{
- QSet<QString> types;
- const GList *pads = gst_element_factory_get_static_pad_templates(factory);
- for (const GList *pad = pads; pad; pad = g_list_next(pad)) {
- GstStaticPadTemplate *templ = reinterpret_cast<GstStaticPadTemplate *>(pad->data);
- if (templ->direction == direction) {
- GstCaps *caps = gst_static_caps_get(&templ->static_caps);
- for (uint i = 0; i < gst_caps_get_size(caps); ++i) {
- GstStructure *structure = gst_caps_get_structure(caps, i);
- types.insert(QString::fromUtf8(gst_structure_get_name(structure)));
- }
- gst_caps_unref(caps);
- }
- }
-
- return types;
-}
-
-QGstCodecsInfo::QGstCodecsInfo(QGstCodecsInfo::ElementType elementType)
-{
- updateCodecs(elementType);
- for (auto &codec : supportedCodecs()) {
- GstElementFactory *factory = gst_element_factory_find(codecElement(codec).constData());
- if (factory) {
- GstPadDirection direction = elementType == Muxer ? GST_PAD_SINK : GST_PAD_SRC;
- m_streamTypes.insert(codec, streamTypes(factory, direction));
- gst_object_unref(GST_OBJECT(factory));
- }
- }
-}
-
-QStringList QGstCodecsInfo::supportedCodecs() const
-{
- return m_codecs;
-}
-
-QString QGstCodecsInfo::codecDescription(const QString &codec) const
-{
- return m_codecInfo.value(codec).description;
-}
-
-QByteArray QGstCodecsInfo::codecElement(const QString &codec) const
-
-{
- return m_codecInfo.value(codec).elementName;
-}
-
-QStringList QGstCodecsInfo::codecOptions(const QString &codec) const
-{
- QStringList options;
-
- QByteArray elementName = m_codecInfo.value(codec).elementName;
- if (elementName.isEmpty())
- return options;
-
- GstElement *element = gst_element_factory_make(elementName, nullptr);
- if (element) {
- guint numProperties;
- GParamSpec **properties = g_object_class_list_properties(G_OBJECT_GET_CLASS(element),
- &numProperties);
- for (guint j = 0; j < numProperties; ++j) {
- GParamSpec *property = properties[j];
- // ignore some properties
- if (strcmp(property->name, "name") == 0 || strcmp(property->name, "parent") == 0)
- continue;
-
- options.append(QLatin1String(property->name));
- }
- g_free(properties);
- gst_object_unref(element);
- }
-
- return options;
-}
-
-void QGstCodecsInfo::updateCodecs(ElementType elementType)
-{
- m_codecs.clear();
- m_codecInfo.clear();
-
- GstPadDirection padDirection = GST_PAD_SRC;
- if (elementType == Demuxer || elementType == AudioDecoder || elementType == VideoDecoder)
- padDirection = GST_PAD_SINK;
-
- GList *elements = elementFactories(elementType);
-
- QSet<QByteArray> fakeEncoderMimeTypes;
- fakeEncoderMimeTypes << "unknown/unknown"
- << "audio/x-raw-int" << "audio/x-raw-float"
- << "video/x-raw-yuv" << "video/x-raw-rgb";
-
- QSet<QByteArray> fieldsToAdd;
- fieldsToAdd << "mpegversion" << "layer" << "layout"
- << "variant";
-
- GList *element = elements;
- while (element) {
- GstElementFactory *factory = (GstElementFactory *)element->data;
- element = element->next;
-
- const GList *padTemplates = gst_element_factory_get_static_pad_templates(factory);
- while (padTemplates) {
- GstStaticPadTemplate *padTemplate = (GstStaticPadTemplate *)padTemplates->data;
- padTemplates = padTemplates->next;
-
- if (padTemplate->direction == padDirection) {
- GstCaps *caps = gst_static_caps_get(&padTemplate->static_caps);
- for (uint i=0; i<gst_caps_get_size(caps); i++) {
- const GstStructure *structure = gst_caps_get_structure(caps, i);
-
- //skip "fake" encoders
- if (fakeEncoderMimeTypes.contains(gst_structure_get_name(structure)))
- continue;
-
- GstStructure *newStructure = qt_gst_structure_new_empty(gst_structure_get_name(structure));
-
- //add structure fields to distinguish between formats with similar mime types,
- //like audio/mpeg
- for (int j=0; j<gst_structure_n_fields(structure); j++) {
- const gchar* fieldName = gst_structure_nth_field_name(structure, j);
- if (fieldsToAdd.contains(fieldName)) {
- const GValue *value = gst_structure_get_value(structure, fieldName);
- GType valueType = G_VALUE_TYPE(value);
-
- //don't add values of range type,
- //gst_pb_utils_get_codec_description complains about not fixed caps
-
- if (valueType != GST_TYPE_INT_RANGE && valueType != GST_TYPE_DOUBLE_RANGE &&
- valueType != GST_TYPE_FRACTION_RANGE && valueType != GST_TYPE_LIST &&
- valueType != GST_TYPE_ARRAY)
- gst_structure_set_value(newStructure, fieldName, value);
- }
- }
-
- GstCaps *newCaps = gst_caps_new_full(newStructure, nullptr);
-
- gchar *capsString = gst_caps_to_string(newCaps);
- QString codec = QLatin1String(capsString);
- if (capsString)
- g_free(capsString);
- // skip stuff that's not really a known audio/video codec
- if (codec.startsWith("application"))
- continue;
- GstRank rank = GstRank(gst_plugin_feature_get_rank(GST_PLUGIN_FEATURE(factory)));
-
- // If two elements provide the same codec, use the highest ranked one
- QMap<QString, CodecInfo>::const_iterator it = m_codecInfo.constFind(codec);
- if (it == m_codecInfo.constEnd() || it->rank < rank) {
- if (it == m_codecInfo.constEnd())
- m_codecs.append(codec);
-
- CodecInfo info;
- info.elementName = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory));
-
- gchar *description = gst_pb_utils_get_codec_description(newCaps);
- info.description = QString::fromUtf8(description);
- if (description)
- g_free(description);
-
- info.rank = rank;
-
- m_codecInfo.insert(codec, info);
- }
-
- gst_caps_unref(newCaps);
- }
- gst_caps_unref(caps);
- }
- }
- }
-
- gst_plugin_feature_list_free(elements);
-}
-
-GList *QGstCodecsInfo::elementFactories(ElementType elementType) const
-{
- GstElementFactoryListType gstElementType = 0;
- switch (elementType) {
- case AudioEncoder:
- gstElementType = GST_ELEMENT_FACTORY_TYPE_AUDIO_ENCODER;
- break;
- case VideoEncoder:
- // GST_ELEMENT_FACTORY_TYPE_VIDEO_ENCODER also lists image encoders. We don't want these here.
- gstElementType = (GstElementFactoryListType)(GST_ELEMENT_FACTORY_TYPE_ENCODER | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO);
- break;
- case Muxer:
- gstElementType = GST_ELEMENT_FACTORY_TYPE_MUXER;
- break;
- case AudioDecoder:
- gstElementType = (GstElementFactoryListType)(GST_ELEMENT_FACTORY_TYPE_DECODER | GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO);
- break;
- case VideoDecoder:
- gstElementType = (GstElementFactoryListType)(GST_ELEMENT_FACTORY_TYPE_DECODER | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO);
- break;
- case Demuxer:
- gstElementType = GST_ELEMENT_FACTORY_TYPE_DEMUXER;
- break;
- }
-
- GList *list = gst_element_factory_list_get_elements(gstElementType, GST_RANK_MARGINAL);
- if (elementType == AudioEncoder) {
- // Manually add "audioconvert" to the list
- // to allow linking with various containers.
- auto factory = gst_element_factory_find("audioconvert");
- if (factory)
- list = g_list_prepend(list, factory);
- }
-
- return list;
-}
-
-QSet<QString> QGstCodecsInfo::supportedStreamTypes(const QString &codec) const
-{
- return m_streamTypes.value(codec);
-}
-
-QStringList QGstCodecsInfo::supportedCodecs(const QSet<QString> &types) const
-{
- QStringList result;
- for (auto &candidate : supportedCodecs()) {
- auto candidateTypes = supportedStreamTypes(candidate);
- if (candidateTypes.intersects(types))
- result << candidate;
- }
-
- return result;
-}
diff --git a/src/multimedia/platform/gstreamer/common/qgstcodecsinfo_p.h b/src/multimedia/platform/gstreamer/common/qgstcodecsinfo_p.h
deleted file mode 100644
index fb2fb71d9..000000000
--- a/src/multimedia/platform/gstreamer/common/qgstcodecsinfo_p.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QGSTCODECSINFO_H
-#define QGSTCODECSINFO_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qtmultimediaglobal_p.h>
-#include <QtCore/qmap.h>
-#include <QtCore/qstringlist.h>
-#include <QSet>
-
-#include <gst/gst.h>
-
-QT_BEGIN_NAMESPACE
-
-class Q_MULTIMEDIA_EXPORT QGstCodecsInfo
-{
-public:
- enum ElementType { AudioEncoder, VideoEncoder, Muxer, AudioDecoder, VideoDecoder, Demuxer };
-
- struct CodecInfo {
- QString description;
- QByteArray elementName;
- GstRank rank;
- };
-
- QGstCodecsInfo(ElementType elementType);
-
- QStringList supportedCodecs() const;
- QString codecDescription(const QString &codec) const;
- QByteArray codecElement(const QString &codec) const;
- QStringList codecOptions(const QString &codec) const;
- QSet<QString> supportedStreamTypes(const QString &codec) const;
- QStringList supportedCodecs(const QSet<QString> &types) const;
-
-private:
- void updateCodecs(ElementType elementType);
- GList *elementFactories(ElementType elementType) const;
-
- QStringList m_codecs;
- QMap<QString, CodecInfo> m_codecInfo;
- QMap<QString, QSet<QString>> m_streamTypes;
-};
-
-Q_DECLARE_TYPEINFO(QGstCodecsInfo::CodecInfo, Q_RELOCATABLE_TYPE);
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/multimedia/platform/gstreamer/common/qgstutils_p.h b/src/multimedia/platform/gstreamer/common/qgstutils_p.h
index 7b6b6ded1..5cf5035ea 100644
--- a/src/multimedia/platform/gstreamer/common/qgstutils_p.h
+++ b/src/multimedia/platform/gstreamer/common/qgstutils_p.h
@@ -195,6 +195,10 @@ class QGstCaps {
public:
QGstCaps(const GstCaps *c) : caps(c) {}
const GstCaps *caps;
+ void unref() {
+ gst_caps_unref(const_cast<GstCaps *>(caps));
+ caps = nullptr;
+ }
bool isNull() const { return !caps; }
diff --git a/src/multimedia/platform/gstreamer/mediacapture/qgstreamercapturesession.cpp b/src/multimedia/platform/gstreamer/mediacapture/qgstreamercapturesession.cpp
index 193ccaa34..131e18e80 100644
--- a/src/multimedia/platform/gstreamer/mediacapture/qgstreamercapturesession.cpp
+++ b/src/multimedia/platform/gstreamer/mediacapture/qgstreamercapturesession.cpp
@@ -129,25 +129,17 @@ GstElement *QGstreamerCaptureSession::buildFileSink()
static GstEncodingContainerProfile *createContainerProfile(const QMediaEncoderSettings &settings)
{
- GstCaps *caps = nullptr;
-
auto *formatInfo = QGstreamerIntegration::instance()->m_formatsInfo;
- if (!formatInfo->encodableMediaContainers().contains(settings.format()))
- return nullptr;
-
- const char *format = formatInfo->nativeFormat(settings.format());
- Q_ASSERT(format);
-
- caps = gst_caps_from_string(format);
+ QGstCaps caps = formatInfo->formatCaps(settings.format());
GstEncodingContainerProfile *profile = (GstEncodingContainerProfile *)gst_encoding_container_profile_new(
"container_profile",
(gchar *)"custom container profile",
- caps,
+ const_cast<GstCaps *>(caps.caps),
NULL); //preset
- gst_caps_unref(caps);
+ caps.unref();
return profile;
}
@@ -156,23 +148,17 @@ static GstEncodingProfile *createVideoProfile(const QMediaEncoderSettings &setti
{
auto *formatInfo = QGstreamerIntegration::instance()->m_formatsInfo;
- if (!formatInfo->encodableVideoCodecs().contains(settings.videoCodec()))
- return nullptr;
-
- const char *codec = formatInfo->nativeFormat(settings.videoCodec());
- Q_ASSERT(codec);
- GstCaps *caps = gst_caps_from_string(codec);
-
- if (!caps)
+ QGstCaps caps = formatInfo->videoCaps(settings);
+ if (caps.isNull())
return nullptr;
GstEncodingVideoProfile *profile = gst_encoding_video_profile_new(
- caps,
+ const_cast<GstCaps *>(caps.caps),
nullptr,
NULL, //restriction
0); //presence
- gst_caps_unref(caps);
+ caps.unref();
gst_encoding_video_profile_set_pass(profile, 0);
gst_encoding_video_profile_set_variableframerate(profile, TRUE);
@@ -184,21 +170,17 @@ static GstEncodingProfile *createAudioProfile(const QMediaEncoderSettings &setti
{
auto *formatInfo = QGstreamerIntegration::instance()->m_formatsInfo;
- if (!formatInfo->encodableAudioCodecs().contains(settings.audioCodec()))
+ QGstCaps caps = formatInfo->audioCaps(settings);
+ if (caps.isNull())
return nullptr;
- const char *codec = formatInfo->nativeFormat(settings.audioCodec());
- Q_ASSERT(codec);
-
- GstCaps *caps = gst_caps_from_string(codec);
-
GstEncodingProfile *profile = (GstEncodingProfile *)gst_encoding_audio_profile_new(
- caps,
+ const_cast<GstCaps *>(caps.caps),
nullptr, //preset
NULL, //restriction
0); //presence
- gst_caps_unref(caps);
+ caps.unref();
return profile;
}
diff --git a/src/multimedia/platform/gstreamer/mediacapture/qgstreamerrecordercontrol.cpp b/src/multimedia/platform/gstreamer/mediacapture/qgstreamerrecordercontrol.cpp
index 7c60ed4d1..fabf6cf20 100644
--- a/src/multimedia/platform/gstreamer/mediacapture/qgstreamerrecordercontrol.cpp
+++ b/src/multimedia/platform/gstreamer/mediacapture/qgstreamerrecordercontrol.cpp
@@ -42,6 +42,7 @@
#include <QtGui/qdesktopservices.h>
#include <QStandardPaths>
#include "qaudiodeviceinfo.h"
+#include <qmimetype.h>
QGstreamerRecorderControl::QGstreamerRecorderControl(QGstreamerCaptureSession *session)
: QMediaRecorderControl(session),
@@ -154,9 +155,9 @@ void QGstreamerRecorderControl::record()
m_state = QMediaRecorder::RecordingState;
if (m_outputLocation.isEmpty()) {
- QString container;// ### = m_session->mediaContainerControl()->containerExtension();
+ QString container = resolvedEncoderSettings().mimeType().preferredSuffix();
if (container.isEmpty())
- container = "raw";
+ container = QString::fromLatin1("raw");
m_session->setOutputLocation(QUrl(generateFileName(defaultDir(), container)));
}
@@ -232,12 +233,10 @@ void QGstreamerRecorderControl::setEncoderSettings(const QMediaEncoderSettings &
QMediaEncoderSettings QGstreamerRecorderControl::resolvedEncoderSettings() const
{
QMediaEncoderSettings f = m_settings;
- f.resolveFormat(m_session->captureMode() & QGstreamerCaptureSession::Video ?
- QMediaEncoderSettings::AudioAndVideo : QMediaEncoderSettings::AudioOnly);
+ f.resolveFormat();
return f;
}
-
bool QGstreamerRecorderControl::isMuted() const
{
return m_session->isMuted();
diff --git a/src/multimedia/platform/gstreamer/qgstreamerformatsinfo.cpp b/src/multimedia/platform/gstreamer/qgstreamerformatsinfo.cpp
index 1e5c41969..b0fd8e53e 100644
--- a/src/multimedia/platform/gstreamer/qgstreamerformatsinfo.cpp
+++ b/src/multimedia/platform/gstreamer/qgstreamerformatsinfo.cpp
@@ -40,135 +40,308 @@
#include "qgstreamerformatsinfo_p.h"
#include "private/qgstutils_p.h"
-#include "private/qgstcodecsinfo_p.h"
QT_BEGIN_NAMESPACE
-static struct {
- const char *name;
- QMediaFormat::FileFormat value;
-} videoFormatsMap[] = {
- { "video/x-ms-asf", QMediaFormat::FileFormat::ASF },
- { "video/x-msvideo", QMediaFormat::FileFormat::AVI },
- { "video/x-matroska", QMediaFormat::FileFormat::Matroska },
- { "video/mpeg", QMediaFormat::FileFormat::MPEG4 },
- { "video/quicktime", QMediaFormat::FileFormat::QuickTime },
- { "video/ogg", QMediaFormat::FileFormat::Ogg },
- { "video/webm", QMediaFormat::FileFormat::WebM },
- { nullptr, QMediaFormat::FileFormat::UnspecifiedFormat }
-};
-
-static struct {
- const char *name;
- QMediaFormat::FileFormat value;
-} audioFormatsMap[] = {
- { "audio/mpeg, mpegversion=(int)1, layer=(int)3", QMediaFormat::FileFormat::MP3 },
- { "audio/mpeg, mpegversion=(int)4", QMediaFormat::FileFormat::AAC },
- { "audio/x-flac", QMediaFormat::FileFormat::FLAC },
- { "audio/x-alac", QMediaFormat::FileFormat::ALAC },
- { nullptr, QMediaFormat::FileFormat::UnspecifiedFormat },
-};
-
-static struct {
- const char *name;
- QMediaFormat::VideoCodec value;
-} videoCodecMap[] = {
- { "video/mpeg, mpegversion=(int)1", QMediaFormat::VideoCodec::MPEG1 },
- { "video/mpeg, mpegversion=(int)2", QMediaFormat::VideoCodec::MPEG2 },
- { "video/mpeg, mpegversion=(int)4", QMediaFormat::VideoCodec::MPEG4 },
- { "video/x-h264", QMediaFormat::VideoCodec::H264 },
- { "video/x-h265", QMediaFormat::VideoCodec::H265 },
- { "video/x-vp8", QMediaFormat::VideoCodec::VP8 },
- { "video/x-vp9", QMediaFormat::VideoCodec::VP9 },
- { "video/x-av1", QMediaFormat::VideoCodec::AV1 },
- { "video/x-theora", QMediaFormat::VideoCodec::Theora },
- { "video/x-jpeg", QMediaFormat::VideoCodec::MotionJPEG },
- { nullptr, QMediaFormat::VideoCodec::Unspecified }
-};
-
-static struct {
- const char *name;
- QMediaFormat::AudioCodec value;
-} audioCodecMap[] = {
- { "audio/mpeg, mpegversion=(int)1, layer=(int)3", QMediaFormat::AudioCodec::MP3 },
- { "audio/mpeg, mpegversion=(int)4", QMediaFormat::AudioCodec::AAC },
- { "audio/x-ac3", QMediaFormat::AudioCodec::AC3 },
- { "audio/x-eac3", QMediaFormat::AudioCodec::EAC3 },
- { "audio/x-flac", QMediaFormat::AudioCodec::FLAC },
- { "audio/x-alac", QMediaFormat::AudioCodec::ALAC },
- { "audio/x-true-hd", QMediaFormat::AudioCodec::DolbyTrueHD },
- { "audio/x-vorbis", QMediaFormat::AudioCodec::Vorbis },
- { nullptr, QMediaFormat::AudioCodec::Unspecified },
-};
-
-template<typename Map, typename Hash>
-static auto getList(QGstCodecsInfo::ElementType type, Map *map, Hash &hash)
+static QMediaFormat::AudioCodec audioCodecForCaps(QGstStructure structure)
{
- using T = decltype(map->value);
- QList<T> list;
- QGstCodecsInfo info(type);
- auto codecs = info.supportedCodecs();
- for (const auto &c : codecs) {
- Map *m = map;
- while (m->name) {
- if (m->name == c.toLatin1()) {
- list.append(m->value);
- hash.insert(m->value, m->name);
- break;
- }
- ++m;
+ const char *name = structure.name();
+
+ if (!name || strncmp(name, "audio/", 6))
+ return QMediaFormat::AudioCodec::Unspecified;
+ name += 6;
+ if (!strcmp(name, "mpeg")) {
+ auto version = structure["mpegversion"].toInt();
+ if (version == 1) {
+ auto layer = structure["layer"].toInt();
+ if (layer == 3)
+ return QMediaFormat::AudioCodec::MP3;
}
+ if (version == 4)
+ return QMediaFormat::AudioCodec::AAC;
+ } else if (!strcmp(name, "x-ac3")) {
+ return QMediaFormat::AudioCodec::AC3;
+ } else if (!strcmp(name, "x-eac3")) {
+ return QMediaFormat::AudioCodec::EAC3;
+ } else if (!strcmp(name, "x-flac")) {
+ return QMediaFormat::AudioCodec::FLAC;
+ } else if (!strcmp(name, "x-alac")) {
+ return QMediaFormat::AudioCodec::ALAC;
+ } else if (!strcmp(name, "x-true-hd")) {
+ return QMediaFormat::AudioCodec::DolbyTrueHD;
+ } else if (!strcmp(name, "x-vorbis")) {
+ return QMediaFormat::AudioCodec::Vorbis;
+ } else if (!strcmp(name, "x-opus")) {
+ return QMediaFormat::AudioCodec::Opus;
+ } else if (!strcmp(name, "x-wav")) {
+ return QMediaFormat::AudioCodec::Wave;
}
- return list;
+ return QMediaFormat::AudioCodec::Unspecified;
}
-QGstreamerFormatsInfo::QGstreamerFormatsInfo()
+static QMediaFormat::VideoCodec videoCodecForCaps(QGstStructure structure)
+{
+ const char *name = structure.name();
+
+ if (!name || strncmp(name, "video/", 6))
+ return QMediaFormat::VideoCodec::Unspecified;
+ name += 6;
+
+ if (!strcmp(name, "mpeg")) {
+ auto version = structure["mpegversion"].toInt();
+ if (version == 1)
+ return QMediaFormat::VideoCodec::MPEG1;
+ else if (version == 2)
+ return QMediaFormat::VideoCodec::MPEG2;
+ else if (version == 4)
+ return QMediaFormat::VideoCodec::MPEG4;
+ } else if (!strcmp(name, "x-h264")) {
+ return QMediaFormat::VideoCodec::H264;
+ } else if (!strcmp(name, "x-h265")) {
+ return QMediaFormat::VideoCodec::H265;
+ } else if (!strcmp(name, "x-vp8")) {
+ return QMediaFormat::VideoCodec::VP8;
+ } else if (!strcmp(name, "x-vp9")) {
+ return QMediaFormat::VideoCodec::VP9;
+ } else if (!strcmp(name, "x-av1")) {
+ return QMediaFormat::VideoCodec::AV1;
+ } else if (!strcmp(name, "x-theora")) {
+ return QMediaFormat::VideoCodec::Theora;
+ } else if (!strcmp(name, "x-jpeg")) {
+ return QMediaFormat::VideoCodec::MotionJPEG;
+ }
+ return QMediaFormat::VideoCodec::Unspecified;
+}
+
+static QMediaFormat::FileFormat fileFormatForCaps(QGstStructure structure)
{
- m_decodableMediaContainers = getList(QGstCodecsInfo::Demuxer, videoFormatsMap, formatToCaps);
- m_decodableMediaContainers.append(getList(QGstCodecsInfo::AudioDecoder, audioFormatsMap, formatToCaps));
- m_decodableAudioCodecs = getList(QGstCodecsInfo::AudioDecoder, audioCodecMap, audioToCaps);
- m_decodableVideoCodecs = getList(QGstCodecsInfo::VideoDecoder, videoCodecMap, videoToCaps);
-
- m_encodableMediaContainers = getList(QGstCodecsInfo::Muxer, videoFormatsMap, formatToCaps);
- m_encodableMediaContainers.append(getList(QGstCodecsInfo::AudioEncoder, audioFormatsMap, formatToCaps));
- m_encodableAudioCodecs = getList(QGstCodecsInfo::AudioEncoder, audioCodecMap, audioToCaps);
- m_encodableVideoCodecs = getList(QGstCodecsInfo::VideoEncoder, videoCodecMap, videoToCaps);
+ const char *name = structure.name();
+
+ if (!strcmp(name, "video/x-ms-asf")) {
+ return QMediaFormat::FileFormat::ASF;
+ } else if (!strcmp(name, "video/x-msvideo")) {
+ return QMediaFormat::FileFormat::AVI;
+ } else if (!strcmp(name, "video/x-matroska")) {
+ return QMediaFormat::FileFormat::Matroska;
+ } else if (!strcmp(name, "video/quicktime")) {
+ auto variant = structure["variant"].toString();
+ if (!variant)
+ return QMediaFormat::FileFormat::QuickTime;
+ else if (!strcmp(variant, "iso"))
+ return QMediaFormat::FileFormat::MPEG4;
+ } else if (!strcmp(name, "video/ogg")) {
+ return QMediaFormat::FileFormat::Ogg;
+ } else if (!strcmp(name, "video/webm")) {
+ return QMediaFormat::FileFormat::WebM;
+ }
+ return QMediaFormat::UnspecifiedFormat;
}
-QGstreamerFormatsInfo::~QGstreamerFormatsInfo()
+static QPair<QList<QMediaFormat::AudioCodec>, QList<QMediaFormat::VideoCodec>> getCodecsList(bool decode)
{
+ QList<QMediaFormat::AudioCodec> audio;
+ QList<QMediaFormat::VideoCodec> video;
+ GstPadDirection padDirection = decode ? GST_PAD_SINK : GST_PAD_SRC;
+
+ GList *elementList = gst_element_factory_list_get_elements(decode ? GST_ELEMENT_FACTORY_TYPE_DECODER : GST_ELEMENT_FACTORY_TYPE_ENCODER,
+ GST_RANK_MARGINAL);
+
+ GList *element = elementList;
+ while (element) {
+ GstElementFactory *factory = (GstElementFactory *)element->data;
+ element = element->next;
+
+ const GList *padTemplates = gst_element_factory_get_static_pad_templates(factory);
+ while (padTemplates) {
+ GstStaticPadTemplate *padTemplate = (GstStaticPadTemplate *)padTemplates->data;
+ padTemplates = padTemplates->next;
+
+ if (padTemplate->direction == padDirection) {
+ QGstCaps caps = gst_static_caps_get(&padTemplate->static_caps);
+
+ for (int i = 0; i < caps.size(); i++) {
+ QGstStructure structure = caps.at(i);
+ auto a = audioCodecForCaps(structure);
+ if (a != QMediaFormat::AudioCodec::Unspecified)
+ audio.append(a);
+ auto v = videoCodecForCaps(structure);
+ if (v != QMediaFormat::VideoCodec::Unspecified)
+ video.append(v);
+ }
+ caps.unref();
+ }
+ }
+ }
+ gst_plugin_feature_list_free(elementList);
+ return {audio, video};
}
-QList<QMediaFormat::FileFormat> QGstreamerFormatsInfo::decodableMediaContainers() const
+QList<QGstreamerFormatsInfo::CodecMap> QGstreamerFormatsInfo::getMuxerList(bool demuxer,
+ QList<QMediaFormat::AudioCodec> supportedAudioCodecs,
+ QList<QMediaFormat::VideoCodec> supportedVideoCodecs)
+{
+ QList<QGstreamerFormatsInfo::CodecMap> muxers;
+
+ GstPadDirection padDirection = demuxer ? GST_PAD_SINK : GST_PAD_SRC;
+
+ GList *elementList = gst_element_factory_list_get_elements(demuxer ? GST_ELEMENT_FACTORY_TYPE_DEMUXER : GST_ELEMENT_FACTORY_TYPE_MUXER,
+ GST_RANK_MARGINAL);
+ GList *element = elementList;
+ while (element) {
+ GstElementFactory *factory = (GstElementFactory *)element->data;
+ element = element->next;
+
+ QList<QMediaFormat::FileFormat> fileFormats;
+
+ const GList *padTemplates = gst_element_factory_get_static_pad_templates(factory);
+ while (padTemplates) {
+ GstStaticPadTemplate *padTemplate = (GstStaticPadTemplate *)padTemplates->data;
+ padTemplates = padTemplates->next;
+
+ if (padTemplate->direction == padDirection) {
+ QGstCaps caps = gst_static_caps_get(&padTemplate->static_caps);
+
+ for (int i = 0; i < caps.size(); i++) {
+ QGstStructure structure = caps.at(i);
+ auto fmt = fileFormatForCaps(structure);
+ if (fmt != QMediaFormat::UnspecifiedFormat)
+ fileFormats.append(fmt);
+ }
+ caps.unref();
+ }
+ }
+ if (fileFormats.isEmpty())
+ continue;
+
+ QList<QMediaFormat::AudioCodec> audioCodecs;
+ QList<QMediaFormat::VideoCodec> videoCodecs;
+
+ padTemplates = gst_element_factory_get_static_pad_templates(factory);
+ while (padTemplates) {
+ GstStaticPadTemplate *padTemplate = (GstStaticPadTemplate *)padTemplates->data;
+ padTemplates = padTemplates->next;
+
+ // check the other side for supported inputs/outputs
+ if (padTemplate->direction != padDirection) {
+ QGstCaps caps = gst_static_caps_get(&padTemplate->static_caps);
+
+ for (int i = 0; i < caps.size(); i++) {
+ QGstStructure structure = caps.at(i);
+ auto audio = audioCodecForCaps(structure);
+ if (audio != QMediaFormat::AudioCodec::Unspecified && supportedAudioCodecs.contains(audio))
+ audioCodecs.append(audio);
+ auto video = videoCodecForCaps(structure);
+ if (video != QMediaFormat::VideoCodec::Unspecified && supportedVideoCodecs.contains(video))
+ videoCodecs.append(video);
+ }
+ caps.unref();
+ }
+ }
+ if (!audioCodecs.isEmpty() || !videoCodecs.isEmpty()) {
+ for (auto f : qAsConst(fileFormats))
+ muxers.append({f, audioCodecs, videoCodecs});
+ }
+ }
+ gst_plugin_feature_list_free(elementList);
+ return muxers;
+}
+
+#if 0
+static void dumpMuxers(const QList<QGstreamerFormatsInfo::CodecMap> &muxerList)
{
- return m_decodableMediaContainers;
+ for (const auto &m : muxerList) {
+ qDebug() << " " << QMediaFormat::fileFormatName(m.format);
+ qDebug() << " Audio";
+ for (const auto &a : m.audio)
+ qDebug() << " " << QMediaFormat::audioCodecName(a);
+ qDebug() << " Video";
+ for (const auto &v : m.video)
+ qDebug() << " " << QMediaFormat::videoCodecName(v);
+ }
+
}
+#endif
-QList<QMediaFormat::AudioCodec> QGstreamerFormatsInfo::decodableAudioCodecs() const
+QGstreamerFormatsInfo::QGstreamerFormatsInfo()
{
- return m_decodableAudioCodecs;
+ auto codecs = getCodecsList(/*decode = */ true);
+ decoders = getMuxerList(true, codecs.first, codecs.second);
+
+ codecs = getCodecsList(/*decode = */ false);
+ encoders = getMuxerList(/* demuxer = */false, codecs.first, codecs.second);
+ //dumpMuxers(encoders);
}
-QList<QMediaFormat::VideoCodec> QGstreamerFormatsInfo::decodableVideoCodecs() const
+QGstreamerFormatsInfo::~QGstreamerFormatsInfo()
{
- return m_decodableVideoCodecs;
}
-QList<QMediaFormat::FileFormat> QGstreamerFormatsInfo::encodableMediaContainers() const
+QGstCaps QGstreamerFormatsInfo::formatCaps(const QMediaFormat &f) const
{
- return m_encodableMediaContainers;
+ auto format = f.format();
+ Q_ASSERT(format != QMediaFormat::UnspecifiedFormat);
+
+ const char *capsForFormat[QMediaFormat::LastFileFormat + 1] = {
+ "video/x-ms-asf", // ASF
+ "video/x-msvideo", // AVI
+ "video/x-matroska", // Matroska
+ "video/quicktime, variant=(string)iso", // MPEG4
+ "video/ogg", // Ogg
+ "video/quicktime", // QuickTime
+ "video/webm", // WebM
+ "audio/mpeg, mpegversion=(int)4", // AAC
+ "audio/x-flac", // FLAC
+ "audio/mpeg, mpegversion=(int)1, layer=(int)3", // MP3
+ "audio/mpeg, mpegversion=(int)4", // Mpeg4Audio
+ "audio/x-alac", // ALAC
+ "audio/x-wav" // Wave
+
+ };
+ return gst_caps_from_string(capsForFormat[format]);
}
-QList<QMediaFormat::AudioCodec> QGstreamerFormatsInfo::encodableAudioCodecs() const
+QGstCaps QGstreamerFormatsInfo::audioCaps(const QMediaFormat &f) const
{
- return m_encodableAudioCodecs;
+ auto codec = f.audioCodec();
+ if (codec == QMediaFormat::AudioCodec::Unspecified)
+ return nullptr;
+
+ const char *capsForCodec[(int)QMediaFormat::AudioCodec::LastAudioCodec + 1] = {
+ "audio/mpeg, mpegversion=(int)1, layer=(int)3", // MP3
+ "audio/mpeg, mpegversion=(int)4", // AAC
+ "audio/x-ac3", // AC3
+ "audio/x-eac3", // EAC3
+ "audio/x-flac", // FLAC
+ "audio/x-true-hd", // DolbyTrueHD
+ "audio/x-opus", // Opus
+ "audio/x-vorbis", // Vorbis
+ "audio/x-alac", // ALAC
+ "audio/x-wav", // WAVE
+ };
+ return gst_caps_from_string(capsForCodec[(int)codec]);
}
-QList<QMediaFormat::VideoCodec> QGstreamerFormatsInfo::encodableVideoCodecs() const
+QGstCaps QGstreamerFormatsInfo::videoCaps(const QMediaFormat &f) const
{
- return m_encodableVideoCodecs;
+ auto codec = f.videoCodec();
+ if (codec == QMediaFormat::VideoCodec::Unspecified)
+ return nullptr;
+
+ const char *capsForCodec[(int)QMediaFormat::VideoCodec::LastVideoCodec + 1] = {
+ "video/mpeg, mpegversion=(int)1", // MPEG1,
+ "video/mpeg, mpegversion=(int)2", // MPEG2,
+ "video/mpeg, mpegversion=(int)4", // MPEG4,
+ "video/x-h264", // H264,
+ "video/x-h265", // H265,
+ "video/x-vp8", // VP8,
+ "video/x-vp9", // VP9,
+ "video/x-av1", // AV1,
+ "video/x-theora", // Theora,
+ "video/x-jpeg", // MotionJPEG,
+ };
+ return gst_caps_from_string(capsForCodec[(int)codec]);
}
QT_END_NAMESPACE
diff --git a/src/multimedia/platform/gstreamer/qgstreamerformatsinfo_p.h b/src/multimedia/platform/gstreamer/qgstreamerformatsinfo_p.h
index e81319532..cb9d4d880 100644
--- a/src/multimedia/platform/gstreamer/qgstreamerformatsinfo_p.h
+++ b/src/multimedia/platform/gstreamer/qgstreamerformatsinfo_p.h
@@ -54,6 +54,7 @@
#include <private/qmediaplatformformatinfo_p.h>
#include <qhash.h>
#include <qlist.h>
+#include <private/qgstutils_p.h>
QT_BEGIN_NAMESPACE
@@ -63,30 +64,14 @@ public:
QGstreamerFormatsInfo();
~QGstreamerFormatsInfo();
- QList<QMediaFormat::FileFormat> decodableMediaContainers() const override;
- QList<QMediaFormat::AudioCodec> decodableAudioCodecs() const override;
- QList<QMediaFormat::VideoCodec> decodableVideoCodecs() const override;
+ QGstCaps formatCaps(const QMediaFormat &f) const;
+ QGstCaps audioCaps(const QMediaFormat &f) const;
+ QGstCaps videoCaps(const QMediaFormat &f) const;
+ // ###
+// QGstCaps audioEncoderCaps(const QMediaEncoderSettings &f) const;
+// QGstCaps videoEncoderCaps(const QMediaEncoderSettings &f) const;
- QList<QMediaFormat::FileFormat> encodableMediaContainers() const override;
- QList<QMediaFormat::AudioCodec> encodableAudioCodecs() const override;
- QList<QMediaFormat::VideoCodec> encodableVideoCodecs() const override;
-
- const char *nativeFormat(QMediaFormat::FileFormat f) const { return formatToCaps.value(f); }
- const char *nativeFormat(QMediaFormat::AudioCodec c) const { return audioToCaps.value(c); }
- const char *nativeFormat(QMediaFormat::VideoCodec c) const { return videoToCaps.value(c); }
-
-private:
- QList<QMediaFormat::FileFormat> m_decodableMediaContainers;
- QList<QMediaFormat::AudioCodec> m_decodableAudioCodecs;
- QList<QMediaFormat::VideoCodec> m_decodableVideoCodecs;
-
- QList<QMediaFormat::FileFormat> m_encodableMediaContainers;
- QList<QMediaFormat::AudioCodec> m_encodableAudioCodecs;
- QList<QMediaFormat::VideoCodec> m_encodableVideoCodecs;
-
- QHash<QMediaFormat::FileFormat, const char *> formatToCaps;
- QHash<QMediaFormat::AudioCodec, const char *> audioToCaps;
- QHash<QMediaFormat::VideoCodec, const char *> videoToCaps;
+ QList<CodecMap> getMuxerList(bool demuxer, QList<QMediaFormat::AudioCodec> audioCodecs, QList<QMediaFormat::VideoCodec> videoCodecs);
};
QT_END_NAMESPACE