Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qffmpegaudiodecoder.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 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
5#include "qaudiobuffer.h"
6
9
10#include <qloggingcategory.h>
11
12static Q_LOGGING_CATEGORY(qLcAudioDecoder, "qt.multimedia.ffmpeg.audioDecoder")
13
15
16namespace QFFmpeg
17{
18
19class SteppingAudioRenderer : public Renderer
20{
22public:
23 SteppingAudioRenderer(const QAudioFormat &format) : Renderer({}), m_format(format) { }
24
25 RenderingResult renderInternal(Frame frame) override
26 {
27 if (!frame.isValid())
28 return {};
29
30 if (!m_resampler)
31 m_resampler = std::make_unique<Resampler>(frame.codec(), m_format);
32
33 emit newAudioBuffer(m_resampler->resample(frame.avFrame()));
34
35 return {};
36 }
37
39 void newAudioBuffer(QAudioBuffer);
40
41private:
42 QAudioFormat m_format;
43 std::unique_ptr<Resampler> m_resampler;
44};
45
46class AudioDecoder : public PlaybackEngine
47{
49public:
50 explicit AudioDecoder(const QAudioFormat &format) : m_format(format) { }
51
52 RendererPtr createRenderer(QPlatformMediaPlayer::TrackType trackType) override
53 {
54 if (trackType != QPlatformMediaPlayer::AudioStream)
55 return RendererPtr{ {}, {} };
56
57 auto result = createPlaybackEngineObject<SteppingAudioRenderer>(m_format);
58 m_audioRenderer = result.get();
59
60 connect(result.get(), &SteppingAudioRenderer::newAudioBuffer, this,
61 &AudioDecoder::newAudioBuffer);
62
63 return result;
64 }
65
66 void nextBuffer()
67 {
68 Q_ASSERT(m_audioRenderer);
69 Q_ASSERT(!m_audioRenderer->isStepForced());
70
71 m_audioRenderer->doForceStep();
72 // updateObjectsPausedState();
73 }
74
76 void newAudioBuffer(QAudioBuffer);
77
78private:
79 QPointer<Renderer> m_audioRenderer;
80 QAudioFormat m_format;
81};
82}
83
84
87{
88}
89
91
93{
94 return m_url;
95}
96
98{
99 stop();
100 m_sourceDevice = nullptr;
101
102 if (std::exchange(m_url, fileName) != fileName)
104}
105
107{
108 return m_sourceDevice;
109}
110
112{
113 stop();
114 m_url.clear();
115 if (std::exchange(m_sourceDevice, device) != device)
117}
118
120{
121 qCDebug(qLcAudioDecoder) << "start";
122 auto checkNoError = [this]() {
124 return true;
125
126 durationChanged(-1);
127 positionChanged(-1);
128
129 m_decoder.reset();
130
131 return false;
132 };
133
134 m_decoder = std::make_unique<AudioDecoder>(m_audioFormat);
135 connect(m_decoder.get(), &AudioDecoder::errorOccured, this, &QFFmpegAudioDecoder::errorSignal);
136 connect(m_decoder.get(), &AudioDecoder::endOfStream, this, &QFFmpegAudioDecoder::done);
137 connect(m_decoder.get(), &AudioDecoder::newAudioBuffer, this,
139
140 m_decoder->setMedia(m_url, m_sourceDevice);
141 if (!checkNoError())
142 return;
143
144 m_decoder->setState(QMediaPlayer::PausedState);
145 if (!checkNoError())
146 return;
147
148 m_decoder->nextBuffer();
149 if (!checkNoError())
150 return;
151
152 durationChanged(m_decoder->duration() / 1000);
153 setIsDecoding(true);
154}
155
157{
158 qCDebug(qLcAudioDecoder) << ">>>>> stop";
159 if (m_decoder) {
160 m_decoder.reset();
161 done();
162 }
163}
164
166{
167 return m_audioFormat;
168}
169
171{
172 if (std::exchange(m_audioFormat, format) != format)
173 formatChanged(m_audioFormat);
174}
175
177{
178 auto buffer = std::exchange(m_audioBuffer, QAudioBuffer{});
179 if (!buffer.isValid())
180 return buffer;
181 qCDebug(qLcAudioDecoder) << "reading buffer" << buffer.startTime();
183 if (m_decoder)
184 m_decoder->nextBuffer();
185 return buffer;
186}
187
189{
190 Q_ASSERT(b.isValid());
191 Q_ASSERT(!m_audioBuffer.isValid());
193
194 qCDebug(qLcAudioDecoder) << "new audio buffer" << b.startTime();
195 m_audioBuffer = b;
196 const qint64 pos = b.startTime();
197 positionChanged(pos/1000);
198 bufferAvailableChanged(b.isValid());
199 bufferReady();
200}
201
203{
204 qCDebug(qLcAudioDecoder) << ">>>>> DONE!";
205 finished();
206}
207
208void QFFmpegAudioDecoder::errorSignal(int err, const QString &errorString)
209{
210 // unfortunately the error enums for QAudioDecoder and QMediaPlayer aren't identical.
211 // Map them.
212 switch (QMediaPlayer::Error(err)) {
215 break;
218 break;
221 break;
223 // fall through, Network error doesn't exist in QAudioDecoder
226 break;
227 }
228}
229
231
232#include "moc_qffmpegaudiodecoder_p.cpp"
233
234#include "qffmpegaudiodecoder.moc"
IOBluetoothDevice * device
\inmodule QtMultimedia
bool isValid() const noexcept
Returns true if this is a valid buffer.
The QAudioDecoder class implements decoding audio.
The QAudioFormat class stores audio stream parameter information.
void setSource(const QUrl &fileName) override
void newAudioBuffer(const QAudioBuffer &b)
QIODevice * sourceDevice() const override
void errorSignal(int err, const QString &errorString)
QAudioFormat audioFormat() const override
void setAudioFormat(const QAudioFormat &format) override
virtual ~QFFmpegAudioDecoder()
QFFmpegAudioDecoder(QAudioDecoder *parent)
QAudioBuffer read() override
void setSourceDevice(QIODevice *device) override
QUrl source() const override
\inmodule QtCore \reentrant
Definition qiodevice.h:34
Error
\qmlproperty enumeration QtMultimedia::MediaPlayer::mediaStatus
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
void durationChanged(qint64 duration)
void positionChanged(qint64 position)
void bufferAvailableChanged(bool available)
QAudioDecoder::Error error() const
virtual bool bufferAvailable() const
void formatChanged(const QAudioFormat &format)
void setIsDecoding(bool running=true)
\inmodule QtCore
Definition qpointer.h:18
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
\inmodule QtCore
Definition qurl.h:94
void clear()
Resets the content of the QUrl.
Definition qurl.cpp:1901
Combined button and popup list for selecting options.
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
GLboolean GLboolean GLboolean b
GLenum GLuint buffer
GLint GLsizei GLsizei GLenum format
GLuint64EXT * result
[6]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_OBJECT
#define signals
#define emit
long long qint64
Definition qtypes.h:55
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
QFrame frame
[0]
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent