6#include <QtMultimedia/private/qwindowsaudioutils_p.h>
7#include <QtMultimedia/private/qwmf_support_p.h>
9#include <QtCore/qdebug.h>
10#include <QtCore/qglobal.h>
15#include <system_error>
19MFAudioDecoderControl::MFAudioDecoderControl(QAudioDecoder *parent)
20 : QPlatformAudioDecoder(parent)
21 , m_sourceResolver(makeComObject<SourceResolver>())
23 connect(m_sourceResolver.Get(), &SourceResolver::mediaSourceReady,
this, &MFAudioDecoderControl::handleMediaSourceReady);
24 connect(m_sourceResolver.Get(), &SourceResolver::error,
this, &MFAudioDecoderControl::handleMediaSourceError);
29 m_sourceResolver->shutdown();
34 if (!m_device && m_source == fileName)
37 m_sourceResolver->cancel();
38 m_sourceResolver->shutdown();
43 if (!m_source.isEmpty()) {
44 m_sourceResolver->load(m_source, 0);
45 m_loadingSource =
true;
51 if (m_device == device && m_source.isEmpty())
54 m_sourceResolver->cancel();
55 m_sourceResolver->shutdown();
61 if (m_device->isOpen() && m_device->isReadable()) {
62 m_sourceResolver->load(QUrl(), m_device);
63 m_loadingSource =
true;
70 m_loadingSource =
false;
71 if (m_deferredStart) {
72 m_deferredStart =
false;
73 startReadingSource(m_sourceResolver->mediaSource());
79 m_loadingSource =
false;
80 m_deferredStart =
false;
81 if (hr == MF_E_UNSUPPORTED_BYTESTREAM_TYPE) {
82 error(QAudioDecoder::FormatError, tr(
"Unsupported media type"));
83 }
else if (hr == ERROR_FILE_NOT_FOUND) {
84 error(QAudioDecoder::ResourceError, tr(
"Media not found"));
86 error(QAudioDecoder::ResourceError, tr(
"Unable to load specified URL")
87 + QString::fromStdString(std::system_category().message(hr)));
94 using namespace QWindowsAudioUtils;
95 using namespace std::chrono;
97 m_decoderSourceReader = std::make_unique<MFDecoderSourceReader>();
98 if (!m_decoderSourceReader) {
99 error(QAudioDecoder::ResourceError, tr(
"Could not instantiate MFDecoderSourceReader"));
103 auto mediaType = m_decoderSourceReader->setSource(source, m_outputFormat.sampleFormat());
104 QAudioFormat mediaFormat = QWindowsAudioUtils::mediaTypeToFormat(mediaType.Get());
105 if (!mediaFormat.isValid()) {
106 error(QAudioDecoder::FormatError, tr(
"Invalid media format"));
107 m_decoderSourceReader.reset();
111 ComPtr<IMFPresentationDescriptor> pd;
112 if (SUCCEEDED(source->CreatePresentationDescriptor(pd.GetAddressOf()))) {
113 UINT64 durationHns = 0;
114 pd->GetUINT64(MF_PD_DURATION, &durationHns);
115 durationChanged(round<milliseconds>(QWMF::reference_time{
static_cast<
long long>(durationHns) }));
118 if (!m_resampler.setup(mediaFormat, m_outputFormat.isValid() ? m_outputFormat : mediaFormat)) {
119 qWarning() <<
"Failed to set up resampler";
124 connect(m_decoderSourceReader.get(), &MFDecoderSourceReader::newSample,
this, &MFAudioDecoderControl::handleNewSample);
128 m_decoderSourceReader->readNextSample();
136 if (m_loadingSource) {
137 m_deferredStart =
true;
139 ComPtr<IMFMediaSource> source = m_sourceResolver->mediaSource();
142 error(QAudioDecoder::ResourceError, tr(
"Unable to read from specified device"));
143 else if (m_source.isValid())
144 error(QAudioDecoder::ResourceError, tr(
"Unable to load specified URL"));
146 error(QAudioDecoder::ResourceError, tr(
"No media source specified"));
149 startReadingSource(source);
156 m_deferredStart =
false;
160 disconnect(m_decoderSourceReader.get());
161 m_decoderSourceReader->clearSource();
162 m_decoderSourceReader.reset();
166 m_audioBuffer.swap(buffer);
167 bufferAvailableChanged(
false);
169 setIsDecoding(
false);
178 qint64 sampleStartTimeUs = m_resampler.outputFormat().durationForBytes(m_resampler.totalOutputBytes());
179 QByteArray out = m_resampler.resample(sample);
182 error(QAudioDecoder::Error::ResourceError, tr(
"Failed processing a sample"));
185 m_audioBuffer = QAudioBuffer(out, m_resampler.outputFormat(), sampleStartTimeUs);
187 bufferAvailableChanged(
true);
199 if (m_outputFormat == format)
201 m_outputFormat = format;
202 formatChanged(m_outputFormat);
210 buffer.swap(m_audioBuffer);
212 positionChanged(
std::chrono::duration_cast<
std::chrono::milliseconds>(
std::chrono::microseconds{ buffer.startTime() }));
213 bufferAvailableChanged(
false);
214 m_decoderSourceReader->readNextSample();
222#include "moc_mfaudiodecodercontrol_p.cpp"
void setAudioFormat(const QAudioFormat &format) override
bool bufferAvailable() const override
void setSourceDevice(QIODevice *device) override
QAudioBuffer read() override
void setSource(const QUrl &fileName) override
~MFAudioDecoderControl() override