diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ba0f7e5ea16a2606db664148aefdeaa4437feca7
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,8 @@
+<component name="InspectionProjectProfileManager">
+  <profile version="1.0">
+    <option name="myName" value="Project Default" />
+    <inspection_tool class="Clazy" enabled="true" level="WARNING" enabled_by_default="true">
+      <option name="clazyChecks" value="level0,no-qt-macros" />
+    </inspection_tool>
+  </profile>
+</component>
\ No newline at end of file
diff --git a/AVQt/filter/DecoderVAAPI.cpp b/AVQt/filter/DecoderVAAPI.cpp
index a68f3edf229d6faf9bf99d846ac56483e12743b3..d61dcecebc86002e501cdd314dbc8c3e104ba7d5 100644
--- a/AVQt/filter/DecoderVAAPI.cpp
+++ b/AVQt/filter/DecoderVAAPI.cpp
@@ -72,6 +72,13 @@ namespace AVQt {
 
         stop();
 
+        {
+            QMutexLocker lock(&d->m_cbListMutex);
+            for (const auto &cb: d->m_cbList) {
+                cb->deinit(this);
+            }
+        }
+
         if (d->m_pCodecParams) {
             avcodec_parameters_free(&d->m_pCodecParams);
             d->m_pCodecParams = nullptr;
@@ -228,6 +235,7 @@ namespace AVQt {
 
                     avcodec_parameters_to_context(d->m_pCodecCtx, d->m_pCodecParams);
                     d->m_pCodecCtx->hw_device_ctx = av_buffer_ref(d->m_pDeviceCtx);
+                    d->m_pCodecCtx->time_base = d->m_timebase;
                     ret = avcodec_open2(d->m_pCodecCtx, d->m_pCodec, nullptr);
                     if (ret != 0) {
                         qFatal("%d: Could not open VAAPI decoder: %s", ret, av_make_error_string(strBuf, strBufSize, ret));
diff --git a/AVQt/filter/EncoderVAAPI.cpp b/AVQt/filter/EncoderVAAPI.cpp
index 1c76568bd995933b4f4dcbc67934052ee35c141b..248f91fe24f36602d90825f29e9fe5ea3b6d2f09 100644
--- a/AVQt/filter/EncoderVAAPI.cpp
+++ b/AVQt/filter/EncoderVAAPI.cpp
@@ -45,6 +45,8 @@ namespace AVQt {
     int EncoderVAAPI::deinit() {
         Q_D(AVQt::EncoderVAAPI);
 
+        stop();
+
         {
             QMutexLocker lock(&d->m_cbListMutex);
             for (const auto &cb: d->m_cbList) {
@@ -216,6 +218,10 @@ namespace AVQt {
         {
             QMutexLocker lock{&d->m_inputQueueMutex};
             d->m_inputQueue.enqueue(queueFrame);
+//            std::sort(d->m_inputQueue.begin(), d->m_inputQueue.end(),
+//                      [&](const QPair<AVFrame *, int64_t> &f1, const QPair<AVFrame *, int64_t> &f2) {
+//                          return f1.first->pts < f2.first->pts;
+//                      });
         }
     }
 
@@ -227,7 +233,7 @@ namespace AVQt {
         char strBuf[strBufSize];
 
         while (d->m_running.load()) {
-            if (!d->m_paused.load() && !d->m_inputQueue.isEmpty()) {
+            if (!d->m_paused.load() && d->m_inputQueue.size() > 5) {
                 bool shouldBe = true;
                 if (d->m_firstFrame.compare_exchange_strong(shouldBe, false)) {
                     auto frame = d->m_inputQueue.first().first;
@@ -290,10 +296,19 @@ 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 = 50000000;
+                    d->m_pCodecCtx->rc_min_rate = 30000000;
+                    d->m_pCodecCtx->rc_max_rate = 50000000;
+                    d->m_pCodecCtx->rc_buffer_size = 100000000;
+                    d->m_pCodecCtx->gop_size = 20;
+                    d->m_pCodecCtx->color_primaries = AVCOL_PRI_BT2020;
+                    d->m_pCodecCtx->color_trc = AVCOL_TRC_SMPTE2084;
+                    d->m_pCodecCtx->colorspace = AVCOL_SPC_BT2020_NCL;
+
 //                    }
 
 //                    d->m_pCodecCtx->pix_fmt = AV_PIX_FMT_VAAPI;
-                    d->m_pCodecCtx->time_base = av_make_q(1, 1000000);
+                    d->m_pCodecCtx->time_base = av_make_q(1, 1000000); // Timestamps from frame sources are always microseconds
                     ret = avcodec_open2(d->m_pCodecCtx, d->m_pCodec, nullptr);
                     if (ret < 0) {
                         qFatal("%i: Unable to open VAAPI encoder: %s", ret, av_make_error_string(strBuf, strBufSize, ret));
@@ -325,24 +340,44 @@ namespace AVQt {
                     } else {
                         av_hwframe_transfer_data(d->m_pHWFrame, frame.first, 0);
                     }
-                    d->m_pHWFrame->pts = av_rescale_q(frame.first->pts, av_make_q(1, 1000000), d->m_pCodecCtx->time_base);
+                    d->m_pHWFrame->pts = av_rescale_q(frame.first->pts, av_make_q(1, 1000000),
+                                                      d->m_pCodecCtx->time_base); // Incoming timestamps are always microseconds
+//                    d->m_pHWFrame->pts = frame.first->pts;
                     av_frame_free(&frame.first);
                     ret = avcodec_send_frame(d->m_pCodecCtx, d->m_pHWFrame);
-                    if (ret != 0) {
+                    qDebug("[AVQt::EncoderVAAPI] Sent frame with PTS %lld to encoder", static_cast<long long>(d->m_pHWFrame->pts));
+                    /*if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
+                        break;
+                    } else */if (ret != 0) {
                         qFatal("%i: Could not send frame to VAAPI encoder: %s", ret, av_make_error_string(strBuf, strBufSize, ret));
                     }
+
+//                    avcodec_send_frame(d->m_pCodecCtx, nullptr);
+//
+//                    if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
+//                        break;
+//                    } else if (ret != 0) {
+//                        qFatal("%i: Could not flush VAAPI encoder: %s", ret, av_make_error_string(strBuf, strBufSize, ret));
+//                    }
                 }
                 AVPacket *packet = av_packet_alloc();
                 while (true) {
                     ret = avcodec_receive_packet(d->m_pCodecCtx, packet);
-                    qDebug("[AVQt::EncoderVAAPI] Got packet from encoder with PTS: %lld, timebase: %d/%d",
-                           static_cast<long long>(packet->pts),
-                           d->m_pCodecCtx->time_base.num, d->m_pCodecCtx->time_base.den);
                     if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) {
                         break;
                     } else if (ret != 0) {
                         qFatal("%i: Could not receive packet from encoder: %s", ret, av_make_error_string(strBuf, strBufSize, ret));
                     }
+//                    packet->pts = d->m_pHWFrame->pts;
+//                    packet->pts = d->m_pCodecCtx->coded_frame->pts;
+//                    packet->pts = packet->dts;
+                    packet->pos = -1;
+                    av_packet_rescale_ts(packet, d->m_pCodecCtx->time_base, av_make_q(1, 1000000));
+                    qDebug("[AVQt::EncoderVAAPI] Got packet from encoder with PTS: %lld, DTS: %lld, duration: %lld, timebase: %d/%d",
+                           static_cast<long long>(packet->pts),
+                           static_cast<long long>(packet->dts),
+                           static_cast<long long>(packet->duration),
+                           d->m_pCodecCtx->time_base.num, d->m_pCodecCtx->time_base.den);
                     if (packet->buf) {
                         QMutexLocker lock(&d->m_cbListMutex);
                         for (const auto &cb: d->m_cbList) {
diff --git a/AVQt/output/Muxer.cpp b/AVQt/output/Muxer.cpp
index 935ff345d5ff7b3d7e615227e9d1b953608c5550..2e83823f7b07887bd37c73c6e66ff788f8c3be6e 100644
--- a/AVQt/output/Muxer.cpp
+++ b/AVQt/output/Muxer.cpp
@@ -2,6 +2,7 @@
 // Created by silas on 5/24/21.
 //
 
+#include <experimental/algorithm>
 #include <input/IPacketSource.h>
 #include "private/Muxer_p.h"
 #include "Muxer.h"
@@ -61,7 +62,7 @@ namespace AVQt {
                 qFatal("[AVQt::Muxer] Output device is not writable");
             }
             d->m_pFormatContext = avformat_alloc_context();
-            d->m_pFormatContext->oformat = av_guess_format("mpegts", "", nullptr);
+            d->m_pFormatContext->oformat = av_guess_format("mp4", "", 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);
@@ -92,18 +93,20 @@ namespace AVQt {
             subtitleStream->time_base = timebase;
             d->m_sourceStreamMap[source].insert(subtitleStream, timebase);
         }
-        int ret = avformat_init_output(d->m_pFormatContext, nullptr);
-        if (ret <= 0) {
+        int ret = avformat_write_header(d->m_pFormatContext, nullptr);
+        if (ret != 0) {
             constexpr auto strBufSize = 32;
             char strBuf[strBufSize];
             qWarning("[AVQt::Muxer] %d: Couldn't init AVFormatContext: %s", ret, av_make_error_string(strBuf, strBufSize, ret));
         }
+        qDebug("[AVQt::Muxer] Initialized");
     }
 
     void Muxer::deinit(IPacketSource *source) {
         Q_D(AVQt::Muxer);
 
-        stop(nullptr);
+        stop(source);
+        qDebug("[AVQt::Muxer] deinit() called");
 
         if (d->m_sourceStreamMap.contains(source)) {
             d->m_sourceStreamMap.remove(source);
@@ -115,18 +118,19 @@ namespace AVQt {
         if (d->m_sourceStreamMap.isEmpty()) {
             QMutexLocker lock(&d->m_initMutex);
             if (d->m_pFormatContext) {
-                if (d->m_headerWritten.load()) {
-                    av_write_trailer(d->m_pFormatContext);
-                }
-                int ret = av_interleaved_write_frame(d->m_pFormatContext, nullptr);
+                int ret = av_write_frame(d->m_pFormatContext, nullptr);
                 if (ret != 0) {
                     constexpr auto strBufSize = 32;
                     char strBuf[strBufSize];
                     qWarning("%d: Couldn't flush AVFormatContext packet queue: %s", ret, av_make_error_string(strBuf, strBufSize, ret));
                 }
+//                if (d->m_headerWritten.load()) {
+                av_write_trailer(d->m_pFormatContext);
+                qDebug("[AVQt::Muxer] Wrote trailer");
+//                }
                 avio_flush(d->m_pFormatContext->pb);
-                avio_closep(&d->m_pIOContext);
                 avformat_free_context(d->m_pFormatContext);
+                d->m_outputDevice->close();
             }
         }
 
@@ -179,45 +183,52 @@ namespace AVQt {
     void Muxer::onPacket(IPacketSource *source, AVPacket *packet, int8_t packetType) {
         Q_D(AVQt::Muxer);
 
-        bool unknownSource = !d->m_sourceStreamMap.contains(source);
-        bool initStream = false;
-        AVStream *addStream;
-        if (!unknownSource) {
-            for (const auto &stream : d->m_sourceStreamMap[source].keys()) {
-                if ((packetType == IPacketSource::CB_VIDEO && stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) ||
-                    (packetType == IPacketSource::CB_AUDIO && stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) ||
-                    (packetType == IPacketSource::CB_SUBTITLE && stream->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
-                    addStream = stream;
-                    initStream = true;
-                    break;
+        if (packet->pts != AV_NOPTS_VALUE) {
+
+            bool unknownSource = !d->m_sourceStreamMap.contains(source);
+            bool initStream = false;
+            AVStream *addStream;
+            if (!unknownSource) {
+                for (const auto &stream : d->m_sourceStreamMap[source].keys()) {
+                    if ((packetType == IPacketSource::CB_VIDEO && stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) ||
+                        (packetType == IPacketSource::CB_AUDIO && stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) ||
+                        (packetType == IPacketSource::CB_SUBTITLE && stream->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
+                        addStream = stream;
+                        initStream = true;
+                        break;
+                    }
                 }
             }
-        }
-        if (unknownSource || !initStream) {
-            qWarning("[AVQt::Muxer] onPacket() called without preceding call to init() for stream type. Ignoring packet");
-            return;
-        }
+            if (unknownSource || !initStream) {
+                qWarning("[AVQt::Muxer] onPacket() called without preceding call to init() for stream type. Ignoring packet");
+                return;
+            }
+
+            QPair<AVPacket *, AVStream *> queuePacket{av_packet_clone(packet), addStream};
+            queuePacket.first->stream_index = addStream->index;
+            qDebug("[AVQt::Muxer] Getting packet with PTS: %lld", static_cast<long long>(packet->pts));
+            av_packet_rescale_ts(queuePacket.first, av_make_q(1, 1000000), addStream->time_base);
 
-        QPair<AVPacket *, AVStream *> queuePacket{av_packet_clone(packet), addStream};
-        queuePacket.first->stream_index = addStream->index;
-        qDebug("[AVQt::Muxer] Getting packet with PTS: %lld", static_cast<long long>(packet->pts));
-        av_packet_rescale_ts(queuePacket.first, d->m_sourceStreamMap[source][addStream], addStream->time_base);
+            while (d->m_inputQueue.size() >= 100) {
+                QThread::msleep(2);
+            }
 
-        QMutexLocker lock(&d->m_inputQueueMutex);
-        d->m_inputQueue.enqueue(queuePacket);
+            QMutexLocker lock(&d->m_inputQueueMutex);
+            d->m_inputQueue.enqueue(queuePacket);
+//            std::sort(d->m_inputQueue.begin(), d->m_inputQueue.end(), &MuxerPrivate::packetQueueCompare);
+        }
     }
 
     void Muxer::run() {
         Q_D(AVQt::Muxer);
 
         while (d->m_running.load()) {
-            if (!d->m_paused.load() && !d->m_inputQueue.isEmpty()) {
+            if (!d->m_paused.load() && d->m_inputQueue.size() > 5) {
                 QPair<AVPacket *, AVStream *> packet;
                 {
                     QMutexLocker lock(&d->m_inputQueueMutex);
                     packet = d->m_inputQueue.dequeue();
                 }
-//                av_packet_rescale_ts(packet.first, packet.second->time_base, av_make_q(1, AV_TIME_BASE));
                 int ret = av_interleaved_write_frame(d->m_pFormatContext, packet.first);
                 qDebug("Written packet");
                 if (ret != 0) {
@@ -264,4 +275,8 @@ namespace AVQt {
 
         return result ? outputDevice->pos() : AVERROR_UNKNOWN;
     }
+
+    bool MuxerPrivate::packetQueueCompare(const QPair<AVPacket *, AVStream *> &packet1, const QPair<AVPacket *, AVStream *> &packet2) {
+        return packet1.first->dts < packet2.first->dts;
+    }
 }
\ No newline at end of file
diff --git a/AVQt/output/Muxer.h b/AVQt/output/Muxer.h
index a0ddeeda02cdf1b994ed35483680c2924d0fb902..09d76da55fde2dd1b5408aeea2b2dc15d3349f67 100644
--- a/AVQt/output/Muxer.h
+++ b/AVQt/output/Muxer.h
@@ -61,4 +61,4 @@ namespace AVQt {
     };
 }
 
-#endif //LIBAVQT_MUXER_H
+#endif //LIBAVQT_MUXER_H
\ No newline at end of file
diff --git a/AVQt/output/private/Muxer_p.h b/AVQt/output/private/Muxer_p.h
index cbe1523645755427e74bf816403d36950e46039d..ca43c3509aa082d74f34d217019e48d850edd489 100644
--- a/AVQt/output/private/Muxer_p.h
+++ b/AVQt/output/private/Muxer_p.h
@@ -47,7 +47,9 @@ namespace AVQt {
         static int64_t seekIO(void *opaque, int64_t offset, int whence);
 
         static int writeToIO(void *opaque, uint8_t *buf, int buf_size);
+
+        static bool packetQueueCompare(const QPair<AVPacket *, AVStream *> &packet1, const QPair<AVPacket *, AVStream *> &packet2);
     };
 }
 
-#endif //LIBAVQT_MUXER_P_H
+#endif //LIBAVQT_MUXER_P_H
\ No newline at end of file
diff --git a/Player/main.cpp b/Player/main.cpp
index 7a4cef9d521e602b0ce52c88599296c90e85133a..a4623d4f5d22aafbcbdd9d0cc7a7ee9e43f33367 100644
--- a/Player/main.cpp
+++ b/Player/main.cpp
@@ -76,16 +76,17 @@ int main(int argc, char *argv[]) {
 #endif
     AVQt::OpenGLRenderer renderer;
 
-//    AVQt::IEncoder *encoder = new AVQt::EncoderVAAPI("hevc_vaapi");
+    AVQt::IEncoder *encoder = new AVQt::EncoderVAAPI("hevc_vaapi");
 
     demuxer.registerCallback(videoDecoder, AVQt::IPacketSource::CB_VIDEO);
-//    videoDecoder->registerCallback(encoder);
+    videoDecoder->registerCallback(encoder);
 
-//    QFile outputFile("output.ts");
-//    outputFile.open(QIODevice::ReadWrite | QIODevice::Truncate);
-//    AVQt::Muxer muxer(&outputFile);
+    QFile outputFile("output.mp4");
+    outputFile.open(QIODevice::ReadWrite | QIODevice::Truncate);
+    outputFile.seek(0);
+    AVQt::Muxer muxer(&outputFile);
 
-//    encoder->registerCallback(&muxer, AVQt::IPacketSource::CB_VIDEO);
+    encoder->registerCallback(&muxer, AVQt::IPacketSource::CB_VIDEO);
     videoDecoder->registerCallback(&renderer);
 
     renderer.setMinimumSize(QSize(360, 240));
@@ -105,7 +106,7 @@ int main(int argc, char *argv[]) {
 
     QObject::connect(app, &QApplication::aboutToQuit, [&] {
         demuxer.deinit();
-//        delete encoder;
+        delete encoder;
         delete videoDecoder;
     });