Revision control

Copy as Markdown

// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFFMPEGAUDIORENDERER_P_H
#define QFFMPEGAUDIORENDERER_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtFFmpegMediaPluginImpl/private/qffmpegrenderer_p.h>
#include <QtMultimedia/qaudiobuffer.h>
QT_BEGIN_NAMESPACE
class QAudioOutput;
class QAudioBufferOutput;
class QAudioSink;
class QFFmpegResampler;
namespace QFFmpeg {
struct AbstractAudioFrameConverter;
class AudioRenderer : public Renderer
{
Q_OBJECT
public:
AudioRenderer(const PlaybackEngineObjectID &id, const TimeController &tc, QAudioOutput *output,
QAudioBufferOutput *bufferOutput, bool pitchCompensation);
void setOutput(QAudioOutput *output);
void setOutput(QAudioBufferOutput *bufferOutput);
void setPitchCompensation(bool enabled);
~AudioRenderer() override;
protected:
using Microseconds = std::chrono::microseconds;
struct SynchronizationStamp
{
QAudio::State audioSinkState = QAudio::IdleState;
qsizetype audioSinkBytesFree = 0;
qsizetype bufferBytesWritten = 0;
TimePoint timePoint = TimePoint::max();
};
struct BufferLoadingInfo
{
enum Type { Low, Moderate, High };
Type type = Moderate;
TimePoint timePoint = TimePoint::max();
Microseconds delay = Microseconds(0);
};
struct AudioTimings
{
Microseconds actualBufferDuration = Microseconds(0);
Microseconds maxSoundDelay = Microseconds(0);
Microseconds minSoundDelay = Microseconds(0);
};
struct BufferedDataWithOffset
{
QAudioBuffer buffer;
qsizetype offset = 0;
bool isValid() const { return buffer.isValid(); }
qsizetype size() const { return buffer.byteCount() - offset; }
const char *data() const { return buffer.constData<char>() + offset; }
};
void seekInternal() override;
RenderingResult renderInternal(Frame frame) override;
RenderingResult pushFrameToOutput(const Frame &frame);
void pushFrameToBufferOutput(const Frame &frame);
void onPlaybackRateChanged() override;
TimePoint nextTimePoint() const override;
void onPauseChanged() override;
void freeOutput();
void updateOutputs(const Frame &frame);
void initAudioFrameConverter(const Frame &frame);
void onDeviceChanged();
void updateVolume();
void updateSynchronization(const SynchronizationStamp &stamp, const Frame &frame);
Microseconds bufferLoadingTime(const SynchronizationStamp &syncStamp) const;
void onAudioSinkStateChanged(QAudio::State state);
Microseconds durationForBytes(qsizetype bytes) const;
private:
QPointer<QAudioOutput> m_output;
QPointer<QAudioBufferOutput> m_bufferOutput;
std::unique_ptr<QAudioSink> m_sink;
AudioTimings m_timings;
BufferLoadingInfo m_bufferLoadingInfo;
std::unique_ptr<QFFmpegResampler> m_bufferOutputResampler;
QAudioFormat m_sinkFormat;
QPointer<QIODevice> m_ioDevice;
bool m_deviceChanged = false;
bool m_bufferOutputChanged = false;
bool m_firstFrameToSink = true;
// pitch compensation
bool m_pitchCompensation = false;
std::unique_ptr<AbstractAudioFrameConverter> m_audioFrameConverter;
struct SessionContext
{
// TODO: add other members after clarifying the best session cleanup strategy
BufferedDataWithOffset bufferedData;
bool lastFramePushDone = true;
bool drained = false;
};
SessionContext m_sessionCtx;
};
} // namespace QFFmpeg
QT_END_NAMESPACE
#endif // QFFMPEGAUDIORENDERER_P_H