diff --git a/AVQt/AVQt b/AVQt/AVQt
index 7e31b527e2422a529bd1514167be7a47355ad16a..3acd66f277e2bb6201c41f916dc7d9ea09cce65c 100644
--- a/AVQt/AVQt
+++ b/AVQt/AVQt
@@ -14,4 +14,5 @@
 #include "output/IAudioSink.h"
 #include "output/OpenGLRenderer.h"
 #include "output/OpenALAudioOutput.h"
+#include "output/Muxer.h"
 //#include "output/FrameFileSaver.h"
\ No newline at end of file
diff --git a/AVQt/CMakeLists.txt b/AVQt/CMakeLists.txt
index 436bf3967c1ccb18c9ba68c3293332a5cb754bd2..716663c6713417984f3427e66b33abadee736293 100644
--- a/AVQt/CMakeLists.txt
+++ b/AVQt/CMakeLists.txt
@@ -74,6 +74,10 @@ set(SOURCES
         output/OpenALAudioOutput.h
         output/private/OpenALAudioOutput_p.h
         output/OpenALAudioOutput.cpp
+
+        output/Muxer.h
+        output/private/Muxer_p.h
+        output/Muxer.cpp
         )
 
 add_library(AVQt SHARED ${SOURCES})
diff --git a/AVQt/filter/DecoderDXVA2.cpp b/AVQt/filter/DecoderDXVA2.cpp
index 41c5c294f37b2a6558dab609c3b126fea351c6d1..6e2219d47cdda936ab156767ce646b4ddd35a3a4 100644
--- a/AVQt/filter/DecoderDXVA2.cpp
+++ b/AVQt/filter/DecoderDXVA2.cpp
@@ -287,7 +287,7 @@ namespace AVQt {
                                d->m_timebase.num,
                                d->m_timebase.den);
                         QTime time = QTime::currentTime();
-                        cb->onFrame(this, cbFrame, static_cast<int64_t>(av_q2d(av_inv_q(d->m_framerate)) * 1000.0));
+                        cb->onFrame(this, cbFrame, static_cast<int64_t>(av_q2d(av_inv_q(d->m_framerate)) * 1000.0), d->m_pDeviceCtx);
                         qDebug() << "Video CB time:" << time.msecsTo(QTime::currentTime());
                         av_frame_unref(cbFrame);
                         av_frame_free(&cbFrame);
diff --git a/AVQt/filter/DecoderMMAL.cpp b/AVQt/filter/DecoderMMAL.cpp
index 2ddf4d6df1a95f9e61e51386d57ae98897e5a936..7a84383b65c4e5e663fae26782e4d1981f026ee6 100644
--- a/AVQt/filter/DecoderMMAL.cpp
+++ b/AVQt/filter/DecoderMMAL.cpp
@@ -292,7 +292,7 @@ namespace AVQt {
                                d->m_timebase.num,
                                d->m_timebase.den);
                         QTime time = QTime::currentTime();
-                        cb->onFrame(this, cbFrame, static_cast<int64_t>(av_q2d(av_inv_q(d->m_framerate)) * 1000.0));
+                        cb->onFrame(this, cbFrame, static_cast<int64_t>(av_q2d(av_inv_q(d->m_framerate)) * 1000.0), nullptr);
                         qDebug() << "Video CB time:" << time.msecsTo(QTime::currentTime());
                         av_frame_unref(cbFrame);
                         av_frame_free(&cbFrame);
diff --git a/AVQt/filter/DecoderQSV.cpp b/AVQt/filter/DecoderQSV.cpp
index 464d43c5ed3d288e1e52208cddb857c708fc65bc..29de5b4b86dda9b0936a07ce1da5e61383badf0d 100644
--- a/AVQt/filter/DecoderQSV.cpp
+++ b/AVQt/filter/DecoderQSV.cpp
@@ -287,7 +287,8 @@ namespace AVQt {
                                d->m_timebase.num,
                                d->m_timebase.den);
                         QTime time = QTime::currentTime();
-                        cb->onFrame(this, cbFrame, static_cast<int64_t>(av_q2d(av_inv_q(d->m_framerate)) * 1000.0));
+                        cb->onFrame(this, cbFrame, static_cast<int64_t>(av_q2d(av_inv_q(d->m_framerate)) * 1000.0),
+                                    av_buffer_ref(d->m_pDeviceCtx));
                         qDebug() << "Video CB time:" << time.msecsTo(QTime::currentTime());
                         av_frame_unref(cbFrame);
                         av_frame_free(&cbFrame);
diff --git a/AVQt/filter/DecoderVAAPI.cpp b/AVQt/filter/DecoderVAAPI.cpp
index d61dcecebc86002e501cdd314dbc8c3e104ba7d5..919839e24bce4ed632ac049dd7f6f8da9c225832 100644
--- a/AVQt/filter/DecoderVAAPI.cpp
+++ b/AVQt/filter/DecoderVAAPI.cpp
@@ -220,12 +220,12 @@ namespace AVQt {
                 if (d->m_pCodecParams && !d->m_pCodecCtx) {
                     d->m_pCodec = avcodec_find_decoder(d->m_pCodecParams->codec_id);
                     if (!d->m_pCodec) {
-                        qFatal("No audio decoder found");
+                        qFatal("No video decoder found");
                     }
 
                     d->m_pCodecCtx = avcodec_alloc_context3(d->m_pCodec);
                     if (!d->m_pCodecCtx) {
-                        qFatal("Could not allocate audio decoder context, probably out of memory");
+                        qFatal("Could not allocate video decoder context, probably out of memory");
                     }
 
                     ret = av_hwdevice_ctx_create(&d->m_pDeviceCtx, AV_HWDEVICE_TYPE_VAAPI, "/dev/dri/renderD128", nullptr, 0);
@@ -267,13 +267,18 @@ namespace AVQt {
                         lock.relock();
                     }
                 }
-                AVFrame *frame = av_frame_alloc();
                 while (true) {
+                    AVFrame *frame = av_frame_alloc();
                     ret = avcodec_receive_frame(d->m_pCodecCtx, frame);
                     if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) {
                         break;
+                    } else if (ret == -12) { // -12 == Out of memory, didn't know the macro name
+                        av_frame_free(&frame);
+                        msleep(1);
+                        continue;
                     } else if (ret < 0) {
-                        qFatal("%d: Error receiving frame from VAAPI decoder: %s", ret, av_make_error_string(strBuf, strBufSize, ret));
+                        qFatal("%d: Error receiving frame %d from VAAPI decoder: %s", ret, d->m_pCodecCtx->frame_number,
+                               av_make_error_string(strBuf, strBufSize, ret));
                     }
 
 //                    auto t1 = NOW();
@@ -295,9 +300,9 @@ namespace AVQt {
                                d->m_timebase.num,
                                d->m_timebase.den);
                         QTime time = QTime::currentTime();
-                        cb->onFrame(this, cbFrame, static_cast<int64_t>(av_q2d(av_inv_q(d->m_framerate)) * 1000.0));
+                        cb->onFrame(this, cbFrame, static_cast<int64_t>(av_q2d(av_inv_q(d->m_framerate)) * 1000.0),
+                                    av_buffer_ref(d->m_pDeviceCtx));
                         qDebug() << "Video CB time:" << time.msecsTo(QTime::currentTime());
-                        av_frame_unref(cbFrame);
                         av_frame_free(&cbFrame);
 //                        }));
                     }
@@ -316,9 +321,9 @@ namespace AVQt {
 //                    qDebug("Decoder frame transfer time: %ld us", TIME_US(t1, t3));
 
 //                    av_frame_free(&swFrame);
-                    av_frame_unref(frame);
+                    av_frame_free(&frame);
                 }
-                av_frame_free(&frame);
+//                av_frame_free(&frame);
             } else {
                 msleep(4);
             }
diff --git a/AVQt/filter/EncoderVAAPI.cpp b/AVQt/filter/EncoderVAAPI.cpp
index e94235e68346c30b72239c85aa070701531039a6..f1f10f0fe99a8755e057c6d689c3b7f9a1543ac8 100644
--- a/AVQt/filter/EncoderVAAPI.cpp
+++ b/AVQt/filter/EncoderVAAPI.cpp
@@ -8,10 +8,11 @@
 #include "output/IPacketSink.h"
 
 namespace AVQt {
-    EncoderVAAPI::EncoderVAAPI(QString encoder, QObject *parent) : QThread(parent), d_ptr(new EncoderVAAPIPrivate(this)) {
+    EncoderVAAPI::EncoderVAAPI(CODEC codec, int bitrate, QObject *parent) : QThread(parent), d_ptr(new EncoderVAAPIPrivate(this)) {
         Q_D(AVQt::EncoderVAAPI);
 
-        d->m_encoder = std::move(encoder);
+        d->m_codec = codec;
+        d->m_bitrate = bitrate;
     }
 
     [[maybe_unused]] EncoderVAAPI::EncoderVAAPI(EncoderVAAPIPrivate &p) : d_ptr(&p) {
@@ -34,9 +35,34 @@ namespace AVQt {
 //        constexpr auto strBufSize = 64;
 //        char strBuf[strBufSize];
 
-        d->m_pCodec = avcodec_find_encoder_by_name(d->m_encoder.toLocal8Bit().constData());
+        std::string codec_name;
+        switch (d->m_codec) {
+            case CODEC::H264:
+                codec_name = "h264_vaapi";
+                break;
+            case CODEC::HEVC:
+                codec_name = "hevc_vaapi";
+                break;
+            case CODEC::VP9:
+                if (qEnvironmentVariable("LIBVA_DRIVER_NAME") == "iHD") {
+                    qFatal("[AVQt::EncoderVAAPI] Unsupported codec: VP9");
+                } else {
+                    codec_name = "vp9_vaapi";
+                }
+                break;
+            case CODEC::VP8:
+                codec_name = "vp8_vaapi";
+                break;
+            case CODEC::MPEG2:
+                codec_name = "mpeg2_vaapi";
+                break;
+            case CODEC::AV1:
+                qFatal("[AVQt::EncoderVAAPI] Unsupported codec: AV1");
+        }
+
+        d->m_pCodec = avcodec_find_encoder_by_name(codec_name.c_str());
         if (!d->m_pCodec) {
-            qFatal("Could not find encoder: %s", d->m_encoder.toLocal8Bit().constData());
+            qFatal("Could not find encoder: %s", codec_name.c_str());
         }
 
         return 0;
@@ -136,8 +162,8 @@ namespace AVQt {
     int EncoderVAAPI::init(IFrameSource *source, AVRational framerate, int64_t duration) {
         Q_UNUSED(source)
         Q_UNUSED(duration)
+        Q_UNUSED(framerate)
         Q_D(AVQt::EncoderVAAPI);
-        d->m_framerate = framerate;
         init();
         return 0;
     }
@@ -193,7 +219,7 @@ namespace AVQt {
         }
     }
 
-    void EncoderVAAPI::onFrame(IFrameSource *source, AVFrame *frame, int64_t frameDuration) {
+    void EncoderVAAPI::onFrame(IFrameSource *source, AVFrame *frame, int64_t frameDuration, AVBufferRef *pDeviceCtx) {
         Q_UNUSED(source)
         Q_D(AVQt::EncoderVAAPI);
 
@@ -212,7 +238,7 @@ namespace AVQt {
                 break;
         }
 
-        while (d->m_inputQueue.size() > 100) {
+        while (d->m_inputQueue.size() > 4) {
             QThread::msleep(1);
         }
         {
@@ -276,10 +302,10 @@ namespace AVQt {
 
                     d->m_pCodecCtx->hw_device_ctx = av_buffer_ref(d->m_pDeviceCtx);
                     d->m_pCodecCtx->hw_frames_ctx = av_buffer_ref(d->m_pFramesCtx);
-//                    d->m_pCodecCtx->bit_rate = 5000000;
-//                    d->m_pCodecCtx->rc_min_rate = 4500000;
-//                    d->m_pCodecCtx->rc_max_rate = 6000000;
-//                    d->m_pCodecCtx->rc_buffer_size = 10000000;
+                    d->m_pCodecCtx->bit_rate = d->m_bitrate;
+                    d->m_pCodecCtx->rc_min_rate = static_cast<int>(std::round(d->m_bitrate * 0.8));
+                    d->m_pCodecCtx->rc_max_rate = static_cast<int>(std::round(d->m_bitrate * 1.1));
+                    d->m_pCodecCtx->rc_buffer_size = d->m_bitrate * 2;
                     d->m_pCodecCtx->gop_size = 20;
                     d->m_pCodecCtx->max_b_frames = 0;
                     d->m_pCodecCtx->color_primaries = AVCOL_PRI_BT2020;
@@ -306,7 +332,7 @@ namespace AVQt {
                     for (const auto &cb: d->m_cbList) {
                         AVCodecParameters *parameters = avcodec_parameters_alloc();
                         avcodec_parameters_from_context(parameters, d->m_pCodecCtx);
-                        cb->init(this, d->m_framerate, d->m_pCodecCtx->time_base, 0, parameters, nullptr, nullptr);
+                        cb->init(this, av_make_q(0, 1), d->m_pCodecCtx->time_base, 0, parameters, nullptr, nullptr);
                         cb->start(this);
                     }
                 }
diff --git a/AVQt/filter/EncoderVAAPI.h b/AVQt/filter/EncoderVAAPI.h
index 617160defbe3ee073a00125e38b0b4cc4d8088e2..6de818797b378882e5f8a71e199168f9622bfd41 100644
--- a/AVQt/filter/EncoderVAAPI.h
+++ b/AVQt/filter/EncoderVAAPI.h
@@ -32,7 +32,7 @@ namespace AVQt {
         Q_INTERFACES(AVQt::IEncoder)
 
     public:
-        explicit EncoderVAAPI(QString encoder, QObject *parent = nullptr);
+        explicit EncoderVAAPI(CODEC codec, int bitrate, QObject *parent = nullptr);
 
         EncoderVAAPI(EncoderVAAPI &&other) noexcept;
 
@@ -74,7 +74,7 @@ namespace AVQt {
 
         Q_INVOKABLE void pause(IFrameSource *source, bool paused) Q_DECL_OVERRIDE;
 
-        Q_INVOKABLE void onFrame(IFrameSource *source, AVFrame *frame, int64_t frameDuration) Q_DECL_OVERRIDE;
+        Q_INVOKABLE void onFrame(IFrameSource *source, AVFrame *frame, int64_t frameDuration, AVBufferRef *pDeviceCtx) Q_DECL_OVERRIDE;
 
     signals:
 
diff --git a/AVQt/filter/IEncoder.h b/AVQt/filter/IEncoder.h
index 0554f17f0783899c26f1420fff0cae824e2b1e66..9c41a03269f7cced3df6a160bdc39317926f2039 100644
--- a/AVQt/filter/IEncoder.h
+++ b/AVQt/filter/IEncoder.h
@@ -15,6 +15,10 @@ namespace AVQt {
         Q_INTERFACES(AVQt::IPacketSource)
 
     public:
+        enum class CODEC {
+            H264, HEVC, VP9, VP8, MPEG2, AV1
+        };
+
         virtual ~IEncoder() = default;
 
         virtual bool isPaused() = 0;
@@ -31,7 +35,7 @@ namespace AVQt {
 
         Q_INVOKABLE virtual void pause(IFrameSource *source, bool pause) = 0;
 
-        Q_INVOKABLE virtual void onFrame(IFrameSource *source, AVFrame *frame, int64_t frameDuration) = 0;
+        Q_INVOKABLE virtual void onFrame(IFrameSource *source, AVFrame *frame, int64_t frameDuration, AVBufferRef *pDeviceCtx) = 0;
 
 
         // IPacketSource
diff --git a/AVQt/filter/private/EncoderVAAPI_p.h b/AVQt/filter/private/EncoderVAAPI_p.h
index 239bd63c8fde9d4705cdf6cfab0dc1cf98660e51..f310119b1df5cfde8b828a3875581e512de80ce0 100644
--- a/AVQt/filter/private/EncoderVAAPI_p.h
+++ b/AVQt/filter/private/EncoderVAAPI_p.h
@@ -21,9 +21,9 @@ namespace AVQt {
 
         EncoderVAAPI *q_ptr;
 
-        QString m_encoder{""};
+        IEncoder::CODEC m_codec{IEncoder::CODEC::H264};
+        int m_bitrate{5 * 1024 * 1024};
 
-        AVRational m_framerate{0, 1};
         AVCodec *m_pCodec{nullptr};
         AVCodecContext *m_pCodecCtx{nullptr};
         AVBufferRef *m_pDeviceCtx{nullptr}, *m_pFramesCtx{nullptr};
diff --git a/AVQt/output/IFrameSink.h b/AVQt/output/IFrameSink.h
index 7f36132bb8714a93f67b2cbd2a9fa8cc810b60c0..bb818f88d548e9afe7ec7535be3004d949a65c79 100644
--- a/AVQt/output/IFrameSink.h
+++ b/AVQt/output/IFrameSink.h
@@ -9,6 +9,7 @@
 
 struct AVFrame;
 struct AVRational;
+struct AVBufferRef;
 
 namespace AVQt {
     /*!
@@ -89,7 +90,7 @@ namespace AVQt {
          * @param framerate Source stream framerate
          * @param duration Source frame presentation duration (inverse of framerate)
          */
-        Q_INVOKABLE virtual void onFrame(IFrameSource *source, AVFrame *frame, int64_t frameDuration) = 0;
+        Q_INVOKABLE virtual void onFrame(IFrameSource *source, AVFrame *frame, int64_t frameDuration, AVBufferRef *pDeviceCtx) = 0;
 
     signals:
 
diff --git a/AVQt/output/Muxer.cpp b/AVQt/output/Muxer.cpp
index 6f6788730b8b9ed4a43c5dff6f7a5ce48ec9fa53..d612c3110cfd16c10484e4d25035ca6cfa347cb1 100644
--- a/AVQt/output/Muxer.cpp
+++ b/AVQt/output/Muxer.cpp
@@ -6,9 +6,10 @@
 #include "Muxer.h"
 
 namespace AVQt {
-    Muxer::Muxer(QIODevice *outputDevice, QObject *parent) : QThread(parent), d_ptr(new MuxerPrivate(this)) {
+    Muxer::Muxer(QIODevice *outputDevice, FORMAT format, QObject *parent) : QThread(parent), d_ptr(new MuxerPrivate(this)) {
         Q_D(AVQt::Muxer);
         d->m_outputDevice = outputDevice;
+        d->m_format = format;
     }
 
     Muxer::Muxer(AVQt::MuxerPrivate &p) : d_ptr(&p) {
@@ -59,8 +60,37 @@ namespace AVQt {
             } else if (!d->m_outputDevice->isWritable()) {
                 qFatal("[AVQt::Muxer] Output device is not writable");
             }
+
+            QString outputFormat;
+            switch (d->m_format) {
+                case FORMAT::MP4:
+                    if (d->m_outputDevice->isSequential()) {
+                        qFatal("[AVQt::Muxer] MP4 output format is not available on sequential output devices like sockets");
+                    }
+                    outputFormat = "mp4";
+                    break;
+                case FORMAT::MOV:
+                    if (d->m_outputDevice->isSequential()) {
+                        qFatal("[AVQt::Muxer] MOV output format is not available on sequential output devices like sockets");
+                    }
+                    outputFormat = "mov";
+                    break;
+                case FORMAT::MKV:
+                    outputFormat = "matroska";
+                    break;
+                case FORMAT::WEBM:
+                    outputFormat = "webm";
+                    break;
+                case FORMAT::MPEGTS:
+                    outputFormat = "mpegts";
+                    break;
+                case FORMAT::INVALID:
+                    qFatal("[AVQt::Muxer] FORMAT::INVALID is just a placeholder, don't pass it as an argument");
+                    break;
+            }
+
             d->m_pFormatContext = avformat_alloc_context();
-            d->m_pFormatContext->oformat = av_guess_format("mp4", "", nullptr);
+            d->m_pFormatContext->oformat = av_guess_format(outputFormat.toLocal8Bit().data(), "", nullptr);
             d->m_pIOBuffer = static_cast<uint8_t *>(av_malloc(MuxerPrivate::IOBUF_SIZE));
             d->m_pIOContext = avio_alloc_context(d->m_pIOBuffer, MuxerPrivate::IOBUF_SIZE, 1, d->m_outputDevice, nullptr,
                                                  &MuxerPrivate::writeToIO, &MuxerPrivate::seekIO);
diff --git a/AVQt/output/Muxer.h b/AVQt/output/Muxer.h
index 09d76da55fde2dd1b5408aeea2b2dc15d3349f67..df439442ed93bedf04d0a0baf9778c7325ef3f5f 100644
--- a/AVQt/output/Muxer.h
+++ b/AVQt/output/Muxer.h
@@ -19,11 +19,12 @@ namespace AVQt {
 
         Q_DECLARE_PRIVATE(AVQt::Muxer)
 
-    protected:
-        void run() Q_DECL_OVERRIDE;
-
     public:
-        explicit Muxer(QIODevice *outputDevice, QObject *parent = nullptr);
+        enum class FORMAT {
+            MP4, MOV, MKV, WEBM, MPEGTS, INVALID
+        };
+
+        explicit Muxer(QIODevice *outputDevice, FORMAT format, QObject *parent = nullptr);
 
         Muxer(Muxer &) = delete;
 
@@ -46,6 +47,9 @@ namespace AVQt {
 
         void operator=(const Muxer &) = delete;
 
+    protected:
+        void run() Q_DECL_OVERRIDE;
+
     signals:
 
         void started() Q_DECL_OVERRIDE;
diff --git a/AVQt/output/OpenGLRenderer.cpp b/AVQt/output/OpenGLRenderer.cpp
index d78699bc6edecea2909780f3839ffd8c735ef741..a314955534cc0554bd374627f52feadc9769a353 100644
--- a/AVQt/output/OpenGLRenderer.cpp
+++ b/AVQt/output/OpenGLRenderer.cpp
@@ -142,9 +142,10 @@ namespace AVQt {
         return d->m_paused.load();
     }
 
-    void OpenGLRenderer::onFrame(IFrameSource *source, AVFrame *frame, int64_t duration) {
+    void OpenGLRenderer::onFrame(IFrameSource *source, AVFrame *frame, int64_t duration, AVBufferRef *pDeviceCtx) {
         Q_UNUSED(source)
         Q_UNUSED(duration)
+        Q_UNUSED(pDeviceCtx)
 
         Q_D(AVQt::OpenGLRenderer);
 
diff --git a/AVQt/output/OpenGLRenderer.h b/AVQt/output/OpenGLRenderer.h
index a872577af3fb93025e832149b43dc68b52218841..6fd09bf5ef1bc8461edc5a5a4fbf0e890e7ab6ba 100644
--- a/AVQt/output/OpenGLRenderer.h
+++ b/AVQt/output/OpenGLRenderer.h
@@ -92,7 +92,7 @@ namespace AVQt {
          * @param timebase Source stream time base, if you don't know what this means, you probably don't want to use it.
          * @param framerate Source stream framerate
          */
-        Q_INVOKABLE void onFrame(IFrameSource *source, AVFrame *frame, int64_t frameDuration) Q_DECL_OVERRIDE;
+        Q_INVOKABLE void onFrame(IFrameSource *source, AVFrame *frame, int64_t frameDuration, AVBufferRef *pDeviceCtx) Q_DECL_OVERRIDE;
 
     signals:
 
diff --git a/AVQt/output/private/Muxer_p.h b/AVQt/output/private/Muxer_p.h
index ca43c3509aa082d74f34d217019e48d850edd489..7aefc087e4a29b00bbe2f80c28231fd7e86529c9 100644
--- a/AVQt/output/private/Muxer_p.h
+++ b/AVQt/output/private/Muxer_p.h
@@ -28,8 +28,10 @@ namespace AVQt {
 
         QIODevice *m_outputDevice{nullptr};
 
+        Muxer::FORMAT m_format{Muxer::FORMAT::INVALID};
+
         QMutex m_initMutex{};
-        static constexpr size_t IOBUF_SIZE{4 * 1024};  // 4 KB
+        static constexpr int64_t IOBUF_SIZE{4 * 1024};  // 4 KB
         uint8_t *m_pIOBuffer{nullptr};
         AVIOContext *m_pIOContext{nullptr};
         AVFormatContext *m_pFormatContext{nullptr};
diff --git a/Player/main.cpp b/Player/main.cpp
index 83656d8347d3ce3f95d26da4e4d02202162c9c3c..dd7297924e2238bda4ed89ca61833b5e06c30c7b 100644
--- a/Player/main.cpp
+++ b/Player/main.cpp
@@ -63,17 +63,17 @@ int main(int argc, char *argv[]) {
     inputFile->open(QIODevice::ReadWrite);
 
     AVQt::Demuxer demuxer(inputFile);
-//    AVQt::AudioDecoder decoder;
-//    AVQt::OpenALAudioOutput output;
+    AVQt::AudioDecoder decoder;
+    AVQt::OpenALAudioOutput output;
 
-//    demuxer.registerCallback(&decoder, AVQt::IPacketSource::CB_AUDIO);
-//    decoder.registerCallback(&output);
+    demuxer.registerCallback(&decoder, AVQt::IPacketSource::CB_AUDIO);
+    decoder.registerCallback(&output);
 
     AVQt::IDecoder *videoDecoder;
     AVQt::IEncoder *videoEncoder;
 #ifdef Q_OS_LINUX
     videoDecoder = new AVQt::DecoderVAAPI;
-    videoEncoder = new AVQt::EncoderVAAPI("hevc_vaapi");
+    videoEncoder = new AVQt::EncoderVAAPI(AVQt::IEncoder::CODEC::HEVC, 10 * 1000 * 1000);
 #elif defined(Q_OS_WINDOWS)
     videoDecoder = new AVQt::DecoderDXVA2();
 #else
@@ -82,14 +82,14 @@ int main(int argc, char *argv[]) {
     AVQt::OpenGLRenderer renderer;
 
     demuxer.registerCallback(videoDecoder, AVQt::IPacketSource::CB_VIDEO);
-//    videoDecoder->registerCallback(videoEncoder);
+    videoDecoder->registerCallback(videoEncoder);
 
-//    QFile outputFile("output.mp4");
-//    outputFile.open(QIODevice::ReadWrite | QIODevice::Truncate);
-//    outputFile.seek(0);
-//    AVQt::Muxer muxer(&outputFile);
+    QFile outputFile("output.mp4");
+    outputFile.open(QIODevice::ReadWrite | QIODevice::Truncate);
+    outputFile.seek(0);
+    AVQt::Muxer muxer(&outputFile, AVQt::Muxer::FORMAT::MP4);
 
-//    videoEncoder->registerCallback(&muxer, AVQt::IPacketSource::CB_VIDEO);
+    videoEncoder->registerCallback(&muxer, AVQt::IPacketSource::CB_VIDEO);
     videoDecoder->registerCallback(&renderer);
 
     renderer.setMinimumSize(QSize(360, 240));