diff --git a/src/Lib/AbstractMediaContext.hh b/src/Lib/AbstractMediaContext.hh
new file mode 100644
index 0000000000000000000000000000000000000000..bc896bfcc193203a6f1732eb93116c34c1e1178a
--- /dev/null
+++ b/src/Lib/AbstractMediaContext.hh
@@ -0,0 +1,217 @@
+#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>
+#include <QJsonObject>
+#include <QJsonDocument>
+#include <QJsonArray>
+
+namespace Vivy
+{
+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);
+
+static inline Utils::DeleterFunctionType<AVFormatContext> avFormatContextDeleter =
+    std::bind_front(Utils::freePtrIfNotNull<AVFormatContext>, avformat_free_context);
+
+using AVFormatContextPtr = std::unique_ptr<AVFormatContext, decltype(avFormatContextDeleter)>;
+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)>;
+
+// Simple abstract class to be inherited by video streams and audio streams.
+template <size_t AVMEDIA_TYPE> class AbstractMediaStream {
+    VIVY_UNMOVABLE_OBJECT(AbstractMediaStream)
+
+public:
+    static inline constexpr AVMediaType avMediaType = static_cast<AVMediaType>(AVMEDIA_TYPE);
+
+protected:
+    AbstractMediaStream(AVCodec *streamCodec, AVFormatContext *formatArg, AVStream *streamArg,
+                        int index)
+        : codecId(streamArg->codecpar->codec_id)
+        , codec(streamCodec)
+        , codecParams(streamArg->codecpar)
+        , stream(streamArg)
+        , dataFormat(formatArg)
+        , streamIndexInContext(index)
+    {
+        if (codec == nullptr)
+            throw std::runtime_error("failed to find a decoder for stream");
+
+        codecContext.reset(avcodec_alloc_context3(codec));
+        if (!codecContext)
+            throw std::runtime_error("failed to allocate codec context");
+
+        if (avcodec_parameters_to_context(codecContext.get(), codecParams) < 0)
+            throw std::runtime_error("failed to copy parameters to codec context");
+
+        if (avcodec_open2(codecContext.get(), codec, nullptr) < 0)
+            throw std::runtime_error("failed to open audio decoder for a stream");
+
+        qDebug() << "[Stream] Codec" << codec->name << "id:" << codecId;
+        qDebug() << "[Stream] sample rate:" << codecParams->sample_rate;
+        qDebug() << "[Stream] bit rate:   " << codecParams->bit_rate;
+        qDebug() << "[Stream] channels:   " << codecParams->channels;
+    }
+
+public:
+    virtual ~AbstractMediaStream() noexcept = default;
+    int getStreamIndex() const noexcept { return streamIndexInContext; }
+    QString getName() const noexcept { return QString::fromUtf8(codec->name); }
+    AVCodecID getCodecId() const noexcept { return codecId; }
+
+    virtual QJsonObject getProperties() const noexcept
+    {
+        QJsonObject ret;
+        ret.insert("Codec name", codec->name);
+        return ret;
+    }
+
+protected:
+    // Codec related informations
+    AVCodecID codecId{ AV_CODEC_ID_NONE };
+    AVCodec *codec{ nullptr };
+    AVCodecParameters *codecParams{ nullptr };
+    AVCodecContextPtr codecContext{ nullptr };
+    AVFormatContext *dataFormat{ nullptr };
+
+    // Stream is held by AudioContext
+    AVStream *stream{ nullptr };
+
+    // Store the index of this stream
+    int streamIndexInContext;
+};
+
+template <typename Stream> class AbstractMediaContext {
+    VIVY_UNMOVABLE_OBJECT(AbstractMediaContext)
+
+public:
+    static inline constexpr AVMediaType avMediaType = Stream::avMediaType;
+    using StreamPtr                                 = std::shared_ptr<Stream>;
+    using StreamWeakPtr                             = std::weak_ptr<Stream>;
+
+public:
+    AbstractMediaContext(const QString &path)
+        : filePath(path)
+    {
+        if (!format)
+            throw std::runtime_error("out of memory, can't create allocate the AVFormatContext");
+
+        const std::string filePathStdHolder = filePath.toStdString();
+        const char *filename                = filePathStdHolder.c_str();
+        AVFormatContext *formatPtr          = format.get();
+
+        // Get the format from the file
+        if (avformat_open_input(&formatPtr, filename, nullptr, nullptr) != 0) {
+            [[maybe_unused]] void *relatedOnFailure =
+                format.release(); // freed by avformat_open_input
+            throw std::runtime_error("failed to open file");
+        }
+
+        if (avformat_find_stream_info(formatPtr, nullptr) < 0) {
+            throw std::runtime_error("failed to get audio stream info");
+        }
+
+        // Populate all the stream indexes
+        for (uint i = 0; i < format->nb_streams; ++i) {
+            AVStream *itFmt           = format->streams[i];
+            AVCodecParameters *params = itFmt->codecpar;
+            AVCodec *streamCodec      = avcodec_find_decoder(params->codec_id);
+            if (streamCodec && streamCodec->type == avMediaType)
+                audioStreams.insert(i, std::make_shared<Stream>(streamCodec, formatPtr, itFmt, i));
+        }
+
+        // Get the default stream
+        defaultStreamIndex = av_find_best_stream(formatPtr, avMediaType,
+                                                 -1, // Let AV find one stream
+                                                 -1, // We don't want related streams
+                                                 nullptr, 0);
+        if (defaultStreamIndex < 0)
+            qCritical() << "Could not find the best stream";
+
+        qDebug() << "Opened context for" << path << "with duration" << formatPtr->duration
+                 << "and default stream index" << defaultStreamIndex;
+    }
+
+    StreamWeakPtr getStream(int index) const noexcept
+    {
+        if (index < 0)
+            return StreamWeakPtr{ spareNullSreamPtr };
+
+        uint unsignedIndex = static_cast<uint>(index);
+        const auto found   = audioStreams.find(unsignedIndex);
+
+        if (found != audioStreams.end())
+            return StreamWeakPtr{ *found };
+
+        return StreamWeakPtr{ spareNullSreamPtr };
+    }
+
+    StreamWeakPtr getDefaultStream() const noexcept
+    {
+        return (defaultStreamIndex < 0) ? StreamWeakPtr{ spareNullSreamPtr }
+                                        : getStream(defaultStreamIndex);
+    }
+
+    virtual QString getElementName() const noexcept
+    {
+        return "Context: " + QFileInfo(filePath).baseName();
+    }
+
+    virtual QJsonDocument getProperties() const noexcept
+    {
+        QJsonDocument ret;
+        QJsonArray streams;
+
+        QFileInfo file(filePath);
+
+        for (const auto &audioStreamPtr : audioStreams) {
+            streams.append(audioStreamPtr->getProperties());
+        }
+
+        QJsonObject self{ { "Streams", streams }, { "Base name", file.baseName() } };
+
+        ret.setObject(self);
+        return ret;
+    }
+
+private:
+    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 };
+};
+}