#pragma once #ifndef __cplusplus #error "This is a C++ header" #endif extern "C" { #include <libavutil/opt.h> #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libswresample/swresample.h> #include <libavcodec/avfft.h> #include <memory.h> } #include "Utils.hh" #include <QtGlobal> #include <QMap> #include <QVector> #include <QString> namespace Vivy { class AudioContext; // The memory representation of an audio file. It is created inplace and should // not be moved around. It should be used to get the properties of an audio // file and its streams. The user can use a stream from the file and get data // from it. class AudioContext final { VIVY_UNMOVABLE_OBJECT(AudioContext) public: // Hold all the data for a stream in an audio file. Should only be owned by // the AudioContext class. class Stream final { VIVY_UNMOVABLE_OBJECT(Stream) static inline Utils::DeleterFunctionType<double> dataDeleter = std::bind_front(Utils::freePtrIfNotNull<double>, av_free); static inline Utils::DeleterFunctionType<AVCodecContext> codecContexteleter = std::bind_front(Utils::freePPtrIfNotNull<AVCodecContext>, avcodec_free_context); static inline Utils::DeleterFunctionType<AVFrame> avFrameDeleter = std::bind_front(Utils::freePPtrIfNotNull<AVFrame>, av_frame_free); static inline Utils::DeleterFunctionType<SwrContext> swrContenxtDeleter = std::bind_front(Utils::freePPtrIfNotNull<SwrContext>, swr_free); // All the used types using AVCodecContextPtr = std::unique_ptr<AVCodecContext, decltype(codecContexteleter)>; using DataPtr = std::shared_ptr<double[]>; using AVFramePtr = std::unique_ptr<AVFrame, decltype(avFrameDeleter)>; using SwrContextPtr = std::unique_ptr<SwrContext, decltype(swrContenxtDeleter)>; public: Stream(AVCodec *, AVFormatContext *, AVStream *, int index); ~Stream() noexcept; // The non-owning view of the stream's data using DataWeakPtr = std::weak_ptr<double[]>; // Decode the stream void decodeData(); void cleanUpData() noexcept; bool isDecoded() const noexcept; int getDataSampleRate() const noexcept; size_t getDecodedDataSize() const noexcept; size_t getDecodedChunkSize() const noexcept; size_t getDecodedDecalage() const noexcept; double *getDecodedData() const noexcept; // Some getters int getChannels() const noexcept; int getSampleRate() const noexcept; QString getName() const noexcept; AVCodecID getCodecId() const noexcept; qint64 getBitRate() const noexcept; // Get the index from the audio context int getStreamIndex() const noexcept; QJsonObject getProperties() const noexcept; private: // Codec related informations AVCodecID codecId{ AV_CODEC_ID_NONE }; AVCodec *codec{ nullptr }; AVCodecParameters *codecParams{ nullptr }; AVCodecContextPtr codecContext{ nullptr }; // Stream is held by AudioContext AVStream *audioStream{ nullptr }; // Store the index of this stream int streamIndexInAudioContext; // Resampled frame data AVFormatContext *dataFormat; SwrContextPtr dataSwrContext{ swr_alloc(), swrContenxtDeleter }; AVFramePtr dataFrame{ av_frame_alloc(), avFrameDeleter }; double *dataPtr{ nullptr }; size_t dataSize{ 0 }; // Constants for the resampler static constexpr uint resamplerChunkSize = 512; static constexpr uint resamplerOverlap = 128; static constexpr uint resamplerDecalage = resamplerChunkSize - resamplerOverlap; static constexpr uint resamplerSampleRate = 44100; }; using StreamPtr = std::shared_ptr<Stream>; using StreamWeakPtr = std::weak_ptr<Stream>; public: AudioContext(const QString &path); StreamWeakPtr getStream(int) const noexcept; StreamWeakPtr getDefaultStream() const noexcept; QString getElementName() const noexcept; QJsonDocument getProperties() const noexcept; private: // Regarding the format static inline Utils::DeleterFunctionType<AVFormatContext> avFormatContextDeleter = std::bind_front(Utils::freePtrIfNotNull<AVFormatContext>, avformat_free_context); using AVFormatContextPtr = std::unique_ptr<AVFormatContext, decltype(avFormatContextDeleter)>; AVFormatContextPtr format{ avformat_alloc_context(), avFormatContextDeleter }; const QString filePath; // Usefull information QMap<uint, StreamPtr> audioStreams{}; // THe audio streams of the file int defaultStreamIndex{ -1 }; // Spare always null shared pointer, to be used when the audioStream[i] was // not found. StreamPtr spareNullSreamPtr{ nullptr }; }; }