diff options
author | Piotr Srebrny <piotr.srebrny@qt.io> | 2022-04-29 14:56:22 +0200 |
---|---|---|
committer | Piotr Srebrny <piotr.srebrny@qt.io> | 2022-05-12 12:53:39 +0200 |
commit | b525dcbcbbe005d39599e07422e078e8dedc087e (patch) | |
tree | 8a85515fc2dedb60318924865350cce8a2d4df2c | |
parent | 2aeddf0c93274a1bce97e6186ce9465863bb87a8 (diff) |
Add support for audio channel configuration on Windows
This patch add conversion of QAudioFormat channels into WMF formats
WAVEFORMATEXTENSIBLE and IMFMediaType, which enables proper channel
mapping for QAudioSink on the Windows platform.
Change-Id: I8f7038a34cda0f53c1ed9c6e9530de04b81e4056
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
-rw-r--r-- | src/multimedia/windows/qwindowsaudioutils.cpp | 68 |
1 files changed, 67 insertions, 1 deletions
diff --git a/src/multimedia/windows/qwindowsaudioutils.cpp b/src/multimedia/windows/qwindowsaudioutils.cpp index 41c27a28f..df470b29d 100644 --- a/src/multimedia/windows/qwindowsaudioutils.cpp +++ b/src/multimedia/windows/qwindowsaudioutils.cpp @@ -38,9 +38,61 @@ ****************************************************************************/ #include "qwindowsaudioutils_p.h" +#include "qdebug.h" +#include "ks.h" +#include "ksmedia.h" QT_BEGIN_NAMESPACE +static QAudioFormat::AudioChannelPosition channelFormatMap[] = + { QAudioFormat::FrontLeft // SPEAKER_FRONT_LEFT (0x1) + , QAudioFormat::FrontRight // SPEAKER_FRONT_RIGHT (0x2) + , QAudioFormat::FrontCenter // SPEAKER_FRONT_CENTER (0x4) + , QAudioFormat::LFE // SPEAKER_LOW_FREQUENCY (0x8) + , QAudioFormat::BackLeft // SPEAKER_BACK_LEFT (0x10) + , QAudioFormat::BackRight // SPEAKER_BACK_RIGHT (0x20) + , QAudioFormat::FrontLeftOfCenter // SPEAKER_FRONT_LEFT_OF_CENTER (0x40) + , QAudioFormat::FrontRightOfCenter// SPEAKER_FRONT_RIGHT_OF_CENTER (0x80) + , QAudioFormat::BackCenter // SPEAKER_BACK_CENTER (0x100) + , QAudioFormat::SideLeft // SPEAKER_SIDE_LEFT (0x200) + , QAudioFormat::SideRight // SPEAKER_SIDE_RIGHT (0x400) + , QAudioFormat::TopCenter // SPEAKER_TOP_CENTER (0x800) + , QAudioFormat::TopFrontLeft // SPEAKER_TOP_FRONT_LEFT (0x1000) + , QAudioFormat::TopFrontCenter // SPEAKER_TOP_FRONT_CENTER (0x2000) + , QAudioFormat::TopFrontRight // SPEAKER_TOP_FRONT_RIGHT (0x4000) + , QAudioFormat::TopBackLeft // SPEAKER_TOP_BACK_LEFT (0x8000) + , QAudioFormat::TopBackCenter // SPEAKER_TOP_BACK_CENTER (0x10000) + , QAudioFormat::TopBackRight // SPEAKER_TOP_BACK_RIGHT (0x20000) + }; + +static QAudioFormat::ChannelConfig maskToChannelConfig(UINT32 mask, int count) +{ + quint32 config = 0; + int set = 0; + for (auto c : channelFormatMap) { + if (mask & 1) { + config |= QAudioFormat::channelConfig(c); + ++set; + } + if (set >= count) + break; + mask >>= 1; + } + return QAudioFormat::ChannelConfig(config); +} + +static UINT32 channelConfigToMask(QAudioFormat::ChannelConfig config) +{ + UINT32 mask = 0; + quint32 i = 0; + for (auto c : channelFormatMap) { + if (config & QAudioFormat::channelConfig(c)) + mask |= 1 << i; + ++i; + } + return mask; +} + bool QWindowsAudioUtils::formatToWaveFormatExtensible(const QAudioFormat &format, WAVEFORMATEXTENSIBLE &wfx) { if (!format.isValid()) @@ -64,7 +116,8 @@ bool QWindowsAudioUtils::formatToWaveFormatExtensible(const QAudioFormat &format if (format.channelCount() > 2) { wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; wfx.Format.cbSize = 22; - wfx.dwChannelMask = 0xFFFFFFFF >> (32 - format.channelCount()); + wfx.dwChannelMask = format.channelConfig() == QAudioFormat::ChannelConfigUnknown ? KSAUDIO_SPEAKER_DIRECTOUT + : DWORD(format.channelConfig()); } return true; @@ -87,6 +140,8 @@ QAudioFormat QWindowsAudioUtils::waveFormatExToFormat(const WAVEFORMATEX &in) auto wfe = reinterpret_cast<const WAVEFORMATEXTENSIBLE &>(in); if (wfe.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) out.setSampleFormat(QAudioFormat::Float); + if (qPopulationCount(wfe.dwChannelMask) >= in.nChannels) + out.setChannelConfig(maskToChannelConfig(wfe.dwChannelMask, in.nChannels)); } } else if (in.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) { out.setSampleFormat(QAudioFormat::Float); @@ -104,7 +159,16 @@ QAudioFormat QWindowsAudioUtils::mediaTypeToFormat(IMFMediaType *mediaType) UINT32 val = 0; if (SUCCEEDED(mediaType->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &val))) { format.setChannelCount(int(val)); + } else { + qWarning() << "Could not determine channel count from IMFMediaType"; + return {}; } + + if (SUCCEEDED(mediaType->GetUINT32(MF_MT_AUDIO_CHANNEL_MASK, &val))) { + if (int(qPopulationCount(val)) >= format.channelCount()) + format.setChannelConfig(maskToChannelConfig(val, format.channelCount())); + } + if (SUCCEEDED(mediaType->GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, &val))) { format.setSampleRate(int(val)); } @@ -143,6 +207,8 @@ QWindowsIUPointer<IMFMediaType> QWindowsAudioUtils::formatToMediaType(const QAud } mediaType->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, UINT32(format.channelCount())); + if (format.channelConfig() != QAudioFormat::ChannelConfigUnknown) + mediaType->SetUINT32(MF_MT_AUDIO_CHANNEL_MASK, channelConfigToMask(format.channelConfig())); mediaType->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, UINT32(format.sampleRate())); auto alignmentBlock = UINT32(format.bytesPerFrame()); mediaType->SetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, alignmentBlock); |