diff --git a/CMakeLists.txt b/CMakeLists.txt
index 72a245b0a77c4ebe81720bffcd75974d3b04f6de..271e3ecc586523d41dc23de78f56f1dc578ba7e0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -488,7 +488,7 @@ set(EXT_INCLUDE_DIRS
         ${LIBLAVA_EXT_DIR}/spdlog/include
         # Since the encoder is written against a specific version of the vulkan headers, the required version of the headers has to be added to the project.
         # ${LIBLAVA_EXT_DIR}/Vulkan-Headers/include
-		${LIBLAVA_INC_DIR}/vulkan_headers
+        ${LIBLAVA_INC_DIR}/vulkan_headers
         ${LIBLAVA_EXT_DIR}/VulkanMemoryAllocator/include
         ${LIBLAVA_EXT_DIR}/volk
         #${LIBLAVA_EXT_DIR}/stb
@@ -689,6 +689,11 @@ message("=======================================================================
             ${SRC_DIR}/vr_application.hpp ${SRC_DIR}/vr_application.cpp
             ${SRC_DIR}/scene.hpp ${SRC_DIR}/scene.cpp
 
+            #Encoder
+            ${SRC_DIR}/encoder/encoder.hpp ${SRC_DIR}/encoder/encoder.cpp
+            ${SRC_DIR}/encoder/vulkan_encoder.hpp ${SRC_DIR}/encoder/vulkan_encoder.cpp
+            ${SRC_DIR}/encoder/nvidia_encoder.hpp ${SRC_DIR}/encoder/nvidia_encoder.cpp
+
             #Headset
             ${SRC_DIR}/headset/headset.hpp ${SRC_DIR}/headset/headset.cpp
             ${SRC_DIR}/headset/emulated_headset.hpp ${SRC_DIR}/headset/emulated_headset.cpp
@@ -713,7 +718,6 @@ message("=======================================================================
             #Utility
             ${SRC_DIR}/utility/command_parser.hpp ${SRC_DIR}/utility/command_parser.cpp
             ${SRC_DIR}/utility/companion_window.hpp ${SRC_DIR}/utility/companion_window.cpp
-            ${SRC_DIR}/utility/encoder.hpp ${SRC_DIR}/utility/encoder.cpp
             ${SRC_DIR}/utility/extern_fence.hpp ${SRC_DIR}/utility/extern_fence.cpp
             ${SRC_DIR}/utility/frame_capture.hpp ${SRC_DIR}/utility/frame_capture.cpp
             ${SRC_DIR}/utility/geometry_buffer.hpp ${SRC_DIR}/utility/geometry_buffer.cpp
@@ -803,6 +807,7 @@ message("=======================================================================
             source_group("" FILES ${SRC_DIR}/scene.cpp)
             source_group("" FILES ${SRC_DIR}/scene.hpp)
             
+            source_group("Encoder" REGULAR_EXPRESSION ${SRC_DIR}/encoder/*)
             source_group("Headset" REGULAR_EXPRESSION ${SRC_DIR}/headset/*)
             source_group("Strategy" REGULAR_EXPRESSION ${SRC_DIR}/strategy/*)
             source_group("Stream" REGULAR_EXPRESSION ${SRC_DIR}/stream/*)
diff --git a/src/encoder/encoder.cpp b/src/encoder/encoder.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6c54c434527947a5a79d57204a0d9c41a0744619
--- /dev/null
+++ b/src/encoder/encoder.cpp
@@ -0,0 +1,51 @@
+#include "encoder.hpp"
+#include "vulkan_encoder.hpp"
+#include "nvidia_encoder.hpp"
+
+bool setup_instance_for_encoder(EncoderType encoder_type, lava::frame_config& config)
+{
+    switch (encoder_type)
+    {
+    case ENCODER_TYPE_VULKAN:
+        return setup_instance_for_vulkan_encoder(config);
+    case ENCODER_TYPE_NVIDIA:
+        return setup_instance_for_nvidia_encoder(config);
+    default:
+        lava::log()->error("Unkown encoder type!");
+        break;
+    }
+
+    return false;
+}
+
+bool setup_device_for_encoder(EncoderType encoder_type, lava::device::create_param& parameters)
+{
+    switch (encoder_type)
+    {
+    case ENCODER_TYPE_VULKAN:
+        return setup_device_for_vulkan_encoder(parameters);
+    case ENCODER_TYPE_NVIDIA:
+        return setup_device_for_nvidia_encoder(parameters);
+    default:
+        lava::log()->error("Unkown encoder type!");
+        break;
+    }
+
+    return false;
+}
+
+Encoder::Ptr make_encoder(EncoderType encoder_type)
+{
+    switch (encoder_type)
+    {
+    case ENCODER_TYPE_VULKAN:
+        return std::make_shared<VulkanEncoder>();
+    case ENCODER_TYPE_NVIDIA:
+        return std::make_shared<NvidiaEncoder>();
+    default:
+        lava::log()->error("Unkown encoder type!");
+        break;
+    }
+
+    return nullptr;
+}
\ No newline at end of file
diff --git a/src/encoder/encoder.hpp b/src/encoder/encoder.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..a766aed117c8b8c12f5e50526be1ff09b1ffc419
--- /dev/null
+++ b/src/encoder/encoder.hpp
@@ -0,0 +1,92 @@
+/*
+  The encoder can be used to create a h264 stream out of a sequence of images.
+  In order to be able to use the encoder, it is neccessary to call the function setup_instance_for_encoder(...) during the setup of the vulkan instance.
+  Besides that, it is neccessary to call the function setup_device_for_encoder(...) during the setup of the vulkan device.
+  A frame can be submitted for encoding using the function encode(...).
+  After the completion of an encode task, a callback function is executed to which the resulting ouput of the task is passed.
+  Example:
+
+   //During on_setup_instance(...)
+   setup_instance_for_encoder(...);
+
+   //During on_setup_device(...)
+   setup_device_for_encoder(...);
+
+   //During creation and submission of a frame
+   Encoder::Ptr encoder = make_encoder();
+
+   encoder->create(...);
+
+   encoder->encode(..., image, ..., [](const std::span<uint8_t>& content, bool is_config)
+   {
+        //Use content
+   });
+*/
+
+#pragma once
+#include <liblava/lava.hpp>
+#include <glm/glm.hpp>
+#include <functional>
+#include <span>
+#include <memory>
+#include <cstdint>
+
+enum EncoderMode
+{
+    ENCODER_MODE_CONSTANT_BITRATE,
+    ENCODER_MODE_CONSTANT_QUALITY
+};
+
+// When adding or removing an encoder, the functions make_encoder(...), setup_instance_for_encoder(...), setup_device_for_encoder(...) as well as
+// the function set_encoder(...) of the CommandParser need to be adapted accordingly.
+enum EncoderType
+{
+    ENCODER_TYPE_VULKAN, //Use vulkan video for encoding
+    ENCODER_TYPE_NVIDIA  //Use Nvenc for encoding
+};
+
+class Encoder
+{
+public:
+    typedef std::shared_ptr<Encoder> Ptr;
+
+    //NOTE: If the is_config flag is true, the content passed to this callback function contains a sequence parameter set or picture parameter set.
+    typedef std::function<void(const std::span<uint8_t>& content, bool is_config)> OnEncodeComplete;
+    typedef std::function<void()> OnEncodeError;
+
+public:
+    Encoder() = default;
+    virtual ~Encoder() = default;
+
+    //NOTE: The parameter input_buffers defines how many input images the encoder should provide.
+    virtual bool create(lava::device_ptr device, const lava::renderer& renderer, const glm::uvec2& size, uint32_t input_buffers) = 0;
+    virtual void destroy() = 0;
+
+    //NOTE: The following functions should be thread safe.
+    //NOTE: The callback function is executed only by the worker thread of the encoder.
+    virtual bool encode(VkCommandBuffer command_buffer, lava::renderer& renderer, lava::image::ptr image, VkImageLayout image_layout, OnEncodeComplete function) = 0;
+
+    //NOTE: The callbacks are executed only by the worker thread of the encoder.
+    //NOTE: Set the callbacks before calling create and don't do it again after calling create.
+    virtual void set_on_encode_error(OnEncodeError function) = 0;
+
+    //NOTE: The following functions should be thread safe.
+    //NOTE: The following settings are only suggestions and can be ignored if for example the feature is not supported.
+    virtual void set_mode(EncoderMode mode) = 0;            //NOTE: Defines if the encoder should use constant quality or constant bitrate. Default: constant quality
+    virtual void set_quality(double quality) = 0;           //NOTE: The quality ranges from 0.0 (low quality) to 1.0 (high quality). Default: 0.0
+    virtual void set_bitrate(double bitrate) = 0;           //NOTE: The bitrate is given in MBits/s. Default: 5.0
+    virtual void set_key_rate(uint32_t key_rate) = 0;       //NOTE: The keyrate is defined as the number of frames between two i-frames. Default: 90
+    virtual void set_frame_rate(uint32_t frame_rate) = 0;   //NOTE: The frame rate is given in frames per second. Default: 90
+
+    //NOTE: The following functions should be thread safe.
+    virtual EncoderMode get_mode() const = 0;
+    virtual double get_quality() const = 0;
+    virtual double get_bitrate() const = 0;
+    virtual uint32_t get_key_rate() const = 0;
+    virtual uint32_t get_frame_rate() const = 0;
+};
+
+bool setup_instance_for_encoder(EncoderType encoder_type, lava::frame_config& config);
+bool setup_device_for_encoder(EncoderType encoder_type, lava::device::create_param& parameters);
+
+Encoder::Ptr make_encoder(EncoderType encoder_type);
\ No newline at end of file
diff --git a/src/encoder/nvidia_encoder.cpp b/src/encoder/nvidia_encoder.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a60a23ec33d54fd0ddf48feff964881f7b1d321b
--- /dev/null
+++ b/src/encoder/nvidia_encoder.cpp
@@ -0,0 +1,81 @@
+#include "nvidia_encoder.hpp"
+
+bool NvidiaEncoder::create(lava::device_ptr device, const lava::renderer& renderer, const glm::uvec2& size, uint32_t input_buffers)
+{
+    return false;
+}
+
+void NvidiaEncoder::destroy()
+{
+
+}
+
+bool NvidiaEncoder::encode(VkCommandBuffer command_buffer, lava::renderer& renderer, lava::image::ptr image, VkImageLayout image_layout, OnEncodeComplete function)
+{
+    return false;
+}
+
+void NvidiaEncoder::set_on_encode_error(OnEncodeError function)
+{
+    this->on_encoder_error = std::move(function);
+}
+
+void NvidiaEncoder::set_mode(EncoderMode mode)
+{
+    this->mode = mode;
+}
+
+void NvidiaEncoder::set_quality(double quality)
+{
+    this->quality = quality;
+}
+
+void NvidiaEncoder::set_bitrate(double bitrate)
+{
+    this->bitrate = bitrate;
+}
+
+void NvidiaEncoder::set_key_rate(uint32_t key_rate)
+{
+    this->key_rate = key_rate;
+}
+
+void NvidiaEncoder::set_frame_rate(uint32_t frame_rate)
+{
+    this->frame_rate = frame_rate;
+}
+
+EncoderMode NvidiaEncoder::get_mode() const
+{
+    return this->mode;
+}
+
+double NvidiaEncoder::get_quality() const
+{
+    return this->quality;
+}
+
+double NvidiaEncoder::get_bitrate() const
+{
+    return this->bitrate;
+}
+
+uint32_t NvidiaEncoder::get_key_rate() const
+{
+    return this->key_rate;
+}
+
+uint32_t NvidiaEncoder::get_frame_rate() const
+{
+    return this->frame_rate;
+}
+
+bool setup_instance_for_nvidia_encoder(lava::frame_config& config)
+{
+    return false;
+}
+
+bool setup_device_for_nvidia_encoder(lava::device::create_param& parameters)
+{
+    return false;
+}
\ No newline at end of file
diff --git a/src/encoder/nvidia_encoder.hpp b/src/encoder/nvidia_encoder.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..d80c96ee6908ca1c0dea303e82bd34d3fbadce10
--- /dev/null
+++ b/src/encoder/nvidia_encoder.hpp
@@ -0,0 +1,49 @@
+#pragma once
+#include <liblava/lava.hpp>
+#include <glm/glm.hpp>
+#include <functional>
+#include <span>
+#include <memory>
+#include <cstdint>
+
+#include "encoder.hpp"
+
+class NvidiaEncoder : public Encoder
+{
+public:
+    typedef std::shared_ptr<NvidiaEncoder> Ptr;
+
+public:
+    NvidiaEncoder() = default;
+
+    bool create(lava::device_ptr device, const lava::renderer& renderer, const glm::uvec2& size, uint32_t input_buffers);
+    void destroy();
+
+    bool encode(VkCommandBuffer command_buffer, lava::renderer& renderer, lava::image::ptr image, VkImageLayout image_layout, OnEncodeComplete function);
+
+    void set_on_encode_error(OnEncodeError function);
+
+    void set_mode(EncoderMode mode);
+    void set_quality(double quality);
+    void set_bitrate(double bitrate);
+    void set_key_rate(uint32_t key_rate);
+    void set_frame_rate(uint32_t frame_rate);
+
+    EncoderMode get_mode() const;
+    double get_quality() const;
+    double get_bitrate() const;
+    uint32_t get_key_rate() const;
+    uint32_t get_frame_rate() const;
+
+private:
+    OnEncodeError on_encoder_error;
+
+    EncoderMode mode = ENCODER_MODE_CONSTANT_QUALITY;
+    double quality = 0.0;
+    double bitrate = 5.0;
+    uint32_t key_rate = 90;
+    uint32_t frame_rate = 90;
+};
+
+bool setup_instance_for_nvidia_encoder(lava::frame_config& config);
+bool setup_device_for_nvidia_encoder(lava::device::create_param& parameters);
\ No newline at end of file
diff --git a/src/utility/encoder.cpp b/src/encoder/vulkan_encoder.cpp
similarity index 92%
rename from src/utility/encoder.cpp
rename to src/encoder/vulkan_encoder.cpp
index 51112a6c23cc50819cb5db8795edaa421bdec583..b11d8b5e71d18068b60ef90367b17ffc72400e1d 100644
--- a/src/utility/encoder.cpp
+++ b/src/encoder/vulkan_encoder.cpp
@@ -1,8 +1,8 @@
-#include "encoder.hpp"
+#include "vulkan_encoder.hpp"
 #include <array>
 #include <vk_video/vulkan_video_codecs_common.h>
 
-bool Encoder::create(lava::device_ptr device, const lava::renderer& renderer,  asio::executor executor, const glm::uvec2& size, uint32_t frame_count)
+bool VulkanEncoder::create(lava::device_ptr device, const lava::renderer& renderer, const glm::uvec2& size, uint32_t frame_count)
 {
     //Get the default graphics queue of lava for querey ownership transiations
     this->default_queue = renderer.get_queue();
@@ -97,7 +97,7 @@ bool Encoder::create(lava::device_ptr device, const lava::renderer& renderer,  a
     //Create a pool of frames. Each frame is used for a single input image that needs to be encoded.
     for (uint32_t index = 0; index < frame_count; index++)
     {
-        EncoderFrame::Ptr frame = make_encoder_frame();
+        VulkanEncoderFrame::Ptr frame = std::make_shared<VulkanEncoderFrame>();
         frame->output_query_index = index;
 
         //Create the images that are used for the encoding as input images.
@@ -144,7 +144,7 @@ bool Encoder::create(lava::device_ptr device, const lava::renderer& renderer,  a
         }
 
         //Allocate a command buffer as well as a semaphore and a fence for the frame.
-        if (!this->create_encode_resources(device, executor, frame))
+        if (!this->create_encode_resources(device, this->worker_executor.get_executor(), frame))
         {
             return false;
         }
@@ -158,14 +158,19 @@ bool Encoder::create(lava::device_ptr device, const lava::renderer& renderer,  a
     this->frame_count = frame_count;
     this->frame_index = 0;
 
+    this->worker_thread = std::thread([this]()
+    {
+        this->worker_executor.run();
+    });
+
     return true;
 }
 
-void Encoder::destroy()
+void VulkanEncoder::destroy()
 {
     lava::device_ptr device = this->descriptor_layout->get_device();
 
-    for (EncoderFrame::Ptr frame : this->frame_list)
+    for (VulkanEncoderFrame::Ptr frame : this->frame_list)
     {
         this->destroy_frame(device, frame);
     }
@@ -177,43 +182,7 @@ void Encoder::destroy()
     this->destroy_session(device);
 }
 
-void Encoder::set_mode(EncoderMode mode)
-{
-    this->setting_mode = mode;
-    this->control_change = true;
-}
-
-void Encoder::set_key_rate(uint32_t key_rate)
-{
-    this->setting_key_rate = key_rate;
-    this->control_change = true;
-}
-
-void Encoder::set_bit_rate(double bit_rate)
-{
-    this->setting_bit_rate = bit_rate;
-    this->control_change = true;
-}
-
-void Encoder::set_frame_rate(uint32_t frame_rate)
-{
-    this->setting_frame_rate = frame_rate;
-    this->control_change = true;
-}
-
-void Encoder::set_quality_iframe(uint32_t quality)
-{
-    this->setting_quality_iframe = glm::clamp(quality, 0u, 51u);
-    this->control_change = true;
-}
-
-void Encoder::set_quality_pframe(uint32_t quality)
-{
-    this->setting_quality_pframe = glm::clamp(quality, 0u, 51u);
-    this->control_change = true;
-}
-
-bool Encoder::encode_frame(VkCommandBuffer command_buffer, lava::renderer& renderer, lava::image::ptr image, VkImageLayout image_layout, EncoderCallback callback)
+bool VulkanEncoder::encode(VkCommandBuffer command_buffer, lava::renderer& renderer, lava::image::ptr image, VkImageLayout image_layout, OnEncodeComplete callback)
 {
     if (!this->encode_control(renderer, callback))
     {
@@ -226,7 +195,7 @@ bool Encoder::encode_frame(VkCommandBuffer command_buffer, lava::renderer& rende
     }
 
     lava::device_ptr device = image->get_device();
-    EncoderFrame::Ptr frame = nullptr;
+    VulkanEncoderFrame::Ptr frame = nullptr;
 
     //Get an unused image form the frame pool
     if (!this->aquire_frame(frame))
@@ -235,7 +204,7 @@ bool Encoder::encode_frame(VkCommandBuffer command_buffer, lava::renderer& rende
     }
 
     frame->frame_index = this->frame_index;
-    frame->type = ENCODER_FRAME_TYPE_FRAME;
+    frame->type = VULKAN_ENCODER_FRAME_TYPE_FRAME;
     frame->callback = std::move(callback);
 
     //Check if the input image has the right layout. If not change the layout.
@@ -329,7 +298,68 @@ bool Encoder::encode_frame(VkCommandBuffer command_buffer, lava::renderer& rende
     return true;
 }
 
-bool Encoder::encode_control(lava::renderer& renderer, EncoderCallback callback)
+void VulkanEncoder::set_on_encode_error(OnEncodeError function)
+{
+    this->on_encode_error = std::move(function);
+}
+
+void VulkanEncoder::set_mode(EncoderMode mode)
+{
+    this->setting_mode = mode;
+    this->control_change = true;
+}
+
+void VulkanEncoder::set_quality(double quality)
+{
+    this->setting_quality_iframe = glm::clamp((uint32_t)((1.0 - quality) * 51), 0u, 51u);
+    this->setting_quality_pframe = glm::clamp((uint32_t)((1.0 - quality) * 51), 0u, 51u);
+    this->control_change = true;
+}
+
+void VulkanEncoder::set_bitrate(double bitrate)
+{
+    this->setting_bit_rate = bitrate;
+    this->control_change = true;
+}
+
+void VulkanEncoder::set_key_rate(uint32_t key_rate)
+{
+    this->setting_key_rate = key_rate;
+    this->control_change = true;
+}
+
+void VulkanEncoder::set_frame_rate(uint32_t frame_rate)
+{
+    this->setting_frame_rate = frame_rate;
+    this->control_change = true;
+}
+
+EncoderMode VulkanEncoder::get_mode() const
+{
+    return this->setting_mode;
+}
+
+double VulkanEncoder::get_quality() const
+{
+    return 1.0 - ((double)this->setting_quality_iframe / 51.0);
+}
+
+double VulkanEncoder::get_bitrate() const
+{
+    return this->setting_bit_rate;
+}
+
+uint32_t VulkanEncoder::get_key_rate() const
+{
+    return this->setting_key_rate;
+}
+
+uint32_t VulkanEncoder::get_frame_rate() const
+{
+    return this->setting_frame_rate;
+}
+
+bool VulkanEncoder::encode_control(lava::renderer& renderer, OnEncodeComplete callback)
 {
     if (!this->control_change)
     {
@@ -337,7 +367,7 @@ bool Encoder::encode_control(lava::renderer& renderer, EncoderCallback callback)
     }
 
     lava::device_ptr device = this->descriptor_layout->get_device();
-    EncoderFrame::Ptr frame = nullptr;
+    VulkanEncoderFrame::Ptr frame = nullptr;
 
     //Get an unused image form the frame pool
     if (!this->aquire_frame(frame))
@@ -346,7 +376,7 @@ bool Encoder::encode_control(lava::renderer& renderer, EncoderCallback callback)
     }
 
     frame->frame_index = this->frame_index;
-    frame->type = ENCODER_FRAME_TYPE_CONTROL;
+    frame->type = VULKAN_ENCODER_FRAME_TYPE_CONTROL;
     frame->callback = std::move(callback);
 
     //Create the encode command buffer.
@@ -366,7 +396,7 @@ bool Encoder::encode_control(lava::renderer& renderer, EncoderCallback callback)
     return true;
 }
 
-bool Encoder::encode_config(lava::renderer& renderer, EncoderCallback callback)
+bool VulkanEncoder::encode_config(lava::renderer& renderer, OnEncodeComplete callback)
 {
     if (!this->config_change)
     {
@@ -374,7 +404,7 @@ bool Encoder::encode_config(lava::renderer& renderer, EncoderCallback callback)
     }
 
     lava::device_ptr device = this->descriptor_layout->get_device();
-    EncoderFrame::Ptr frame = nullptr;
+    VulkanEncoderFrame::Ptr frame = nullptr;
 
     //Get an unused image form the frame pool
     if (!this->aquire_frame(frame))
@@ -383,7 +413,7 @@ bool Encoder::encode_config(lava::renderer& renderer, EncoderCallback callback)
     }
 
     frame->frame_index = this->frame_index;
-    frame->type = ENCODER_FRAME_TYPE_CONFIG;
+    frame->type = VULKAN_ENCODER_FRAME_TYPE_CONFIG;
     frame->callback = std::move(callback);
 
     //Create the encode command buffer.
@@ -403,7 +433,7 @@ bool Encoder::encode_config(lava::renderer& renderer, EncoderCallback callback)
     return true;
 }
 
-bool Encoder::aquire_frame(EncoderFrame::Ptr& frame)
+bool VulkanEncoder::aquire_frame(VulkanEncoderFrame::Ptr& frame)
 {
     std::unique_lock<std::mutex> lock(this->frame_mutex);
 
@@ -418,14 +448,14 @@ bool Encoder::aquire_frame(EncoderFrame::Ptr& frame)
     return false;
 }
 
-void Encoder::release_frame(EncoderFrame::Ptr frame)
+void VulkanEncoder::release_frame(VulkanEncoderFrame::Ptr frame)
 {
     std::unique_lock<std::mutex> lock(this->frame_mutex);
 
     this->frame_queue.push_back(frame);
 }
 
-bool Encoder::submit_frame(lava::device_ptr device, EncoderFrame::Ptr frame, lava::renderer& renderer)
+bool VulkanEncoder::submit_frame(lava::device_ptr device, VulkanEncoderFrame::Ptr frame, lava::renderer& renderer)
 {
     frame->encode_fence->async_wait([this, device, frame](const asio::error_code& error_code)
     {
@@ -499,7 +529,7 @@ bool Encoder::submit_frame(lava::device_ptr device, EncoderFrame::Ptr frame, lav
     return true;
 }
 
-void Encoder::write_image(lava::device_ptr device, EncoderFrame::Ptr frame, lava::image::ptr image)
+void VulkanEncoder::write_image(lava::device_ptr device, VulkanEncoderFrame::Ptr frame, lava::image::ptr image)
 {
     VkDescriptorImageInfo image_info;
     image_info.sampler = this->sampler;
@@ -521,7 +551,7 @@ void Encoder::write_image(lava::device_ptr device, EncoderFrame::Ptr frame, lava
     vkUpdateDescriptorSets(device->get(), 1, &write_info, 0, nullptr);
 }
 
-bool Encoder::record_encoding(lava::device_ptr device, EncoderFrame::Ptr frame)
+bool VulkanEncoder::record_encoding(lava::device_ptr device, VulkanEncoderFrame::Ptr frame)
 {
     VkFence fence = frame->encode_fence->get();
 
@@ -548,13 +578,13 @@ bool Encoder::record_encoding(lava::device_ptr device, EncoderFrame::Ptr frame)
 
     switch (frame->type)
     {
-    case ENCODER_FRAME_TYPE_CONTROL:
+    case VULKAN_ENCODER_FRAME_TYPE_CONTROL:
         this->encode_pass_control_setup(frame->encode_command_buffer, frame);
         break;
-    case ENCODER_FRAME_TYPE_CONFIG:
+    case VULKAN_ENCODER_FRAME_TYPE_CONFIG:
         this->encode_pass_config_setup(frame->encode_command_buffer, frame);
         break;
-    case ENCODER_FRAME_TYPE_FRAME:
+    case VULKAN_ENCODER_FRAME_TYPE_FRAME:
         this->encode_pass_frame_setup(frame->encode_command_buffer, frame);
         break;
     default:
@@ -569,42 +599,41 @@ bool Encoder::record_encoding(lava::device_ptr device, EncoderFrame::Ptr frame)
     return true;
 }
 
-void Encoder::retrive_encoding(lava::device_ptr device, EncoderFrame::Ptr frame)
+void VulkanEncoder::retrive_encoding(lava::device_ptr device, VulkanEncoderFrame::Ptr frame)
 {
-    if (frame->type == ENCODER_FRAME_TYPE_CONTROL)
+    if (frame->type == VULKAN_ENCODER_FRAME_TYPE_CONTROL)
     {
-        frame->callback(std::span<uint8_t>(), frame->type);
+        return;
     }
 
-    else
+    std::array<uint32_t, 3> buffer_range;
+    memset(buffer_range.data(), 0, sizeof(uint32_t) * buffer_range.size());
+
+    if (vkGetQueryPoolResults(device->get(), this->query_pool, frame->output_query_index, 1, sizeof(uint32_t) * buffer_range.size(), buffer_range.data(), 0, VK_QUERY_RESULT_WAIT_BIT | VK_QUERY_RESULT_WITH_STATUS_BIT_KHR) != VK_SUCCESS)
     {
-        std::array<uint32_t, 3> buffer_range;
-        memset(buffer_range.data(), 0, sizeof(uint32_t) * buffer_range.size());
+        return;
+    }
 
-        if (vkGetQueryPoolResults(device->get(), this->query_pool, frame->output_query_index, 1, sizeof(uint32_t) * buffer_range.size(), buffer_range.data(), 0, VK_QUERY_RESULT_WAIT_BIT | VK_QUERY_RESULT_WITH_STATUS_BIT_KHR) != VK_SUCCESS)
-        {
-            return;
-        }
+    uint32_t range_offset = buffer_range[0];
+    uint32_t range_size = buffer_range[1];
 
-        uint32_t range_offset = buffer_range[0];
-        uint32_t range_size = buffer_range[1];
+    vmaInvalidateAllocation(device->alloc(), frame->output_memory, range_offset, range_size);
 
-        vmaInvalidateAllocation(device->alloc(), frame->output_memory, range_offset, range_size);
+    uint8_t* range_pointer = nullptr;
 
-        uint8_t* range_pointer = nullptr;
+    if (vmaMapMemory(device->alloc(), frame->output_memory, (void**) (&range_pointer)))
+    {
+        return;
+    }
 
-        if (vmaMapMemory(device->alloc(), frame->output_memory, (void**) (&range_pointer)))
-        {
-            return;
-        }
+    bool is_config = (frame->type == VULKAN_ENCODER_FRAME_TYPE_CONFIG);
 
-        frame->callback(std::span(range_pointer + range_offset, range_size), frame->type);
+    frame->callback(std::span(range_pointer + range_offset, range_size), is_config);
 
-        vmaUnmapMemory(device->alloc(), frame->output_memory);
-    }
+    vmaUnmapMemory(device->alloc(), frame->output_memory);
 }
 
-bool Encoder::create_profiles(lava::device_ptr device)
+bool VulkanEncoder::create_profiles(lava::device_ptr device)
 {
     this->encode_profile.sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_PROFILE_INFO_EXT;
     this->encode_profile.pNext = nullptr;
@@ -641,7 +670,7 @@ bool Encoder::create_profiles(lava::device_ptr device)
     return true;
 }
 
-bool Encoder::compute_settings(const glm::uvec2& size)
+bool VulkanEncoder::compute_settings(const glm::uvec2& size)
 {
     const glm::uvec2 block_size = glm::uvec2(16); //Macroblock Size of 16x16. TODO: Look up this value form the capabillities.
     const glm::uvec2 image_alignment = glm::uvec2(this->encode_capabillities.inputImageDataFillAlignment.width, this->encode_capabillities.inputImageDataFillAlignment.height);
@@ -657,7 +686,7 @@ bool Encoder::compute_settings(const glm::uvec2& size)
     return true;
 }
 
-bool Encoder::create_session(lava::device_ptr device, const glm::uvec2& size)
+bool VulkanEncoder::create_session(lava::device_ptr device, const glm::uvec2& size)
 {
     VkExtent2D max_video_extend;
     max_video_extend.width = size.x;
@@ -688,7 +717,7 @@ bool Encoder::create_session(lava::device_ptr device, const glm::uvec2& size)
     return true;
 }
 
-bool Encoder::create_parameters(lava::device_ptr device)
+bool VulkanEncoder::create_parameters(lava::device_ptr device)
 {
     //H.264 Specification Section 7.4.2.1.1: 
     //https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-H.264-202108-I!!PDF-E&type=items
@@ -791,7 +820,7 @@ bool Encoder::create_parameters(lava::device_ptr device)
     return true;
 }
 
-bool Encoder::bind_session_memory(lava::device_ptr device)
+bool VulkanEncoder::bind_session_memory(lava::device_ptr device)
 {
     uint32_t requirement_count = 0;
     if (vkGetVideoSessionMemoryRequirementsKHR(device->get(), this->video_session, &requirement_count, nullptr) != VK_SUCCESS)
@@ -855,7 +884,7 @@ bool Encoder::bind_session_memory(lava::device_ptr device)
     return true;
 }
 
-bool Encoder::create_sampler(lava::device_ptr device)
+bool VulkanEncoder::create_sampler(lava::device_ptr device)
 {
     VkSamplerCreateInfo sampler_create_info;
     sampler_create_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
@@ -885,7 +914,7 @@ bool Encoder::create_sampler(lava::device_ptr device)
     return true;
 }
 
-bool Encoder::create_pools(lava::device_ptr device, uint32_t frame_count)
+bool VulkanEncoder::create_pools(lava::device_ptr device, uint32_t frame_count)
 {
     VkCommandPoolCreateInfo command_create_info;
     command_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
@@ -921,7 +950,7 @@ bool Encoder::create_pools(lava::device_ptr device, uint32_t frame_count)
     return true;
 }
 
-bool Encoder::create_layouts(lava::device_ptr device)
+bool VulkanEncoder::create_layouts(lava::device_ptr device)
 {
     this->descriptor_layout = lava::make_descriptor();
     this->descriptor_layout->add_binding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT);
@@ -942,7 +971,7 @@ bool Encoder::create_layouts(lava::device_ptr device)
     return true;
 }
 
-bool Encoder::create_image_memory(lava::device_ptr device, VkImage image, VkImageAspectFlagBits image_aspect, VmaAllocation& memory)
+bool VulkanEncoder::create_image_memory(lava::device_ptr device, VkImage image, VkImageAspectFlagBits image_aspect, VmaAllocation& memory)
 {
     bool is_plane = false;
 
@@ -985,7 +1014,7 @@ bool Encoder::create_image_memory(lava::device_ptr device, VkImage image, VkImag
     return true;
 }
 
-bool Encoder::create_image_view(lava::device_ptr device, VkImage image, VkFormat image_format, VkImageView& image_view)
+bool VulkanEncoder::create_image_view(lava::device_ptr device, VkImage image, VkFormat image_format, VkImageView& image_view)
 {
     VkComponentMapping components;
     components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
@@ -1018,7 +1047,7 @@ bool Encoder::create_image_view(lava::device_ptr device, VkImage image, VkFormat
     return true;
 }
 
-bool Encoder::create_input_images(lava::device_ptr device, EncoderFrame::Ptr frame)
+bool VulkanEncoder::create_input_images(lava::device_ptr device, VulkanEncoderFrame::Ptr frame)
 {
     //TODO: Share memory between combined image and luma, chroma image.
     //The input image (input_combined) for the encoding is a multi plane images.
@@ -1222,7 +1251,7 @@ bool Encoder::create_input_images(lava::device_ptr device, EncoderFrame::Ptr fra
     return true;
 }
 
-bool Encoder::create_slot_image(lava::device_ptr device, EncoderFrame::Ptr frame)
+bool VulkanEncoder::create_slot_image(lava::device_ptr device, VulkanEncoderFrame::Ptr frame)
 {
     VkExtent3D image_extend;
     image_extend.width = this->setting_image_size.x;
@@ -1308,7 +1337,7 @@ bool Encoder::create_slot_image(lava::device_ptr device, EncoderFrame::Ptr frame
     return true;
 }
 
-bool Encoder::create_output_buffer(lava::device_ptr device, EncoderFrame::Ptr frame)
+bool VulkanEncoder::create_output_buffer(lava::device_ptr device, VulkanEncoderFrame::Ptr frame)
 {
     VkVideoProfileListInfoKHR profile_list;
     profile_list.sType = VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR;
@@ -1374,7 +1403,7 @@ bool Encoder::create_output_buffer(lava::device_ptr device, EncoderFrame::Ptr fr
     return true;
 }
 
-bool Encoder::create_convert_pass(lava::device_ptr device, EncoderFrame::Ptr frame)
+bool VulkanEncoder::create_convert_pass(lava::device_ptr device, VulkanEncoderFrame::Ptr frame)
 {
     VkClearValue luma_clear_value;
     luma_clear_value.color.float32[0] = 0.0f;
@@ -1453,7 +1482,7 @@ bool Encoder::create_convert_pass(lava::device_ptr device, EncoderFrame::Ptr fra
     return true;
 }
 
-bool Encoder::create_convert_pipeline(lava::device_ptr device, EncoderFrame::Ptr frame)
+bool VulkanEncoder::create_convert_pipeline(lava::device_ptr device, VulkanEncoderFrame::Ptr frame)
 {
     VkPipelineColorBlendAttachmentState luma_blend_state;
     luma_blend_state.blendEnable = VK_FALSE;
@@ -1507,7 +1536,7 @@ bool Encoder::create_convert_pipeline(lava::device_ptr device, EncoderFrame::Ptr
     return true;
 }
 
-bool Encoder::create_subsample_pass(lava::device_ptr device, EncoderFrame::Ptr frame)
+bool VulkanEncoder::create_subsample_pass(lava::device_ptr device, VulkanEncoderFrame::Ptr frame)
 {
     VkClearValue chroma_clear_value;
     chroma_clear_value.color.float32[0] = 0.0f;
@@ -1567,7 +1596,7 @@ bool Encoder::create_subsample_pass(lava::device_ptr device, EncoderFrame::Ptr f
     return true;
 }
 
-bool Encoder::create_subsample_pipeline(lava::device_ptr device, EncoderFrame::Ptr frame)
+bool VulkanEncoder::create_subsample_pipeline(lava::device_ptr device, VulkanEncoderFrame::Ptr frame)
 {
     VkPipelineColorBlendAttachmentState chroma_blend_state;
     chroma_blend_state.blendEnable = VK_FALSE;
@@ -1629,7 +1658,7 @@ bool Encoder::create_subsample_pipeline(lava::device_ptr device, EncoderFrame::P
     return true;
 }
 
-bool Encoder::create_encode_resources(lava::device_ptr device, asio::executor executor, EncoderFrame::Ptr frame)
+bool VulkanEncoder::create_encode_resources(lava::device_ptr device, asio::executor executor, VulkanEncoderFrame::Ptr frame)
 {
     frame->encode_fence = make_extern_fence();
 
@@ -1668,7 +1697,7 @@ bool Encoder::create_encode_resources(lava::device_ptr device, asio::executor ex
     return true;
 }
 
-void Encoder::destroy_session(lava::device_ptr device)
+void VulkanEncoder::destroy_session(lava::device_ptr device)
 {
     vkDestroyVideoSessionKHR(device->get(), this->video_session, lava::memory::alloc());
     vkDestroyVideoSessionParametersKHR(device->get(), this->video_session_paremeters, lava::memory::alloc());
@@ -1681,7 +1710,7 @@ void Encoder::destroy_session(lava::device_ptr device)
     this->video_session_memory.clear();
 }
 
-void Encoder::destroy_resources(lava::device_ptr device)
+void VulkanEncoder::destroy_resources(lava::device_ptr device)
 {
     vkDestroySampler(device->get(), this->sampler, lava::memory::alloc());
     vkDestroyCommandPool(device->get(), this->command_pool, lava::memory::alloc());
@@ -1692,7 +1721,7 @@ void Encoder::destroy_resources(lava::device_ptr device)
     this->pipeline_layout->destroy();
 }
 
-void Encoder::destroy_frame(lava::device_ptr device, EncoderFrame::Ptr frame)
+void VulkanEncoder::destroy_frame(lava::device_ptr device, VulkanEncoderFrame::Ptr frame)
 {
     vkDestroyImageView(device->get(), frame->input_view_luma, lava::memory::alloc());
     vkDestroyImageView(device->get(), frame->input_view_chroma, lava::memory::alloc());
@@ -1731,7 +1760,7 @@ void Encoder::destroy_frame(lava::device_ptr device, EncoderFrame::Ptr frame)
     frame->encode_fence->destroy(device);
 }
 
-bool Encoder::check_encode_support(lava::device_ptr device, const lava::queue& queue) const
+bool VulkanEncoder::check_encode_support(lava::device_ptr device, const lava::queue& queue) const
 {
     uint32_t property_count = 0;
     vkGetPhysicalDeviceQueueFamilyProperties2(device->get_physical_device()->get(), &property_count, nullptr);
@@ -1759,7 +1788,7 @@ bool Encoder::check_encode_support(lava::device_ptr device, const lava::queue& q
     return false;
 }
 
-bool Encoder::check_format_support(lava::device_ptr device, VkImageUsageFlags usage, VkFormat format) const
+bool VulkanEncoder::check_format_support(lava::device_ptr device, VkImageUsageFlags usage, VkFormat format) const
 {
     VkVideoProfileListInfoKHR video_profiles;
     video_profiles.sType = VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR;
@@ -1804,17 +1833,17 @@ bool Encoder::check_format_support(lava::device_ptr device, VkImageUsageFlags us
     return false;
 }
 
-void Encoder::convert_pass(VkCommandBuffer command_buffer)
+void VulkanEncoder::convert_pass(VkCommandBuffer command_buffer)
 {
     vkCmdDraw(command_buffer, 4, 1, 0, 0); //Draw fullscreen quad
 }
 
-void Encoder::subsample_pass(VkCommandBuffer command_buffer)
+void VulkanEncoder::subsample_pass(VkCommandBuffer command_buffer)
 {
     vkCmdDraw(command_buffer, 4, 1, 0, 0); //Draw fullscreen quad
 }
 
-void Encoder::encode_pass_control_setup(VkCommandBuffer command_buffer, EncoderFrame::Ptr frame)
+void VulkanEncoder::encode_pass_control_setup(VkCommandBuffer command_buffer, VulkanEncoderFrame::Ptr frame)
 {
     VkVideoBeginCodingInfoKHR begin_info;
     begin_info.sType = VK_STRUCTURE_TYPE_VIDEO_BEGIN_CODING_INFO_KHR;
@@ -1837,7 +1866,7 @@ void Encoder::encode_pass_control_setup(VkCommandBuffer command_buffer, EncoderF
     vkCmdEndVideoCodingKHR(command_buffer, &end_info);
 }
 
-void Encoder::encode_pass_control_command(VkCommandBuffer command_buffer, EncoderFrame::Ptr frame)
+void VulkanEncoder::encode_pass_control_command(VkCommandBuffer command_buffer, VulkanEncoderFrame::Ptr frame)
 {
     VkVideoEncodeH264RateControlLayerInfoEXT codec_layer_info;
     codec_layer_info.sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_RATE_CONTROL_LAYER_INFO_EXT;
@@ -1897,7 +1926,7 @@ void Encoder::encode_pass_control_command(VkCommandBuffer command_buffer, Encode
     this->invalidate_slots();
 }
 
-void Encoder::encode_pass_config_setup(VkCommandBuffer command_buffer, EncoderFrame::Ptr frame)
+void VulkanEncoder::encode_pass_config_setup(VkCommandBuffer command_buffer, VulkanEncoderFrame::Ptr frame)
 {
     VkVideoBeginCodingInfoKHR begin_info;
     begin_info.sType = VK_STRUCTURE_TYPE_VIDEO_BEGIN_CODING_INFO_KHR;
@@ -1951,7 +1980,7 @@ void Encoder::encode_pass_config_setup(VkCommandBuffer command_buffer, EncoderFr
     vkCmdPipelineBarrier2KHR(command_buffer, &buffer_dependency);
 }
 
-void Encoder::encode_pass_config_command(VkCommandBuffer command_buffer, EncoderFrame::Ptr frame)
+void VulkanEncoder::encode_pass_config_command(VkCommandBuffer command_buffer, VulkanEncoderFrame::Ptr frame)
 {
     VkVideoPictureResourceInfoKHR input_resource;
     input_resource.sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR;
@@ -1988,9 +2017,9 @@ void Encoder::encode_pass_config_command(VkCommandBuffer command_buffer, Encoder
     vkCmdEncodeVideoKHR(command_buffer, &encode_info);
 }
 
-void Encoder::encode_pass_frame_setup(VkCommandBuffer command_buffer, EncoderFrame::Ptr frame)
+void VulkanEncoder::encode_pass_frame_setup(VkCommandBuffer command_buffer, VulkanEncoderFrame::Ptr frame)
 {
-    std::vector<EncoderFrame::Ptr> reference_slots;
+    std::vector<VulkanEncoderFrame::Ptr> reference_slots;
     this->process_slots(frame, reference_slots);
 
     VkImageSubresourceRange image_range;
@@ -2037,7 +2066,7 @@ void Encoder::encode_pass_frame_setup(VkCommandBuffer command_buffer, EncoderFra
 
     for (uint32_t index = 0; index < reference_slots.size(); index++)
     {
-        EncoderFrame::Ptr reference_slot = reference_slots[index];
+        VulkanEncoderFrame::Ptr reference_slot = reference_slots[index];
 
         VkImageMemoryBarrier2& slot_barrier = slot_barriers[index + 2];
         slot_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2;
@@ -2135,7 +2164,7 @@ void Encoder::encode_pass_frame_setup(VkCommandBuffer command_buffer, EncoderFra
     vkCmdPipelineBarrier2KHR(command_buffer, &buffer_dependency);
 }
 
-void Encoder::encode_pass_frame_command(VkCommandBuffer command_buffer, EncoderFrame::Ptr frame, const std::vector<EncoderFrame::Ptr>& reference_slots)
+void VulkanEncoder::encode_pass_frame_command(VkCommandBuffer command_buffer, VulkanEncoderFrame::Ptr frame, const std::vector<VulkanEncoderFrame::Ptr>& reference_slots)
 {
     VkOffset2D encode_offset;
     encode_offset.x = 0;
@@ -2180,7 +2209,7 @@ void Encoder::encode_pass_frame_command(VkCommandBuffer command_buffer, EncoderF
 
     for (uint32_t index = 0; index < reference_slots.size(); index++)
     {
-        EncoderFrame::Ptr reference_slot = reference_slots[index];
+        VulkanEncoderFrame::Ptr reference_slot = reference_slots[index];
 
         VkVideoPictureResourceInfoKHR& slot_resource = reference_slot_resources[index];
         slot_resource.sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR;
@@ -2295,13 +2324,13 @@ void Encoder::encode_pass_frame_command(VkCommandBuffer command_buffer, EncoderF
     vkCmdEncodeVideoKHR(command_buffer, &encode_info);
 }
 
-void Encoder::setup_slots()
+void VulkanEncoder::setup_slots()
 {
     this->frame_slots.resize(this->setting_reference_frames + 1);
     this->invalidate_slots();
 }
 
-void Encoder::process_slots(EncoderFrame::Ptr frame, std::vector<EncoderFrame::Ptr>& reference_slots)
+void VulkanEncoder::process_slots(VulkanEncoderFrame::Ptr frame, std::vector<VulkanEncoderFrame::Ptr>& reference_slots)
 {
     if (this->is_key_frame())
     {
@@ -2342,7 +2371,7 @@ void Encoder::process_slots(EncoderFrame::Ptr frame, std::vector<EncoderFrame::P
 
     reference_slots.clear();
 
-    for (EncoderFrame::Ptr slot : this->frame_slots)
+    for (VulkanEncoderFrame::Ptr slot : this->frame_slots)
     {
         if (slot != nullptr && slot != frame)
         {
@@ -2350,7 +2379,7 @@ void Encoder::process_slots(EncoderFrame::Ptr frame, std::vector<EncoderFrame::P
         }
     }
 
-    std::sort(reference_slots.begin(), reference_slots.end(), [](EncoderFrame::Ptr frame1, EncoderFrame::Ptr frame2)
+    std::sort(reference_slots.begin(), reference_slots.end(), [](VulkanEncoderFrame::Ptr frame1, VulkanEncoderFrame::Ptr frame2)
     {
         return frame1->frame_index > frame2->frame_index;
     });
@@ -2359,7 +2388,7 @@ void Encoder::process_slots(EncoderFrame::Ptr frame, std::vector<EncoderFrame::P
     reference_slots.resize(reference_count);
 }
 
-void Encoder::invalidate_slots()
+void VulkanEncoder::invalidate_slots()
 {
     for (uint32_t index = 0; index < this->frame_slots.size(); index++)
     {
@@ -2367,14 +2396,24 @@ void Encoder::invalidate_slots()
     }
 }
 
-bool Encoder::is_key_frame() const
+bool VulkanEncoder::is_key_frame() const
 {
     return (this->frame_index % this->setting_key_rate) == 0;
 }
 
 VkPhysicalDeviceSynchronization2Features sync_feature;
 
-bool setup_encoder(lava::device::create_param& parameters)
+bool setup_instance_for_vulkan_encoder(lava::frame_config& config)
+{
+    if (config.info.req_api_version < lava::api_version::v1_1)
+    {
+        config.info.req_api_version = lava::api_version::v1_1;
+    }
+
+    return true;
+}
+
+bool setup_device_for_vulkan_encoder(lava::device::create_param& parameters)
 {
     parameters.extensions.push_back(VK_KHR_VIDEO_QUEUE_EXTENSION_NAME);
     parameters.extensions.push_back(VK_KHR_VIDEO_ENCODE_QUEUE_EXTENSION_NAME);
@@ -2386,19 +2425,9 @@ bool setup_encoder(lava::device::create_param& parameters)
     parameters.add_queue(VK_QUEUE_VIDEO_ENCODE_BIT_KHR);
 
     sync_feature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES;
-    sync_feature.pNext = (void*)parameters.next;
+    sync_feature.pNext = (void*) parameters.next;
     sync_feature.synchronization2 = VK_TRUE;
     parameters.next = &sync_feature;
 
     return true;
-}
-
-Encoder::Ptr make_encoder()
-{
-    return std::make_shared<Encoder>();
-}
-
-EncoderFrame::Ptr make_encoder_frame()
-{
-    return std::make_shared<EncoderFrame>();
 }
\ No newline at end of file
diff --git a/src/utility/encoder.hpp b/src/encoder/vulkan_encoder.hpp
similarity index 54%
rename from src/utility/encoder.hpp
rename to src/encoder/vulkan_encoder.hpp
index 4e221f85d39a4e64cd12d31b43284998c5c05ac9..78a18994798c3c1d51445482a207619b4a3f7af8 100644
--- a/src/utility/encoder.hpp
+++ b/src/encoder/vulkan_encoder.hpp
@@ -1,60 +1,28 @@
-/*
-  The encoder can be used to create a h264 stream out of a sequence of images.
-  In order to be able to use the encoder, it is neccessary to call the function setup_encoder(...) during the setup of the vulkan device.
-  Besides that, the requested vulkan version has to be set to Vulkan 1.1 during the setup of the vulkan instance.
-  A frame can be submitted for encoding using the function encode_frame(...).
-  After the completion of an encode task, a callback function is executed to which the resulting ouput of the task is passed.
-  Example:
-
-   //During on_setup_instance(...)
-   req_api_version = lava::api_version::v1_1;
-
-   //During on_setup_device(...)
-   setup_encoder(...);
-
-   //During creation and submission of a frame
-   Encoder::Ptr encoder = make_encoder();
-
-   encoder->create(...);
-
-   encoder->encoder_frame(..., image, ..., [](const std::span<uint8_t>& content, EncoderFrameType type)
-   {
-        //Use content
-   });
-*/
-
 #pragma once
 #include <liblava/lava.hpp>
 #include <asio.hpp>
+#include <thread>
+#include <mutex>
+#include <functional>
 #include <optional>
 #include <vector>
 #include <span>
 #include <memory>
-#include <mutex>
-#include <functional>
-#include <optional>
 
-#include "extern_fence.hpp"
+#include "encoder.hpp"
+#include "utility/extern_fence.hpp"
 
-enum EncoderMode
+enum VulkanEncoderFrameType
 {
-    ENCODER_MODE_CONSTANT_BITRATE,
-    ENCODER_MODE_CONSTANT_QUALITY
+    VULKAN_ENCODER_FRAME_TYPE_CONTROL,
+    VULKAN_ENCODER_FRAME_TYPE_CONFIG,
+    VULKAN_ENCODER_FRAME_TYPE_FRAME
 };
 
-enum EncoderFrameType
-{
-    ENCODER_FRAME_TYPE_CONTROL,
-    ENCODER_FRAME_TYPE_CONFIG,
-    ENCODER_FRAME_TYPE_FRAME
-};
-
-typedef std::function<void(const std::span<uint8_t>& content, EncoderFrameType type)> EncoderCallback;
-
-struct EncoderFrame
+struct VulkanEncoderFrame
 {
 public:
-    typedef std::shared_ptr<EncoderFrame> Ptr;
+    typedef std::shared_ptr<VulkanEncoderFrame> Ptr;
 
 public:
     VmaAllocation input_memory_combined;
@@ -97,47 +65,48 @@ public:
     ExternFence::Ptr encode_fence;
 
     uint32_t frame_index = 0;
-    EncoderFrameType type;
-    EncoderCallback callback;
+    VulkanEncoderFrameType type;
+    Encoder::OnEncodeComplete callback;
 };
 
-class Encoder
+class VulkanEncoder : public Encoder
 {
 public:
-    typedef std::shared_ptr<Encoder> Ptr;
+    typedef std::shared_ptr<VulkanEncoder> Ptr;
 
 public:
-    Encoder() = default;
+    VulkanEncoder() = default;
 
-    bool create(lava::device_ptr device, const lava::renderer& renderer, asio::executor executor, const glm::uvec2& size, uint32_t frame_count);
-    //NOTE: Assume all async operations has been completed.
+    bool create(lava::device_ptr device, const lava::renderer& renderer, const glm::uvec2& size, uint32_t input_buffers);
     void destroy();
 
+    bool encode(VkCommandBuffer command_buffer, lava::renderer& renderer, lava::image::ptr image, VkImageLayout image_layout, OnEncodeComplete function);
+
+    void set_on_encode_error(OnEncodeError function);
+
     void set_mode(EncoderMode mode);
-    //NOTE: The number of frames between two key frames.
+    void set_quality(double quality);
+    void set_bitrate(double bitrate);
     void set_key_rate(uint32_t key_rate);
-    //NOTE: The bit rate in Mbit per second.
-    void set_bit_rate(double bit_rate);
-    //NOTE: The frame rate in frames per second.
     void set_frame_rate(uint32_t frame_rate);
-    //NOTE: The quality of i-frames in range from 0 to 51, where 0 means a lowest compression and 51 means highest compression.
-    void set_quality_iframe(uint32_t quality);
-    //NOTE: The quality of p-frames in range from 0 to 51, where 0 means a lowest compression and 51 means highest compression.
-    void set_quality_pframe(uint32_t quality);
 
-    bool encode_frame(VkCommandBuffer command_buffer, lava::renderer& renderer, lava::image::ptr image, VkImageLayout image_layout, EncoderCallback callback);
+    EncoderMode get_mode() const;
+    double get_quality() const;
+    double get_bitrate() const;
+    uint32_t get_key_rate() const;
+    uint32_t get_frame_rate() const;
 
 private:
-    bool encode_control(lava::renderer& renderer, EncoderCallback callback);
-    bool encode_config(lava::renderer& renderer, EncoderCallback callback);
+    bool encode_control(lava::renderer& renderer, OnEncodeComplete callback);
+    bool encode_config(lava::renderer& renderer, OnEncodeComplete callback);
 
-    bool aquire_frame(EncoderFrame::Ptr& frame);
-    void release_frame(EncoderFrame::Ptr frame);
-    bool submit_frame(lava::device_ptr device, EncoderFrame::Ptr frame, lava::renderer& renderer);
+    bool aquire_frame(VulkanEncoderFrame::Ptr& frame);
+    void release_frame(VulkanEncoderFrame::Ptr frame);
+    bool submit_frame(lava::device_ptr device, VulkanEncoderFrame::Ptr frame, lava::renderer& renderer);
 
-    void write_image(lava::device_ptr device, EncoderFrame::Ptr frame, lava::image::ptr image);
-    bool record_encoding(lava::device_ptr device, EncoderFrame::Ptr frame);
-    void retrive_encoding(lava::device_ptr device, EncoderFrame::Ptr frame);
+    void write_image(lava::device_ptr device, VulkanEncoderFrame::Ptr frame, lava::image::ptr image);
+    bool record_encoding(lava::device_ptr device, VulkanEncoderFrame::Ptr frame);
+    void retrive_encoding(lava::device_ptr device, VulkanEncoderFrame::Ptr frame);
 
     bool create_profiles(lava::device_ptr device);
     bool compute_settings(const glm::uvec2& size);
@@ -153,19 +122,19 @@ private:
     bool create_image_memory(lava::device_ptr device, VkImage image, VkImageAspectFlagBits image_aspect, VmaAllocation& memory);
     bool create_image_view(lava::device_ptr device, VkImage image, VkFormat image_format, VkImageView& image_view);
 
-    bool create_input_images(lava::device_ptr device, EncoderFrame::Ptr frame);
-    bool create_slot_image(lava::device_ptr device, EncoderFrame::Ptr frame);
-    bool create_output_buffer(lava::device_ptr device, EncoderFrame::Ptr frame);
+    bool create_input_images(lava::device_ptr device, VulkanEncoderFrame::Ptr frame);
+    bool create_slot_image(lava::device_ptr device, VulkanEncoderFrame::Ptr frame);
+    bool create_output_buffer(lava::device_ptr device, VulkanEncoderFrame::Ptr frame);
 
-    bool create_convert_pass(lava::device_ptr device, EncoderFrame::Ptr frame);
-    bool create_convert_pipeline(lava::device_ptr device, EncoderFrame::Ptr frame);
-    bool create_subsample_pass(lava::device_ptr device, EncoderFrame::Ptr frame);
-    bool create_subsample_pipeline(lava::device_ptr device, EncoderFrame::Ptr frame);
-    bool create_encode_resources(lava::device_ptr device, asio::executor executor, EncoderFrame::Ptr frame);
+    bool create_convert_pass(lava::device_ptr device, VulkanEncoderFrame::Ptr frame);
+    bool create_convert_pipeline(lava::device_ptr device, VulkanEncoderFrame::Ptr frame);
+    bool create_subsample_pass(lava::device_ptr device, VulkanEncoderFrame::Ptr frame);
+    bool create_subsample_pipeline(lava::device_ptr device, VulkanEncoderFrame::Ptr frame);
+    bool create_encode_resources(lava::device_ptr device, asio::executor executor, VulkanEncoderFrame::Ptr frame);
 
     void destroy_session(lava::device_ptr device);
     void destroy_resources(lava::device_ptr device);
-    void destroy_frame(lava::device_ptr device, EncoderFrame::Ptr frame);
+    void destroy_frame(lava::device_ptr device, VulkanEncoderFrame::Ptr frame);
 
     bool check_encode_support(lava::device_ptr device, const lava::queue& queue) const;
     bool check_format_support(lava::device_ptr device, VkImageUsageFlags usage, VkFormat format) const;
@@ -173,15 +142,15 @@ private:
     void convert_pass(VkCommandBuffer command_buffer);
     void subsample_pass(VkCommandBuffer command_buffer);
 
-    void encode_pass_control_setup(VkCommandBuffer command_buffer, EncoderFrame::Ptr frame);
-    void encode_pass_control_command(VkCommandBuffer command_buffer, EncoderFrame::Ptr frame);
-    void encode_pass_config_setup(VkCommandBuffer command_buffer, EncoderFrame::Ptr frame);
-    void encode_pass_config_command(VkCommandBuffer command_buffer, EncoderFrame::Ptr frame);
-    void encode_pass_frame_setup(VkCommandBuffer command_buffer, EncoderFrame::Ptr frame);
-    void encode_pass_frame_command(VkCommandBuffer command_buffer, EncoderFrame::Ptr frame, const std::vector<EncoderFrame::Ptr>& reference_slots);
+    void encode_pass_control_setup(VkCommandBuffer command_buffer, VulkanEncoderFrame::Ptr frame);
+    void encode_pass_control_command(VkCommandBuffer command_buffer, VulkanEncoderFrame::Ptr frame);
+    void encode_pass_config_setup(VkCommandBuffer command_buffer, VulkanEncoderFrame::Ptr frame);
+    void encode_pass_config_command(VkCommandBuffer command_buffer, VulkanEncoderFrame::Ptr frame);
+    void encode_pass_frame_setup(VkCommandBuffer command_buffer, VulkanEncoderFrame::Ptr frame);
+    void encode_pass_frame_command(VkCommandBuffer command_buffer, VulkanEncoderFrame::Ptr frame, const std::vector<VulkanEncoderFrame::Ptr>& reference_slots);
 
     void setup_slots();
-    void process_slots(EncoderFrame::Ptr frame, std::vector<EncoderFrame::Ptr>& reference_slots);
+    void process_slots(VulkanEncoderFrame::Ptr frame, std::vector<VulkanEncoderFrame::Ptr>& reference_slots);
     void invalidate_slots();
 
     bool is_key_frame() const;
@@ -208,6 +177,9 @@ private:
     uint32_t setting_buffer_size;
 
 private:
+    std::thread worker_thread;
+    asio::io_context worker_executor;
+
     VkSampler sampler = nullptr;
     VkCommandPool command_pool = nullptr;
     VkQueryPool query_pool = nullptr;
@@ -219,9 +191,11 @@ private:
     VkSemaphore previous_semaphore = VK_NULL_HANDLE;
 
     std::mutex frame_mutex;
-    std::vector<EncoderFrame::Ptr> frame_queue; //NOTE: Protected by frame_mutex
-    std::vector<EncoderFrame::Ptr> frame_list;
-    std::vector<EncoderFrame::Ptr> frame_slots;
+    std::vector<VulkanEncoderFrame::Ptr> frame_queue; //NOTE: Protected by frame_mutex
+    std::vector<VulkanEncoderFrame::Ptr> frame_list;
+    std::vector<VulkanEncoderFrame::Ptr> frame_slots;
+    
+    OnEncodeError on_encode_error;
 
 private:
     lava::queue default_queue;
@@ -243,7 +217,5 @@ private:
     const uint8_t picture_parameter_id = 0;
 };
 
-bool setup_encoder(lava::device::create_param& parameters);
-
-Encoder::Ptr make_encoder();
-EncoderFrame::Ptr make_encoder_frame();
\ No newline at end of file
+bool setup_instance_for_vulkan_encoder(lava::frame_config& config);
+bool setup_device_for_vulkan_encoder(lava::device::create_param& parameters);
\ No newline at end of file
diff --git a/src/headset/remote_headset.cpp b/src/headset/remote_headset.cpp
index 61e57da81c95e889b03f810b55f2b493f3a80bc6..22bda66a2d834532ef623f408f8608ccd93ee412 100644
--- a/src/headset/remote_headset.cpp
+++ b/src/headset/remote_headset.cpp
@@ -17,23 +17,27 @@ RemoteHeadset::RemoteHeadset()
 
 bool RemoteHeadset::on_setup_instance(lava::frame_config& config)
 {
-    // Required in oder to get:
-    // VK_KHR_external_fence,
-    // VK_KHR_external_fence_capabilities,
-    // VK_KHR_get_physical_device_properties2
-    config.info.req_api_version = lava::api_version::v1_1;
+    if (!setup_instance_for_extern_fence(config))
+    {
+        return false;
+    }
+
+    if (!setup_instance_for_encoder(this->get_application()->get_command_parser().get_encoder(), config))
+    {
+        return false;
+    }
 
     return true;
 }
 
 bool RemoteHeadset::on_setup_device(lava::device::create_param& parameters)
 {
-    if (!setup_extern_fence(this->get_application()->get_instance(), parameters.extensions))
+    if (!setup_device_for_extern_fence(this->get_application()->get_instance(), parameters))
     {
         return false;
     }
 
-    if (!setup_encoder(parameters))
+    if (!setup_device_for_encoder(this->get_application()->get_command_parser().get_encoder(), parameters))
     {
         return false;
     }
@@ -147,7 +151,7 @@ bool RemoteHeadset::on_interface()
         {
             for (Encoder::Ptr encoder : this->encoders)
             {
-                encoder->set_bit_rate(this->encoder_bit_rate * 1000);
+                encoder->set_bitrate(this->encoder_bit_rate * 1000);
             }
         }
 
@@ -162,19 +166,11 @@ bool RemoteHeadset::on_interface()
 
     else if (this->encoder_mode == ENCODER_MODE_CONSTANT_QUALITY)
     {
-        if (ImGui::SliderInt("Quality I-Frame", (int32_t*)&this->encoder_quality_iframe, 1, 51))
+        if (ImGui::SliderFloat("Quality", &this->encoder_quality, 0.0, 1.0))
         {
             for (Encoder::Ptr encoder : this->encoders)
             {
-                encoder->set_quality_iframe(this->encoder_quality_iframe);
-            }
-        }
-
-        if (ImGui::SliderInt("Quality P-Frame", (int32_t*)&this->encoder_quality_pframe, 1, 51))
-        {
-            for (Encoder::Ptr encoder : this->encoders)
-            {
-                encoder->set_quality_pframe(this->encoder_quality_pframe);
+                encoder->set_quality(this->encoder_quality);
             }
         }
     }
@@ -258,19 +254,16 @@ void RemoteHeadset::submit_frame(VkCommandBuffer command_buffer, VkImageLayout f
     uint32_t transform_id = this->transform_id;
 
     pass_timer->begin_pass(command_buffer, "Encode Setup " + std::to_string(frame_id));
-    bool result = encoder->encode_frame(command_buffer, renderer, framebuffer, frame_layout, [this, frame_number, frame_id, transform_id](const std::span<uint8_t>& content, EncoderFrameType type)
+    bool result = encoder->encode(command_buffer, renderer, framebuffer, frame_layout, [this, frame_number, frame_id, transform_id](const std::span<uint8_t>& content, bool is_config)
     {
-        switch (type)
+        if (is_config)
         {
-        case ENCODER_FRAME_TYPE_CONFIG:
             this->transport->send_frame_config_nal(frame_id, content);
-            break;
-        case ENCODER_FRAME_TYPE_FRAME:
+        }
+
+        else
+        {
             this->transport->send_frame_nal(frame_number, frame_id, transform_id, content);
-            break;
-        case ENCODER_FRAME_TYPE_CONTROL:
-        default:
-            break;
         }
     });
     pass_timer->end_pass(command_buffer);
@@ -446,24 +439,28 @@ bool RemoteHeadset::create_encoders()
 
     for (uint32_t index = 0; index < this->encoders.size(); index++)
     {
-        Encoder::Ptr encoder = make_encoder();
+        Encoder::Ptr encoder = make_encoder(this->get_application()->get_command_parser().get_encoder());
+
+        encoder->set_on_encode_error([this]()
+        {
+            this->on_encode_error();
+        });
+
+        encoder->set_mode((EncoderMode) this->encoder_mode);
+        encoder->set_quality(this->encoder_quality);
+        encoder->set_bitrate(this->encoder_bit_rate);
+        encoder->set_key_rate(this->encoder_key_rate);
+        encoder->set_frame_rate(this->encoder_frame_rate);
 
         lava::device_ptr device = this->get_application()->get_device();
         lava::renderer& renderer = this->get_application()->get_renderer();
         uint32_t frame_count = this->get_application()->get_frame_count();
 
-        if (!encoder->create(device, renderer, this->transport->get_context().get_executor(), this->resolution, frame_count))
+        if (!encoder->create(device, renderer, this->resolution, frame_count))
         {
             return false;
         }
 
-        encoder->set_mode((EncoderMode)this->encoder_mode);
-        encoder->set_key_rate(this->encoder_key_rate);
-        encoder->set_bit_rate(this->encoder_bit_rate);
-        encoder->set_frame_rate(this->encoder_frame_rate);
-        encoder->set_quality_iframe(this->encoder_quality_iframe);
-        encoder->set_quality_pframe(this->encoder_quality_pframe);
-
         this->encoders[index] = encoder;
     }
 
@@ -612,6 +609,11 @@ void RemoteHeadset::on_transport_error()
     lava::log()->error("Remote Headset: Transport error detected!");
 }
 
+void RemoteHeadset::on_encode_error()
+{
+    lava::log()->error("Remote Headset: Encode error detected!");
+}
+
 bool RemoteHeadset::convert_strategy(StereoStrategyType strategy_type, PacketStereoStrategyId& strategy_id)
 {
     switch (strategy_type)
diff --git a/src/headset/remote_headset.hpp b/src/headset/remote_headset.hpp
index 0719de7f9f884c5b3bdd666c7735107f12de75d0..bbb492460333ec4ffba5b14b9e9b9ec454dbd83e 100644
--- a/src/headset/remote_headset.hpp
+++ b/src/headset/remote_headset.hpp
@@ -8,11 +8,11 @@
 #include <chrono>
 
 #include "headset.hpp"
-#include "strategy/stereo_strategy.hpp"
 
+#include "strategy/stereo_strategy.hpp"
 #include "stream/transport.hpp"
+#include "encoder/encoder.hpp"
 
-#include "utility/encoder.hpp"
 #include "utility/extern_fence.hpp"
 #include "utility/latency.hpp"
 
@@ -73,6 +73,7 @@ private:
     void on_controller_thumbstick(PacketControllerId controller_id, const glm::vec2& thumbstick);
     void on_latency(PacketFrameNumber frame_number, PacketFrameId frame_id, PacketTransformId transform_id, double timestamp_transform_query, double timestamp_server_response, double timestamp_frame_decoded, double timestamp_command_construct, double timestamp_command_executed);
     void on_transport_error();
+    void on_encode_error();
 
     static bool convert_strategy(StereoStrategyType strategy_type, PacketStereoStrategyId& strategy_id);
 
@@ -116,8 +117,7 @@ private:
     uint32_t encoder_input_rate = 90;
     uint32_t encoder_key_rate = 90;
     uint32_t encoder_frame_rate = 90;
-    uint32_t encoder_quality_iframe = 45;
-    uint32_t encoder_quality_pframe = 45;
+    float encoder_quality = 0.0;
     float encoder_bit_rate = 8.0;               //NOTE: Bitrate in Mbit per seconds
     float encoder_last_submit = 0.0f;
     bool encoder_enable_submit = true;
diff --git a/src/stream/transport.hpp b/src/stream/transport.hpp
index 1fd57a1994c1073cd6f1997007cca95ed0a5bde4..9aa0dbe108358d20874d3a29079f97ac6afcbcb4 100644
--- a/src/stream/transport.hpp
+++ b/src/stream/transport.hpp
@@ -117,7 +117,7 @@ private:
     uint32_t bits_received = 0;                           //NOTE: Owned by worker_thread
     double bitrate_send = 0.0;                            //NOTE: Protected by worker_mutex
     double bitrate_received = 0.0;                        //NOTE: Protected by worker_mutex
-    //double max_bitrate_send = 1.0;                        //NOTE: Protected by worker_mutex
+    //double max_bitrate_send = 1.0;                      //NOTE: Protected by worker_mutex
     uint32_t max_send_queue_size = DATAGRAM_SIZE * 128;   //NOTE: Protected by worker_mutex
     bool send_active = false;                             //NOTE: Protected by worker_mutex
     double inactive_time = 0.0;                           //NOTE: Owned by worker_thread
diff --git a/src/utility/command_parser.cpp b/src/utility/command_parser.cpp
index 766e860d29bc4fe21ca8bcbe2908e0c99db636d8..33680e700232e3b4edffe73f86d44710c27748a5 100644
--- a/src/utility/command_parser.cpp
+++ b/src/utility/command_parser.cpp
@@ -74,6 +74,14 @@ bool CommandParser::parse_command(const argh::parser& cmd_line)
             }
         }
 
+        else if (parameter.first == "encoder")
+        {
+            if (!this->set_encoder(parameter.second))
+            {
+                return false;
+            }
+        }
+
         else if (parameter.first == "animation")
         {
             this->animation_name = parameter.second;
@@ -213,6 +221,11 @@ StereoStrategyType CommandParser::get_stereo_strategy() const
     return this->stereo_strategy;
 }
 
+EncoderType CommandParser::get_encoder() const
+{
+    return this->encoder;
+}
+
 SceneUnit CommandParser::get_scene_unit() const
 {
     return this->scene_unit;
@@ -278,12 +291,14 @@ void CommandParser::show_help()
     std::cout << "                                        If no file is specified, sky stays black." << std::endl;
     std::cout << "   --scene-unit={unit}                  The unit in which the geometry of the scene is defined." << std::endl;
     std::cout << "                                        Options: meters (default), centimeters" << std::endl;
-    std::cout << "   --benchmark                          Play animation once and close program after completion." << std::endl;
-    std::cout << "                                        If not set, the application runs indefinitely and the interface is enabled." << std::endl;
     std::cout << "   --headset={headset}                  The headset that should be used." << std::endl;
     std::cout << "                                        Options: emulated (default), openvr, openxr, remote" << std::endl;
     std::cout << "   --stereo-strategy={strategy}         The stereo strategy that should be used." << std::endl;
     std::cout << "                                        Options: native-forward (default), native-deferred, multi-view, dpr" << std::endl;
+    std::cout << "   --encoder={encoder}                  The encoder that should be used when a remote headset is used." << std::endl;
+    std::cout << "                                        Options: vulkan (default), nvidia" << std::endl;
+    std::cout << "   --benchmark                          Play animation once and close program after completion." << std::endl;
+    std::cout << "                                        If not set, the application runs indefinitely and the interface is enabled." << std::endl;
     std::cout << "   --animation={animation_name}         The name of the animation that should be played." << std::endl;
     std::cout << "                                        This parameter is only allowed during a benchmark." << std::endl;
     std::cout << "   --animation-index={animation_index}  The index of the animation that should be played." << std::endl;
@@ -365,6 +380,28 @@ bool CommandParser::set_stero_strategy(const std::string& name)
     return true;
 }
 
+bool CommandParser::set_encoder(const std::string& name)
+{
+    if (name == "vulkan")
+    {
+        this->encoder = ENCODER_TYPE_VULKAN;
+    }
+
+    else if (name == "nvidia")
+    {
+        this->encoder = ENCODER_TYPE_NVIDIA;
+    }
+
+    else
+    {
+        std::cout << "Invalid option set of parameter 'encoder'. Use option --help to get more information." << std::endl;
+
+        return false;
+    }
+
+    return true;
+}
+
 bool CommandParser::set_scene_unit(const std::string& name)
 {
     if (name == "meters")
diff --git a/src/utility/command_parser.hpp b/src/utility/command_parser.hpp
index 8cc7ea9509db65a27dc2c3b222e3e9f96bc9d477..dddd706599d7b7073b1bd1c5123863971f759f2b 100644
--- a/src/utility/command_parser.hpp
+++ b/src/utility/command_parser.hpp
@@ -11,6 +11,7 @@
 #include "../scene.hpp"
 #include "headset/headset.hpp"
 #include "strategy/stereo_strategy.hpp"
+#include "encoder/encoder.hpp"
 
 class CommandParser
 {
@@ -21,6 +22,7 @@ public:
 
     HeadsetType get_headset() const;
     StereoStrategyType get_stereo_strategy() const;
+    EncoderType get_encoder() const;
     SceneUnit get_scene_unit() const;
 
     const std::string& get_scene_path() const;
@@ -43,11 +45,13 @@ private:
 
     bool set_headset(const std::string& name);
     bool set_stero_strategy(const std::string& name);
+    bool set_encoder(const std::string& name);
     bool set_scene_unit(const std::string& name);
 
 private:
     HeadsetType headset = HEADSET_TYPE_EMULATED;
     StereoStrategyType stereo_strategy = STEREO_STRATEGY_TYPE_NATIVE_FORWARD;
+    EncoderType encoder = ENCODER_TYPE_VULKAN;
     SceneUnit scene_unit = SCENE_UNIT_METERS;
 
     std::string scene_path = "";
diff --git a/src/utility/extern_fence.cpp b/src/utility/extern_fence.cpp
index 1cad711b040ce2128b2752f1fefdd397101e3eaf..b14ef16fb4f692ba89b9966ceaa5d6b9ab20d9c7 100644
--- a/src/utility/extern_fence.cpp
+++ b/src/utility/extern_fence.cpp
@@ -141,15 +141,28 @@ public:
 };
 #endif
 
-bool setup_extern_fence(lava::instance& instance, std::vector<const char*>& extensions)
+bool setup_instance_for_extern_fence(lava::frame_config& config)
+{
+    if (config.info.req_api_version < lava::api_version::v1_1)
+    {
+        // Required in oder to get:
+        // VK_KHR_external_fence,
+        // VK_KHR_external_fence_capabilities
+        config.info.req_api_version = lava::api_version::v1_1;
+    }
+
+    return true;
+}
+
+bool setup_device_for_extern_fence(lava::instance& instance, lava::device::create_param& parameters)
 {
 #if defined(WIN32)
     vkGetFenceWin32HandleKHR = (PFN_vkGetFenceWin32HandleKHR)vkGetInstanceProcAddr(instance.get(), "vkGetFenceWin32HandleKHR");
-    extensions.push_back(VK_KHR_EXTERNAL_FENCE_WIN32_EXTENSION_NAME);
+    parameters.extensions.push_back(VK_KHR_EXTERNAL_FENCE_WIN32_EXTENSION_NAME);
 
     return true;
 #elif defined(__unix__)
-    extensions.push_back(VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME);
+    parameters.extensions.push_back(VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME);
 
     return true;
 #else
diff --git a/src/utility/extern_fence.hpp b/src/utility/extern_fence.hpp
index dd525ea7f35553638c7c7584073ef1fc5835e2a9..fd5d86908f284fab8644f5a588e66350b1ad2412 100644
--- a/src/utility/extern_fence.hpp
+++ b/src/utility/extern_fence.hpp
@@ -1,14 +1,14 @@
 /*
   An extren fence can be used to create a special vulkan fence that can also be used together with asio.
-  In order to be able to use extern fences, it is neccessary to call the function setup_extern_fence(...) during the setup of the vulkan device.
-  Besides that, the requested vulkan version has to be set to Vulkan 1.1 during the setup of the vulkan instance.
+  In order to be able to use extern fences, it is neccessary to call the function setup_instance_for_extern_fence(...) during the setup of the vulkan instance.
+  Besides that, the function setup_device_for_extern_fence(...) has to be called during the setup of the vulkan device.
   Example:
 
    //During on_setup_instance(...)
-   req_api_version = lava::api_version::v1_1;
+   setup_instance_for_extern_fence();
 
    //During on_setup_device(...)
-   setup_extern_fence(...);
+   setup_device_for_extern_fence(...);
 
    //During execution
    ExternFence::Ptr extern_fence = make_extern_fence();
@@ -48,6 +48,7 @@ public:
     VkFence get() const;
 };
 
-bool setup_extern_fence(lava::instance& instance, std::vector<const char*>& extensions);
+bool setup_instance_for_extern_fence(lava::frame_config& config);
+bool setup_device_for_extern_fence(lava::instance& instance, lava::device::create_param& parameters);
 
 ExternFence::Ptr make_extern_fence();
\ No newline at end of file
diff --git a/src/vr_application.cpp b/src/vr_application.cpp
index d01d36c9858ccc0cdb9bdf5811da0144a0847da8..e4f7dec562ec3f02ce4579dbbbc6aa83b4762c3e 100644
--- a/src/vr_application.cpp
+++ b/src/vr_application.cpp
@@ -178,6 +178,11 @@ IndirectCache::Ptr VRApplication::get_indirect_cache() const
     return this->indirect_cache;
 }
 
+const CommandParser& VRApplication::get_command_parser() const
+{
+    return this->command_parser;
+}
+
 lava::device_ptr VRApplication::get_device() const
 {
     return this->app->device;
diff --git a/src/vr_application.hpp b/src/vr_application.hpp
index 5ff7ab6275800a475f67cd4a956a6e8950cebd46..d1cd77da3371449f666df7e401c68e84cdcaeb4a 100644
--- a/src/vr_application.hpp
+++ b/src/vr_application.hpp
@@ -46,6 +46,8 @@ public:
     ShadowCache::Ptr get_shadow_cache() const;
     IndirectCache::Ptr get_indirect_cache() const;
 
+    const CommandParser& get_command_parser() const;
+
     lava::device_ptr get_device() const;
     lava::render_target::ptr get_target() const;