diff options
author | André de la Rocha <andre.rocha@qt.io> | 2021-12-19 04:37:24 +0100 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2022-01-04 16:38:54 +0000 |
commit | 8e27c18a185e15162e1aa390e3bb3340494173f2 (patch) | |
tree | 3eba0a8d29a5a1db7c7fbca2cd22e218e4ba6cc1 | |
parent | 81210c8aa3053c505de584d0f6f49a7fac936744 (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>
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 |