Qt 6.x
The Qt SDK
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
8extern "C" {
9#include <libavutil/opt.h>
10}
11
12static Q_LOGGING_CATEGORY(qLcResampler, "qt.multimedia.ffmpeg.resampler")
13
15
16namespace QFFmpeg
17{
18
19Resampler::Resampler(const Codec *codec, const QAudioFormat &outputFormat)
20 : m_outputFormat(outputFormat)
21{
22 qCDebug(qLcResampler) << "createResampler";
23 const AVStream *audioStream = codec->stream();
24 const auto *codecpar = audioStream->codecpar;
25
26 if (!m_outputFormat.isValid())
27 // want the native format
28 m_outputFormat = QFFmpegMediaFormatInfo::audioFormatFromCodecParameters(audioStream->codecpar);
29
30 QAudioFormat::ChannelConfig config = m_outputFormat.channelConfig();
32 config = QAudioFormat::defaultChannelConfigForChannelCount(m_outputFormat.channelCount());
33
34
35 qCDebug(qLcResampler) << "init resampler" << m_outputFormat.sampleRate() << config << codecpar->sample_rate;
36#if QT_FFMPEG_OLD_CHANNEL_LAYOUT
37 auto inConfig = codecpar->channel_layout;
38 if (inConfig == 0)
40 resampler = swr_alloc_set_opts(nullptr, // we're allocating a new context
42 QFFmpegMediaFormatInfo::avSampleFormat(m_outputFormat.sampleFormat()), // out_sample_fmt
43 m_outputFormat.sampleRate(), // out_sample_rate
44 inConfig, // in_ch_layout
45 AVSampleFormat(codecpar->format), // in_sample_fmt
46 codecpar->sample_rate, // in_sample_rate
47 0, // log_offset
48 nullptr);
49#else
50 AVChannelLayout in_ch_layout = codecpar->ch_layout;
51 AVChannelLayout out_ch_layout = {};
52 av_channel_layout_from_mask(&out_ch_layout, QFFmpegMediaFormatInfo::avChannelLayout(config));
53 swr_alloc_set_opts2(&resampler, // we're allocating a new context
54 &out_ch_layout,
55 QFFmpegMediaFormatInfo::avSampleFormat(m_outputFormat.sampleFormat()),
56 m_outputFormat.sampleRate(),
57 &in_ch_layout,
58 AVSampleFormat(codecpar->format),
59 codecpar->sample_rate,
60 0,
61 nullptr);
62#endif
63 swr_init(resampler);
64}
65
66Resampler::~Resampler()
67{
68 swr_free(&resampler);
69}
70
71QAudioBuffer Resampler::resample(const AVFrame *frame)
72{
73 const int maxOutSamples = adjustMaxOutSamples(frame);
74
75 QByteArray samples(m_outputFormat.bytesForFrames(maxOutSamples), Qt::Uninitialized);
76 auto **in = const_cast<const uint8_t **>(frame->extended_data);
77 auto *out = reinterpret_cast<uint8_t *>(samples.data());
78 const int outSamples = swr_convert(resampler, &out, maxOutSamples, in, frame->nb_samples);
79
80 samples.resize(m_outputFormat.bytesForFrames(outSamples));
81
82 qint64 startTime = m_outputFormat.durationForFrames(m_samplesProcessed);
83 m_samplesProcessed += outSamples;
84
85 qCDebug(qLcResampler) << " new frame" << startTime << "in_samples" << frame->nb_samples
86 << outSamples << maxOutSamples;
87 return QAudioBuffer(samples, m_outputFormat, startTime);
88}
89
90int Resampler::adjustMaxOutSamples(const AVFrame *frame)
91{
92 int maxOutSamples = swr_get_out_samples(resampler, frame->nb_samples);
93
94 const auto remainingCompensationDistance = m_endCompensationSample - m_samplesProcessed;
95
96 if (remainingCompensationDistance > 0 && maxOutSamples > remainingCompensationDistance) {
97 // If the remaining compensation distance less than output frame,
98 // the ffmpeg resampler bufferises the rest of frames that makes
99 // unexpected delays on large frames.
100 // The hack might cause some compensation bias on large frames,
101 // however it's not significant for our logic, in fact.
102 // TODO: probably, it will need some improvements
103 setSampleCompensation(0, 0);
104 maxOutSamples = swr_get_out_samples(resampler, frame->nb_samples);
105 }
106
107 return maxOutSamples;
108}
109
110void Resampler::setSampleCompensation(qint32 delta, quint32 distance)
111{
112 const int res = swr_set_compensation(resampler, delta, static_cast<int>(distance));
113 if (res < 0)
114 qCWarning(qLcResampler) << "swr_set_compensation fail:" << res;
115 else {
116 m_sampleCompensationDelta = delta;
117 m_endCompensationSample = m_samplesProcessed + distance;
118 }
119}
120
121qint32 Resampler::activeSampleCompensationDelta() const
122{
123 return m_samplesProcessed < m_endCompensationSample ? m_sampleCompensationDelta : 0;
124}
125}
126
\inmodule QtMultimedia
The QAudioFormat class stores audio stream parameter information.
static Q_MULTIMEDIA_EXPORT ChannelConfig defaultChannelConfigForChannelCount(int channelCount)
Returns a default channel configuration for channelCount.
ChannelConfig
\variable QAudioFormat::NChannelPositions
\inmodule QtCore
Definition qbytearray.h:57
static QAudioFormat audioFormatFromCodecParameters(AVCodecParameters *codecPar)
static AVSampleFormat avSampleFormat(QAudioFormat::SampleFormat format)
static int64_t avChannelLayout(QAudioFormat::ChannelConfig channelConfig)
Combined button and popup list for selecting options.
constexpr Initialization Uninitialized
qint64 startTime
EGLConfig config
QMediaFormat::AudioCodec codec
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
GLsizei samples
GLsizei GLsizei GLfloat distance
GLuint res
GLuint in
unsigned int quint32
Definition qtypes.h:45
int qint32
Definition qtypes.h:44
long long qint64
Definition qtypes.h:55
QTextStream out(stdout)
[7]
QFrame frame
[0]