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
qffmpegresampler.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 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
6#include <qloggingcategory.h>
7
8Q_STATIC_LOGGING_CATEGORY(qLcResampler, "qt.multimedia.ffmpeg.resampler")
9
11
12using namespace QFFmpeg;
13
14QFFmpegResampler::QFFmpegResampler(const QAudioFormat &inputFormat, const QAudioFormat &outputFormat) :
15 m_inputFormat(inputFormat), m_outputFormat(outputFormat)
16{
17 Q_ASSERT(inputFormat.isValid());
18 Q_ASSERT(outputFormat.isValid());
19
20 m_resampler =
21 createResampleContext(AVAudioFormat(m_inputFormat), AVAudioFormat(m_outputFormat));
22}
23
26 : m_outputFormat(outputFormat), m_startTime(startTime)
27{
29
30 qCDebug(qLcResampler) << "createResampler";
31 const AVStream *audioStream = codec->stream();
32
33 if (!m_outputFormat.isValid())
34 // want the native format
35 m_outputFormat = QFFmpegMediaFormatInfo::audioFormatFromCodecParameters(audioStream->codecpar);
36
37 m_resampler = createResampleContext(AVAudioFormat(audioStream->codecpar),
38 AVAudioFormat(m_outputFormat));
39}
40
42
44{
45 if (!m_inputFormat.isValid())
46 return {};
47
48 return resample(reinterpret_cast<const uint8_t **>(&data),
49 m_inputFormat.framesForBytes(static_cast<qint32>(size)));
50}
51
53{
54 return resample(const_cast<const uint8_t **>(frame->extended_data), frame->nb_samples);
55}
56
57QAudioBuffer QFFmpegResampler::resample(const uint8_t **inputData, int inputSamplesCount)
58{
59 const int maxOutSamples = adjustMaxOutSamples(inputSamplesCount);
60
61 QByteArray samples(m_outputFormat.bytesForFrames(maxOutSamples), Qt::Uninitialized);
62 auto *out = reinterpret_cast<uint8_t *>(samples.data());
63 const int outSamples =
64 swr_convert(m_resampler.get(), &out, maxOutSamples, inputData, inputSamplesCount);
65
66 samples.resize(m_outputFormat.bytesForFrames(outSamples));
67
68 const qint64 startTime = m_outputFormat.durationForFrames(m_samplesProcessed) + m_startTime;
69 m_samplesProcessed += outSamples;
70
71 qCDebug(qLcResampler) << " new frame" << startTime << "in_samples" << inputSamplesCount
72 << outSamples << maxOutSamples;
73 return QAudioBuffer(samples, m_outputFormat, startTime);
74}
75
76int QFFmpegResampler::adjustMaxOutSamples(int inputSamplesCount)
77{
78 int maxOutSamples = swr_get_out_samples(m_resampler.get(), inputSamplesCount);
79
80 const auto remainingCompensationDistance = m_endCompensationSample - m_samplesProcessed;
81
82 if (remainingCompensationDistance > 0 && maxOutSamples > remainingCompensationDistance) {
83 // If the remaining compensation distance less than output frame,
84 // the ffmpeg resampler bufferises the rest of frames that makes
85 // unexpected delays on large frames.
86 // The hack might cause some compensation bias on large frames,
87 // however it's not significant for our logic, in fact.
88 // TODO: probably, it will need some improvements
90 maxOutSamples = swr_get_out_samples(m_resampler.get(), inputSamplesCount);
91 }
92
93 return maxOutSamples;
94}
95
97{
98 const int res = swr_set_compensation(m_resampler.get(), delta, static_cast<int>(distance));
99 if (res < 0)
100 qCWarning(qLcResampler) << "swr_set_compensation fail:" << res;
101 else {
102 m_sampleCompensationDelta = delta;
103 m_endCompensationSample = m_samplesProcessed + distance;
104 }
105}
106
108{
109 return m_samplesProcessed < m_endCompensationSample ? m_sampleCompensationDelta : 0;
110}
111
\inmodule QtMultimedia
The QAudioFormat class stores audio stream parameter information.
Q_MULTIMEDIA_EXPORT qint32 bytesForFrames(qint32 frameCount) const
Returns the number of bytes required for frameCount frames of this format.
Q_MULTIMEDIA_EXPORT qint64 durationForFrames(qint32 frameCount) const
Return the number of microseconds represented by frameCount frames in this format.
constexpr bool isValid() const noexcept
Returns true if all of the parameters are valid.
Q_MULTIMEDIA_EXPORT qint32 framesForBytes(qint32 byteCount) const
Returns the number of frames represented by byteCount in this format.
\inmodule QtCore
Definition qbytearray.h:57
static QAudioFormat audioFormatFromCodecParameters(AVCodecParameters *codecPar)
QAudioBuffer resample(const char *data, size_t size) override
~QFFmpegResampler() override
void setSampleCompensation(qint32 delta, quint32 distance)
QFFmpegResampler(const QAudioFormat &inputFormat, const QAudioFormat &outputFormat)
qint32 activeSampleCompensationDelta() const
SwrContextUPtr createResampleContext(const AVAudioFormat &inputFormat, const AVAudioFormat &outputFormat)
Definition qffmpeg.cpp:557
Combined button and popup list for selecting options.
constexpr Initialization Uninitialized
qint64 startTime
QMediaFormat::AudioCodec codec
#define qCWarning(category,...)
#define qCDebug(category,...)
#define Q_STATIC_LOGGING_CATEGORY(name,...)
GLsizei samples
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLsizei GLsizei GLfloat distance
GLuint res
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
unsigned int quint32
Definition qtypes.h:50
int qint32
Definition qtypes.h:49
long long qint64
Definition qtypes.h:60
QTextStream out(stdout)
[7]
QFrame frame
[0]