summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndré de la Rocha <andre.rocha@qt.io>2021-12-19 04:37:24 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2022-01-04 16:38:54 +0000
commit8e27c18a185e15162e1aa390e3bb3340494173f2 (patch)
tree3eba0a8d29a5a1db7c7fbca2cd22e218e4ba6cc1
parent81210c8aa3053c505de584d0f6f49a7fac936744 (diff)
Windows: Get list of supported codecs from Media Foundation
This patch uses a table for container compatibility and queries Media Foundation for the actually supported audio and video codecs, instead of using hardcoded definitions for everything. Also, QImageWriter is queried for supported image formats, and the container selection for audio-only files has been fixed. It is now possible to encode audio as flac, alac, etc. Change-Id: Ie8fcbf6582ff1785ac0c77def8cebb0aef100adb Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Lars Knoll <lars.knoll@qt.io> Reviewed-by: Piotr Srebrny <piotr.srebrny@qt.io> (cherry picked from commit 9ea19cc787a049347f840a3e0560bd537b740dfa) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/multimedia/platform/windows/mediacapture/qwindowsmediadevicesession.cpp3
-rw-r--r--src/multimedia/platform/windows/qwindowsformatinfo.cpp170
-rw-r--r--src/multimedia/platform/windows/qwindowsformatinfo_p.h2
3 files changed, 147 insertions, 28 deletions
diff --git a/src/multimedia/platform/windows/mediacapture/qwindowsmediadevicesession.cpp b/src/multimedia/platform/windows/mediacapture/qwindowsmediadevicesession.cpp
index 5543fb6a2..5a96da72c 100644
--- a/src/multimedia/platform/windows/mediacapture/qwindowsmediadevicesession.cpp
+++ b/src/multimedia/platform/windows/mediacapture/qwindowsmediadevicesession.cpp
@@ -233,7 +233,8 @@ void QWindowsMediaDeviceSession::setAudioOutput(QAudioOutput *output)
QMediaRecorder::Error QWindowsMediaDeviceSession::startRecording(QMediaEncoderSettings &settings, const QString &fileName, bool audioOnly)
{
- GUID container = QWindowsMultimediaUtils::containerForVideoFileFormat(settings.mediaFormat().fileFormat());
+ GUID container = audioOnly ? QWindowsMultimediaUtils::containerForAudioFileFormat(settings.mediaFormat().fileFormat())
+ : QWindowsMultimediaUtils::containerForVideoFileFormat(settings.mediaFormat().fileFormat());
GUID videoFormat = QWindowsMultimediaUtils::videoFormatForCodec(settings.videoCodec());
GUID audioFormat = QWindowsMultimediaUtils::audioFormatForCodec(settings.audioCodec());
diff --git a/src/multimedia/platform/windows/qwindowsformatinfo.cpp b/src/multimedia/platform/windows/qwindowsformatinfo.cpp
index 85c362b29..13f87161e 100644
--- a/src/multimedia/platform/windows/qwindowsformatinfo.cpp
+++ b/src/multimedia/platform/windows/qwindowsformatinfo.cpp
@@ -39,17 +39,108 @@
#include "qwindowsformatinfo_p.h"
+#include <mfapi.h>
+#include <mftransform.h>
+#include <private/qwindowsiupointer_p.h>
+#include <private/qwindowsmultimediautils_p.h>
+
+#include <QtCore/qlist.h>
+#include <QtCore/qset.h>
+#include <QtGui/qimagewriter.h>
QT_BEGIN_NAMESPACE
+template<typename T>
+static T codecForFormat(GUID format) = delete;
+
+template<>
+QMediaFormat::AudioCodec codecForFormat(GUID format)
+{
+ return QWindowsMultimediaUtils::codecForAudioFormat(format);
+}
+
+template<>
+QMediaFormat::VideoCodec codecForFormat(GUID format)
+{
+ return QWindowsMultimediaUtils::codecForVideoFormat(format);
+}
+
+template<typename T>
+static QSet<T> getCodecSet(GUID category)
+{
+ QSet<T> codecSet;
+ IMFActivate **activateArray = nullptr;
+ UINT32 num = 0;
+
+ HRESULT hr = MFTEnumEx(category, MFT_ENUM_FLAG_ALL, nullptr, nullptr, &activateArray, &num);
+
+ if (SUCCEEDED(hr)) {
+ for (UINT32 i = 0; i < num; ++i) {
+ QWindowsIUPointer<IMFTransform> transform;
+ UINT32 typeIndex = 0;
+
+ hr = activateArray[i]->ActivateObject(IID_PPV_ARGS(transform.address()));
+
+ while (SUCCEEDED(hr)) {
+ QWindowsIUPointer<IMFMediaType> mediaType;
+
+ if (category == MFT_CATEGORY_AUDIO_ENCODER || category == MFT_CATEGORY_VIDEO_ENCODER)
+ hr = transform->GetOutputAvailableType(0, typeIndex++, mediaType.address());
+ else
+ hr = transform->GetInputAvailableType(0, typeIndex++, mediaType.address());
+
+ if (SUCCEEDED(hr)) {
+ GUID subtype = GUID_NULL;
+ hr = mediaType->GetGUID(MF_MT_SUBTYPE, &subtype);
+ if (SUCCEEDED(hr))
+ codecSet.insert(codecForFormat<T>(subtype));
+ }
+ }
+ }
+
+ for (UINT32 i = 0; i < num; ++i)
+ activateArray[i]->Release();
+
+ CoTaskMemFree(activateArray);
+ }
+
+ return codecSet;
+}
+
+static QList<QImageCapture::FileFormat> getImageFormatList()
+{
+ QList<QImageCapture::FileFormat> list;
+ auto formats = QImageWriter::supportedImageFormats();
+
+ for (const auto &f : formats) {
+ auto format = QString::fromUtf8(f);
+ if (format.compare(QLatin1String("jpg"), Qt::CaseInsensitive) == 0)
+ list.append(QImageCapture::FileFormat::JPEG);
+ else if (format.compare(QLatin1String("png"), Qt::CaseInsensitive) == 0)
+ list.append(QImageCapture::FileFormat::PNG);
+ else if (format.compare(QLatin1String("webp"), Qt::CaseInsensitive) == 0)
+ list.append(QImageCapture::FileFormat::WebP);
+ else if (format.compare(QLatin1String("tiff"), Qt::CaseInsensitive) == 0)
+ list.append(QImageCapture::FileFormat::Tiff);
+ }
+
+ return list;
+}
+
QWindowsFormatInfo::QWindowsFormatInfo()
{
- decoders = {
+ const QList<CodecMap> containerTable = {
{ QMediaFormat::MPEG4,
- { QMediaFormat::AudioCodec::AAC, QMediaFormat::AudioCodec::MP3, QMediaFormat::AudioCodec::ALAC, QMediaFormat::AudioCodec::AC3, QMediaFormat::AudioCodec::EAC3, },
+ { QMediaFormat::AudioCodec::AAC, QMediaFormat::AudioCodec::MP3, QMediaFormat::AudioCodec::ALAC, QMediaFormat::AudioCodec::AC3, QMediaFormat::AudioCodec::EAC3 },
{ QMediaFormat::VideoCodec::H264, QMediaFormat::VideoCodec::H265, QMediaFormat::VideoCodec::MotionJPEG } },
+ { QMediaFormat::Matroska,
+ { QMediaFormat::AudioCodec::AAC, QMediaFormat::AudioCodec::MP3, QMediaFormat::AudioCodec::ALAC, QMediaFormat::AudioCodec::AC3, QMediaFormat::AudioCodec::EAC3, QMediaFormat::AudioCodec::FLAC, QMediaFormat::AudioCodec::Vorbis, QMediaFormat::AudioCodec::Opus },
+ { QMediaFormat::VideoCodec::H264, QMediaFormat::VideoCodec::H265, QMediaFormat::VideoCodec::VP8, QMediaFormat::VideoCodec::VP9, QMediaFormat::VideoCodec::MotionJPEG } },
+ { QMediaFormat::WebM,
+ { QMediaFormat::AudioCodec::Vorbis, QMediaFormat::AudioCodec::Opus },
+ { QMediaFormat::VideoCodec::VP8, QMediaFormat::VideoCodec::VP9 } },
{ QMediaFormat::QuickTime,
- { QMediaFormat::AudioCodec::AAC, QMediaFormat::AudioCodec::MP3, QMediaFormat::AudioCodec::ALAC, QMediaFormat::AudioCodec::AC3, QMediaFormat::AudioCodec::EAC3, },
+ { QMediaFormat::AudioCodec::AAC, QMediaFormat::AudioCodec::MP3, QMediaFormat::AudioCodec::ALAC, QMediaFormat::AudioCodec::AC3, QMediaFormat::AudioCodec::EAC3 },
{ QMediaFormat::VideoCodec::H264, QMediaFormat::VideoCodec::H265, QMediaFormat::VideoCodec::MotionJPEG } },
{ QMediaFormat::AAC,
{ QMediaFormat::AudioCodec::AAC },
@@ -61,7 +152,7 @@ QWindowsFormatInfo::QWindowsFormatInfo()
{ QMediaFormat::AudioCodec::FLAC },
{} },
{ QMediaFormat::Mpeg4Audio,
- { QMediaFormat::AudioCodec::AAC },
+ { QMediaFormat::AudioCodec::AAC, QMediaFormat::AudioCodec::MP3, QMediaFormat::AudioCodec::ALAC, QMediaFormat::AudioCodec::AC3, QMediaFormat::AudioCodec::EAC3 },
{} },
{ QMediaFormat::WMA,
{ QMediaFormat::AudioCodec::WMA },
@@ -71,30 +162,59 @@ QWindowsFormatInfo::QWindowsFormatInfo()
{ QMediaFormat::VideoCodec::WMV } }
};
- encoders = {
- { QMediaFormat::MPEG4,
- { QMediaFormat::AudioCodec::AAC, QMediaFormat::AudioCodec::MP3 },
- { QMediaFormat::VideoCodec::H264 } },
- { QMediaFormat::AAC,
- { QMediaFormat::AudioCodec::AAC },
- {} },
- { QMediaFormat::MP3,
- { QMediaFormat::AudioCodec::MP3 },
- {} },
- { QMediaFormat::Mpeg4Audio,
- { QMediaFormat::AudioCodec::AAC },
- {} },
- { QMediaFormat::WMA,
- { QMediaFormat::AudioCodec::WMA },
- {} },
- { QMediaFormat::WMV,
- { QMediaFormat::AudioCodec::WMA },
- { QMediaFormat::VideoCodec::WMV } }
+ const QSet<QMediaFormat::FileFormat> decoderFormats = {
+ QMediaFormat::MPEG4,
+ QMediaFormat::Matroska,
+ QMediaFormat::WebM,
+ QMediaFormat::QuickTime,
+ QMediaFormat::AAC,
+ QMediaFormat::MP3,
+ QMediaFormat::FLAC,
+ QMediaFormat::Mpeg4Audio,
+ QMediaFormat::WMA,
+ QMediaFormat::WMV,
};
- // ####
- imageFormats = { QImageCapture::JPEG, QImageCapture::PNG };
+ const QSet<QMediaFormat::FileFormat> encoderFormats = {
+ QMediaFormat::MPEG4,
+ QMediaFormat::AAC,
+ QMediaFormat::MP3,
+ QMediaFormat::FLAC,
+ QMediaFormat::Mpeg4Audio,
+ QMediaFormat::WMA,
+ QMediaFormat::WMV,
+ };
+
+ const auto audioDecoders = getCodecSet<QMediaFormat::AudioCodec>(MFT_CATEGORY_AUDIO_DECODER);
+ const auto audioEncoders = getCodecSet<QMediaFormat::AudioCodec>(MFT_CATEGORY_AUDIO_ENCODER);
+ const auto videoDecoders = getCodecSet<QMediaFormat::VideoCodec>(MFT_CATEGORY_VIDEO_DECODER);
+ const auto videoEncoders = getCodecSet<QMediaFormat::VideoCodec>(MFT_CATEGORY_VIDEO_ENCODER);
+
+ for (const auto &codecMap : containerTable) {
+
+ const QSet<QMediaFormat::AudioCodec> mapAudioSet(codecMap.audio.cbegin(), codecMap.audio.cend());
+ const QSet<QMediaFormat::VideoCodec> mapVideoSet(codecMap.video.cbegin(), codecMap.video.cend());
+
+ if (decoderFormats.contains(codecMap.format)) {
+ CodecMap m;
+ m.format = codecMap.format;
+ m.audio = (audioDecoders & mapAudioSet).values();
+ m.video = (videoDecoders & mapVideoSet).values();
+ if (!m.video.empty() || !m.audio.empty())
+ decoders.append(m);
+ }
+
+ if (encoderFormats.contains(codecMap.format)) {
+ CodecMap m;
+ m.format = codecMap.format;
+ m.audio = (audioEncoders & mapAudioSet).values();
+ m.video = (videoEncoders & mapVideoSet).values();
+ if (!m.video.empty() || !m.audio.empty())
+ encoders.append(m);
+ }
+ }
+ imageFormats = getImageFormatList();
}
QWindowsFormatInfo::~QWindowsFormatInfo()
diff --git a/src/multimedia/platform/windows/qwindowsformatinfo_p.h b/src/multimedia/platform/windows/qwindowsformatinfo_p.h
index 355aea7d7..eeca80a6e 100644
--- a/src/multimedia/platform/windows/qwindowsformatinfo_p.h
+++ b/src/multimedia/platform/windows/qwindowsformatinfo_p.h
@@ -52,8 +52,6 @@
//
#include <private/qplatformmediaformatinfo_p.h>
-#include <qhash.h>
-#include <qlist.h>
QT_BEGIN_NAMESPACE