Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
mfaudiodecodercontrol.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <system_error>
5#include <mferror.h>
6#include <qglobal.h>
7#include "wmcodecdsp.h"
9#include <private/qwindowsaudioutils_p.h>
10
12
14 : QPlatformAudioDecoder(parent)
15 , m_sourceResolver(new SourceResolver)
16{
17 connect(m_sourceResolver, &SourceResolver::mediaSourceReady, this, &MFAudioDecoderControl::handleMediaSourceReady);
18 connect(m_sourceResolver, &SourceResolver::error, this, &MFAudioDecoderControl::handleMediaSourceError);
19}
20
22{
23 m_sourceResolver->shutdown();
24 m_sourceResolver->Release();
25}
26
28{
29 if (!m_device && m_source == fileName)
30 return;
31 stop();
32 m_sourceResolver->cancel();
33 m_sourceResolver->shutdown();
34 m_device = nullptr;
35 m_source = fileName;
37
38 if (!m_source.isEmpty()) {
39 m_sourceResolver->load(m_source, 0);
40 m_loadingSource = true;
41 }
42}
43
45{
46 if (m_device == device && m_source.isEmpty())
47 return;
48 stop();
49 m_sourceResolver->cancel();
50 m_sourceResolver->shutdown();
51 m_source.clear();
52 m_device = device;
54
55 if (m_device) {
56 if (m_device->isOpen() && m_device->isReadable()) {
57 m_sourceResolver->load(QUrl(), m_device);
58 m_loadingSource = true;
59 }
60 }
61}
62
63void MFAudioDecoderControl::handleMediaSourceReady()
64{
65 m_loadingSource = false;
66 if (m_deferredStart) {
67 m_deferredStart = false;
68 startReadingSource(m_sourceResolver->mediaSource());
69 }
70}
71
72void MFAudioDecoderControl::handleMediaSourceError(long hr)
73{
74 m_loadingSource = false;
75 m_deferredStart = false;
76 if (hr == MF_E_UNSUPPORTED_BYTESTREAM_TYPE) {
77 error(QAudioDecoder::FormatError, tr("Unsupported media type"));
78 } else if (hr == ERROR_FILE_NOT_FOUND) {
79 error(QAudioDecoder::ResourceError, tr("Media not found"));
80 } else {
81 error(QAudioDecoder::ResourceError, tr("Unable to load specified URL")
82 + QString::fromStdString(std::system_category().message(hr)));
83 }
84}
85
86void MFAudioDecoderControl::startReadingSource(IMFMediaSource *source)
87{
89
90 m_decoderSourceReader = makeComObject<MFDecoderSourceReader>();
91 if (!m_decoderSourceReader) {
92 error(QAudioDecoder::ResourceError, tr("Could not instantiate MFDecoderSourceReader"));
93 return;
94 }
95
96 auto mediaType = m_decoderSourceReader->setSource(source, m_outputFormat.sampleFormat());
97 QAudioFormat mediaFormat = QWindowsAudioUtils::mediaTypeToFormat(mediaType.Get());
98 if (!mediaFormat.isValid()) {
99 error(QAudioDecoder::FormatError, tr("Invalid media format"));
100 m_decoderSourceReader.Reset();
101 return;
102 }
103
104 ComPtr<IMFPresentationDescriptor> pd;
105 if (SUCCEEDED(source->CreatePresentationDescriptor(pd.GetAddressOf()))) {
106 UINT64 duration = 0;
107 pd->GetUINT64(MF_PD_DURATION, &duration);
108 duration /= 10000;
109 m_duration = qint64(duration);
110 durationChanged(m_duration);
111 }
112
113 if (!m_resampler.setup(mediaFormat, m_outputFormat.isValid() ? m_outputFormat : mediaFormat)) {
114 qWarning() << "Failed to set up resampler";
115 return;
116 }
117
118 connect(m_decoderSourceReader.Get(), &MFDecoderSourceReader::finished, this, &MFAudioDecoderControl::handleSourceFinished);
119 connect(m_decoderSourceReader.Get(), &MFDecoderSourceReader::newSample, this, &MFAudioDecoderControl::handleNewSample);
120
121 setIsDecoding(true);
122
123 m_decoderSourceReader->readNextSample();
124}
125
127{
128 if (isDecoding())
129 return;
130
131 if (m_loadingSource) {
132 m_deferredStart = true;
133 } else {
134 IMFMediaSource *source = m_sourceResolver->mediaSource();
135 if (!source) {
136 if (m_device)
137 error(QAudioDecoder::ResourceError, tr("Unable to read from specified device"));
138 else if (m_source.isValid())
139 error(QAudioDecoder::ResourceError, tr("Unable to load specified URL"));
140 else
141 error(QAudioDecoder::ResourceError, tr("No media source specified"));
142 return;
143 } else {
144 startReadingSource(source);
145 }
146 }
147}
148
150{
151 m_deferredStart = false;
152 if (!isDecoding())
153 return;
154
155 disconnect(m_decoderSourceReader.Get());
156 m_decoderSourceReader->clearSource();
157 m_decoderSourceReader.Reset();
158
159 if (bufferAvailable()) {
161 m_audioBuffer.swap(buffer);
163 }
164 setIsDecoding(false);
165
166 if (m_position != -1) {
167 m_position = -1;
168 positionChanged(m_position);
169 }
170 if (m_duration != -1) {
171 m_duration = -1;
172 durationChanged(m_duration);
173 }
174}
175
176void MFAudioDecoderControl::handleNewSample(ComPtr<IMFSample> sample)
177{
178 Q_ASSERT(sample);
179
180 qint64 sampleStartTimeUs = m_resampler.outputFormat().durationForBytes(m_resampler.totalOutputBytes());
181 QByteArray out = m_resampler.resample(sample.Get());
182
183 if (out.isEmpty()) {
184 error(QAudioDecoder::Error::ResourceError, tr("Failed processing a sample"));
185
186 } else {
187 m_audioBuffer = QAudioBuffer(out, m_resampler.outputFormat(), sampleStartTimeUs);
188
190 bufferReady();
191 }
192}
193
194void MFAudioDecoderControl::handleSourceFinished()
195{
196 stop();
197 finished();
198}
199
201{
202 if (m_outputFormat == format)
203 return;
204 m_outputFormat = format;
205 formatChanged(m_outputFormat);
206}
207
209{
211
212 if (bufferAvailable()) {
213 buffer.swap(m_audioBuffer);
214 m_position = buffer.startTime() / 1000;
215 positionChanged(m_position);
217 m_decoderSourceReader->readNextSample();
218 }
219
220 return buffer;
221}
222
224
225#include "moc_mfaudiodecodercontrol_p.cpp"
IOBluetoothDevice * device
qint64 duration() const override
void setAudioFormat(const QAudioFormat &format) override
bool bufferAvailable() const override
MFAudioDecoderControl(QAudioDecoder *parent)
void setSourceDevice(QIODevice *device) override
QAudioBuffer read() override
void setSource(const QUrl &fileName) override
void newSample(ComPtr< IMFSample >)
\inmodule QtMultimedia
void swap(QAudioBuffer &other) noexcept
Swaps the audio buffer with other.
The QAudioDecoder class implements decoding audio.
The QAudioFormat class stores audio stream parameter information.
constexpr SampleFormat sampleFormat() const noexcept
Returns the current sample format.
Q_MULTIMEDIA_EXPORT qint64 durationForBytes(qint32 byteCount) const
Returns the number of microseconds represented by bytes in this format.
constexpr bool isValid() const noexcept
Returns true if all of the parameters are valid.
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore \reentrant
Definition qiodevice.h:34
bool isOpen() const
Returns true if the device is open; otherwise returns false.
bool isReadable() const
Returns true if data can be read from the device; otherwise returns false.
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
void durationChanged(qint64 duration)
void positionChanged(qint64 position)
void bufferAvailableChanged(bool available)
QAudioDecoder::Error error() const
void formatChanged(const QAudioFormat &format)
void setIsDecoding(bool running=true)
static QString fromStdString(const std::string &s)
Definition qstring.h:1447
\inmodule QtCore
Definition qurl.h:94
bool isValid() const
Returns true if the URL is non-empty and valid; otherwise returns false.
Definition qurl.cpp:1882
bool isEmpty() const
Returns true if the URL has no data; otherwise returns false.
Definition qurl.cpp:1896
void clear()
Resets the content of the QUrl.
Definition qurl.cpp:1909
bool setup(const QAudioFormat &in, const QAudioFormat &out)
QByteArray resample(const QByteArrayView &in)
quint64 totalOutputBytes() const
QAudioFormat outputFormat() const
void mediaSourceReady()
IMFMediaSource * mediaSource() const
void error(long hr)
void load(const QUrl &url, QIODevice *stream)
Combined button and popup list for selecting options.
Q_MULTIMEDIA_EXPORT QAudioFormat mediaTypeToFormat(IMFMediaType *mediaType)
#define qWarning
Definition qlogging.h:166
GLenum GLuint buffer
GLuint GLsizei const GLchar * message
GLint GLsizei GLsizei GLenum format
GLsizei GLsizei GLchar * source
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define tr(X)
long long qint64
Definition qtypes.h:60
QTextStream out(stdout)
[7]
myObject disconnect()
[26]