6#include <QtMultimedia/private/qaudiobuffer_support_p.h>
7#include <QtFFmpegMediaPluginImpl/private/qffmpegframe_p.h>
8#include <QtFFmpegMediaPluginImpl/private/qffmpegresampler_p.h>
9#include <QtFFmpegMediaPluginImpl/private/qffmpegmediaformatinfo_p.h>
11#if defined(Q_CC_MSVC) && defined(QT_MM_OPTIMIZE_DEBUG)
12# pragma optimize("s", on)
16#include <signalsmith-stretch.h>
24qreal sampleRateFactor()
41 static const qreal result = []() {
42 const auto sampleRateFactorStr =
43 qEnvironmentVariable(
"QT_MEDIA_PLAYER_AUDIO_SAMPLE_RATE_FACTOR");
45 const auto result = sampleRateFactorStr.toDouble(&ok);
46 return ok ? result : 1.;
54 explicit TrivialAudioFrameConverter(
const Frame &frame, QAudioFormat outputFormat,
57 int sampleRate = qRound(outputFormat.sampleRate() / playbackRate * sampleRateFactor());
58 outputFormat.setSampleRate(sampleRate);
59 m_converter = createResampler(frame, outputFormat);
62 QAudioBuffer convert(AVFrame *frame)
override {
return m_converter->resample(frame); }
65 std::unique_ptr<QFFmpegResampler> m_converter;
70 explicit PitchShiftingAudioFrameConverter(
const Frame &frame, QAudioFormat outputFormat,
72 : m_playbackRate{ playbackRate }
74 const QAudioFormat mediaFormat = QFFmpegMediaFormatInfo::audioFormatFromCodecParameters(
75 *frame.codecContext()->stream()->codecpar);
77 const QAudioFormat floatFormat = [&] {
78 QAudioFormat ret = mediaFormat;
79 ret.setSampleFormat(QAudioFormat::SampleFormat::Float);
83 m_toPCMDecoder = createResampler(frame, floatFormat);
85 m_pendingFractionalFrames = 0.f;
86 m_stretcher.presetDefault(mediaFormat.channelCount(), outputFormat.sampleRate());
88 const QAudioFormat pitchCompensatedFormat = [&] {
89 QAudioFormat ret = floatFormat;
90 ret.setSampleRate(outputFormat.sampleRate());
93 m_toOutputFormatConverter = QFFmpegResampler::createFromInputFormat(pitchCompensatedFormat, outputFormat,
94 frame.startTime().get());
97 QAudioBuffer convert(AVFrame *frame)
override
99 using namespace QtPrivate;
102 QAudioBuffer wordConverted = m_toPCMDecoder->resample(frame);
105 int mediaFrameCount = wordConverted.frameCount();
106 float expectedNumberOfFrames = mediaFrameCount / m_playbackRate + m_pendingFractionalFrames;
107 int numberOfFullExpectedFrames = qFloor(expectedNumberOfFrames);
108 m_pendingFractionalFrames = expectedNumberOfFrames - numberOfFullExpectedFrames;
110 auto timeStretcherOutput = QAudioBuffer{
111 numberOfFullExpectedFrames,
112 wordConverted.format(),
117 QAudioBufferDeinterleaveAdaptor<
const float>{
121 QAudioBufferDeinterleaveAdaptor<
float>{
124 numberOfFullExpectedFrames);
127 QAudioBuffer outputBuffer = m_toOutputFormatConverter->resample(
128 timeStretcherOutput.constData<
const char>(), timeStretcherOutput.byteCount());
134 std::unique_ptr<QFFmpegResampler> m_toPCMDecoder;
135 signalsmith::stretch::SignalsmithStretch<
float> m_stretcher;
136 std::unique_ptr<QFFmpegResampler> m_toOutputFormatConverter;
137 float m_playbackRate;
138 float m_pendingFractionalFrames = 0.f;
146 const QAudioFormat &outputFormat)
148 return QFFmpegResampler::createFromCodecContext(frame.codecContext(), outputFormat, frame.startTime().get());
154 return std::make_unique<TrivialAudioFrameConverter>(frame, outputFormat, playbackRate);
161 return std::make_unique<PitchShiftingAudioFrameConverter>(frame, outputFormat, playbackRate);
std::unique_ptr< QFFmpegResampler > createResampler(const Frame &frame, const QAudioFormat &outputFormat)
std::unique_ptr< AbstractAudioFrameConverter > makePitchShiftingAudioFrameConverter(const Frame &frame, QAudioFormat outputFormat, float playbackRate)
std::conditional_t< QT_FFMPEG_AVIO_WRITE_CONST, const uint8_t *, uint8_t * > AvioWriteBufferType
std::unique_ptr< AbstractAudioFrameConverter > makeTrivialAudioFrameConverter(const Frame &frame, QAudioFormat outputFormat, float playbackRate)
virtual ~AbstractAudioFrameConverter()