diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 75d507b218f8a8296ecba7448ef8729ce1cf993b..778d11c15273831ee0d6dd214358ce9378760d0e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -28,9 +28,9 @@ linux:
   script:
     - mkdir build
     - cd build
-    - cmake .. -DCMAKE_CXX_FLAGS="-fdiagnostics-color" -DWITH_OPTFLOW=TRUE -DUSE_CPPCHECK=FALSE -DBUILD_CALIBRATION=TRUE -DWITH_CERES=TRUE -DCMAKE_BUILD_TYPE=Release -DCPACK_GENERATOR=DEB
-    - make
-    - make package
+    - /snap/bin/cmake .. -GNinja -DCMAKE_CXX_FLAGS="-fdiagnostics-color" -DWITH_OPTFLOW=TRUE -DUSE_CPPCHECK=FALSE -DBUILD_CALIBRATION=TRUE -DWITH_CERES=TRUE -DCMAKE_BUILD_TYPE=Release -DCPACK_GENERATOR=DEB
+    - ninja
+    - ninja package
     - ctest --output-on-failure
     - cd ../SDK/Python
     - python3 -m unittest discover test
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c876eb84205b251f2b945d9e109927e88b0b6ff7..6c956162961c18ef786883bfdb44edc74b0be44d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 3.1.0)
+cmake_minimum_required (VERSION 3.16.0)
 include (CheckIncludeFile)
 include (CheckIncludeFileCXX)
 include (CheckFunctionExists)
@@ -16,6 +16,7 @@ option(WITH_OPENVR "Build with OpenVR support" OFF)
 option(WITH_OPUS "Use Opus audio compression" ON)
 option(WITH_FIXSTARS "Use Fixstars libSGM" ON)
 option(WITH_CERES "Use Ceres solver" ON)
+option(WITH_SDK "Build the C shared SDK" ON)
 option(USE_CPPCHECK "Apply cppcheck during build" ON)
 option(BUILD_VISION "Enable the vision component" ON)
 option(BUILD_RECONSTRUCT "Enable the reconstruction component" ON)
@@ -163,17 +164,6 @@ add_subdirectory(lib/libstereo)
 include_directories(lib/libstereo/include)
 set_property(TARGET libstereo PROPERTY FOLDER "dependencies")
 
-#
-
-if (WITH_FIXSTARS)
-	set(HAVE_LIBSGM true)
-	add_subdirectory(lib/libsgm)
-	include_directories(lib/libsgm/include)
-	set_property(TARGET sgm PROPERTY FOLDER "dependencies")
-else()
-	add_library(sgm INTERFACE)
-endif()
-
 # ==== Ceres ===================================================================
 
 if (WITH_CERES)
@@ -315,6 +305,7 @@ enable_language(CUDA)
 if (NOT WIN32)
 	set(CMAKE_CUDA_FLAGS "-Xcompiler -fPIC")
 endif()
+set(CMAKE_CUDA_ARCHITECTURES "61")
 set(CMAKE_CUDA_FLAGS_DEBUG "--gpu-architecture=compute_61 -g -DDEBUG -D_DEBUG")
 set(CMAKE_CUDA_FLAGS_RELEASE "--gpu-architecture=compute_61")
 set(HAVE_CUDA TRUE)
@@ -441,6 +432,15 @@ set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
 #	add_library(nvpipe INTERFACE)
 #endif()
 
+if (WITH_FIXSTARS)
+	set(HAVE_LIBSGM true)
+	add_subdirectory(lib/libsgm)
+	include_directories(lib/libsgm/include)
+	set_property(TARGET sgm PROPERTY FOLDER "dependencies")
+else()
+	add_library(sgm INTERFACE)
+endif()
+
 
 add_subdirectory(components/common/cpp)
 #add_subdirectory(applications/calibration)
@@ -460,8 +460,10 @@ add_subdirectory(components/calibration)
 add_subdirectory(applications/tools)
 
 # SDK only compiles on linux currently
-if (NOT WIN32)
-	add_subdirectory(SDK/C)
+if (WITH_SDK)
+	if (NOT WIN32)
+		add_subdirectory(SDK/C)
+	endif()
 endif()
 
 if (HAVE_AVFORMAT)
diff --git a/applications/gui2/CMakeLists.txt b/applications/gui2/CMakeLists.txt
index 60032ebebc0f2dddebc58dd8d70949007bbaf407..7dce75891115c42d423e3d674dc0626f37592ed5 100644
--- a/applications/gui2/CMakeLists.txt
+++ b/applications/gui2/CMakeLists.txt
@@ -73,3 +73,4 @@ target_include_directories(ftl-gui2 PUBLIC
 #target_include_directories(cv-node PUBLIC ${PROJECT_SOURCE_DIR}/include)
 target_link_libraries(ftl-gui2 ftlcommon ftldata ftlctrl ftlrgbd ftlstreams ftlrender Threads::Threads ${OpenCV_LIBS} openvr ftlnet nanogui ${NANOGUI_EXTRA_LIBS} ceres)
 
+target_precompile_headers(ftl-gui2 REUSE_FROM ftldata)
diff --git a/applications/gui2/src/modules/thumbnails.cpp b/applications/gui2/src/modules/thumbnails.cpp
index 52b7b54ef358c6e49c8643060cdc663e0c35020a..14f582233c901269729be23e7923cbbd38cf6b15 100644
--- a/applications/gui2/src/modules/thumbnails.cpp
+++ b/applications/gui2/src/modules/thumbnails.cpp
@@ -27,6 +27,14 @@ ThumbnailsController::~ThumbnailsController() {
 
 }
 
+void ThumbnailsController::removeFrameset(uint32_t id) {
+	{
+		std::unique_lock<std::mutex> lk(mtx_);
+		framesets_.erase(id);
+	}
+	io->feed()->remove(id);
+}
+
 void ThumbnailsController::show_thumbnails() {
 	auto thumb_view = new ftl::gui2::Thumbnails(screen, this);
 
diff --git a/applications/gui2/src/modules/thumbnails.hpp b/applications/gui2/src/modules/thumbnails.hpp
index 353a7e98ff40fcc27d1e39bb47bbae0e9bf47cc2..c24f4641de814670a2523f05091c8e75a614fa34 100644
--- a/applications/gui2/src/modules/thumbnails.hpp
+++ b/applications/gui2/src/modules/thumbnails.hpp
@@ -22,6 +22,8 @@ public:
 
 	std::vector<ftl::data::FrameSetPtr> getFrameSets();
 
+	void removeFrameset(uint32_t id);
+
 private:
 	std::mutex mtx_;
 	std::map<unsigned int, ftl::data::FrameSetPtr> framesets_;
diff --git a/applications/gui2/src/views/thumbnails.cpp b/applications/gui2/src/views/thumbnails.cpp
index c382f8d0b1625bf06a16e7bb4387e4cf65f9aa0c..79c4857d71c4e3d4802ae01cc8341f36d977e8e5 100644
--- a/applications/gui2/src/views/thumbnails.cpp
+++ b/applications/gui2/src/views/thumbnails.cpp
@@ -20,6 +20,9 @@
 #include <nanogui/tabwidget.h>
 #include <nanogui/vscrollpanel.h>
 #include <nanogui/layout.h>
+#include <nanogui/popup.h>
+
+#include <loguru.hpp>
 
 using ftl::gui2::ThumbView;
 using ftl::gui2::Thumbnails;
@@ -58,8 +61,10 @@ ThumbView::ThumbView(nanogui::Widget *parent, ThumbnailsController *control, ftl
 }
 
 bool ThumbView::mouseButtonEvent(const nanogui::Vector2i &p, int button, bool down, int modifiers) {
-	if (!down) {
-		ctrl_->show_camera(id_);
+	if (button == 0) {
+		if (!down) {
+			ctrl_->show_camera(id_);
+		}
 	}
 	return true;
 }
@@ -101,11 +106,45 @@ Thumbnails::Thumbnails(ftl::gui2::Screen *parent, ftl::gui2::ThumbnailsControlle
 
 	tabwidget_ = new nanogui::TabWidget(this);
 	tabwidget_->setFixedSize(size());
+
+	context_menu_ = new nanogui::Window(parent, "");
+	context_menu_->setVisible(false);
+	context_menu_->setLayout(new nanogui::BoxLayout(nanogui::Orientation::Vertical));
+
+	auto *button = new nanogui::Button(context_menu_, "Remove");
+	button->setCallback([this]() {
+		int ix = tabwidget_->activeTab();
+		LOG(INFO) << "REMOVE FSID " << ix;
+
+		tabwidget_->removeTab(ix);
+		thumbnails_.erase(ix);
+		context_menu_->setVisible(false);
+		ctrl_->removeFrameset(ix);
+		//screen()->performLayout();
+	});
 }
 
 
 Thumbnails::~Thumbnails() {
+	if (context_menu_->parent()->getRefCount() > 0) {
+		context_menu_->setVisible(false);
+		context_menu_->dispose();
+	}
+}
 
+bool Thumbnails::mouseButtonEvent(const nanogui::Vector2i &p, int button, bool down, int modifiers) {
+	bool r = View::mouseButtonEvent(p, button, down, modifiers);
+
+	if (button == 1) {
+		if (!down) {
+			context_menu_->setPosition(p - mPos);
+			context_menu_->setVisible(true);
+			return true;
+		}
+	} else {
+		context_menu_->setVisible(false);
+	}
+	return r;
 }
 
 void Thumbnails::updateThumbnails() {
diff --git a/applications/gui2/src/views/thumbnails.hpp b/applications/gui2/src/views/thumbnails.hpp
index 4aab2dc139cea1ce9af7642426dad20829a82309..c9440967de7cd297ee6fef9fa888e7904262f499 100644
--- a/applications/gui2/src/views/thumbnails.hpp
+++ b/applications/gui2/src/views/thumbnails.hpp
@@ -20,6 +20,8 @@ public:
 
 	virtual void draw(NVGcontext *ctx) override;
 
+	bool mouseButtonEvent(const nanogui::Vector2i &p, int button, bool down, int modifiers) override;
+
 private:
 	void updateThumbnails();
 	void addTab(unsigned int fsid);
@@ -38,6 +40,8 @@ private:
 
 	nanogui::Vector2i thumbsize_ = nanogui::Vector2i(320,180);
 
+	nanogui::Window *context_menu_;
+
 public:
 	EIGEN_MAKE_ALIGNED_OPERATOR_NEW
 };
diff --git a/applications/tools/middlebury_gen/CMakeLists.txt b/applications/tools/middlebury_gen/CMakeLists.txt
index 2dffb172d22cfc554088f3971bb90ff2fd60e8e7..13cc2c9e82196e0ff78a8c873f8ce54c0ae30b66 100644
--- a/applications/tools/middlebury_gen/CMakeLists.txt
+++ b/applications/tools/middlebury_gen/CMakeLists.txt
@@ -15,3 +15,4 @@ endif()
 
 #target_include_directories(cv-node PUBLIC ${PROJECT_SOURCE_DIR}/include)
 target_link_libraries(middlebury-gen ftlcommon ftlrgbd Threads::Threads ${OpenCV_LIBS} ftlrender ftloperators ftlstreams)
+set_property(TARGET middlebury-gen PROPERTY CUDA_ARCHITECTURES OFF)
diff --git a/applications/vision/CMakeLists.txt b/applications/vision/CMakeLists.txt
index 4c2674d8da075a997792027591260e5bd09bd5b1..9341fab23e4f388295fae14f5a4f946c9753eff6 100644
--- a/applications/vision/CMakeLists.txt
+++ b/applications/vision/CMakeLists.txt
@@ -22,6 +22,6 @@ set_property(TARGET ftl-vision PROPERTY CUDA_SEPARABLE_COMPILATION OFF)
 endif()
 
 #target_include_directories(cv-node PUBLIC ${PROJECT_SOURCE_DIR}/include)
-target_link_libraries(ftl-vision ftlrgbd ftlcommon ftlstreams ftlctrl ${OpenCV_LIBS} ${LIBSGM_LIBRARIES} ${CUDA_LIBRARIES} ftlnet ftlaudio)
-
+target_link_libraries(ftl-vision ftlrgbd ftlcommon ftlstreams ftlctrl ${OpenCV_LIBS} ${CUDA_LIBRARIES} ftlnet ftlaudio)
 
+target_precompile_headers(ftl-vision REUSE_FROM ftldata)
diff --git a/components/codecs/CMakeLists.txt b/components/codecs/CMakeLists.txt
index 6e7b42f3cd5295d0e9c4acfa8a85385a13bb0302..821a11ed93a11f2075bdd1517468a84e0a9ef9a3 100644
--- a/components/codecs/CMakeLists.txt
+++ b/components/codecs/CMakeLists.txt
@@ -14,6 +14,7 @@ target_include_directories(BaseCodec PUBLIC
 	${CMAKE_CURRENT_SOURCE_DIR}/src/Video_Codec_SDK_9.1.23/Samples/NvCodec
 	$<TARGET_PROPERTY:ftlcommon,INTERFACE_INCLUDE_DIRECTORIES>
 )
+set_property(TARGET BaseCodec PROPERTY CUDA_ARCHITECTURES OFF)
 
 add_library(OpenCVCodec OBJECT	
 	src/opencv_encoder.cpp
@@ -24,6 +25,8 @@ target_include_directories(OpenCVCodec PUBLIC
 	$<TARGET_PROPERTY:ftlcommon,INTERFACE_INCLUDE_DIRECTORIES>
 )
 
+set_property(TARGET OpenCVCodec PROPERTY CUDA_ARCHITECTURES OFF)
+
 set(CODECSRC
 $<TARGET_OBJECTS:BaseCodec>
 $<TARGET_OBJECTS:OpenCVCodec>
@@ -44,6 +47,8 @@ target_include_directories(NvidiaCodec PUBLIC
 )
 list(APPEND CODECSRC $<TARGET_OBJECTS:NvidiaCodec>)
 
+set_property(TARGET NvidiaCodec PROPERTY CUDA_ARCHITECTURES OFF)
+
 add_library(ftlcodecs ${CODECSRC})
 
 if (WIN32)
@@ -62,6 +67,10 @@ target_include_directories(ftlcodecs PUBLIC
 #target_include_directories(cv-node PUBLIC ${PROJECT_SOURCE_DIR}/include)
 target_link_libraries(ftlcodecs ftlcommon ${OpenCV_LIBS} ${CUDA_LIBRARIES} Eigen3::Eigen nvcuvid cuda)
 
+target_precompile_headers(ftlcodecs REUSE_FROM ftlcommon)
+
+set_property(TARGET ftlcodecs PROPERTY CUDA_ARCHITECTURES OFF)
+
 if (BUILD_TESTS)
 add_subdirectory(test)
 endif()
diff --git a/components/codecs/test/CMakeLists.txt b/components/codecs/test/CMakeLists.txt
index 89550a4c146b38de0eed6fcf328441815cec40b4..34753db970a0acab275621de7aa4ceca6020b59c 100644
--- a/components/codecs/test/CMakeLists.txt
+++ b/components/codecs/test/CMakeLists.txt
@@ -39,6 +39,8 @@ ${CMAKE_CURRENT_SOURCE_DIR}/../src/Video_Codec_SDK_9.1.23/Samples/NvCodec)
 target_link_libraries(nvidia_codec_unit
 	Threads::Threads ${OS_LIBS} ${OpenCV_LIBS} ${CUDA_LIBRARIES} ftlcommon nvcuvid cuda)
 
+set_property(TARGET nvidia_codec_unit PROPERTY CUDA_ARCHITECTURES OFF)
+
 
 add_test(NvidiaCodecUnitTest nvidia_codec_unit)
 
diff --git a/components/common/cpp/CMakeLists.txt b/components/common/cpp/CMakeLists.txt
index 9b06a7831a065561a250b460a0f7e22e248a9cb2..7bf8a74398f94ed53a5b657b05d7781cfff16a7f 100644
--- a/components/common/cpp/CMakeLists.txt
+++ b/components/common/cpp/CMakeLists.txt
@@ -29,6 +29,14 @@ target_include_directories(ftlcommon PUBLIC
 	PRIVATE src)
 target_link_libraries(ftlcommon Threads::Threads Eigen3::Eigen ${OS_LIBS} ${OpenCV_LIBS} ${URIPARSER_LIBRARIES} ${CUDA_LIBRARIES})
 
+target_precompile_headers(ftlcommon
+	PRIVATE include/ftl/utility/msgpack.hpp
+	PRIVATE include/ftl/utility/msgpack_optional.hpp
+	PRIVATE include/ftl/cuda_common.hpp
+)
+
+set_property(TARGET ftlcommon PROPERTY CUDA_ARCHITECTURES OFF)
+
 if (BUILD_TESTS)
 add_subdirectory(test)
 endif()
diff --git a/components/common/cpp/src/timer.cpp b/components/common/cpp/src/timer.cpp
index 890f7dc839a17e848f5392146072d180f2067afd..2ef4432415615057691bc68de063b5fdfcd2feab 100644
--- a/components/common/cpp/src/timer.cpp
+++ b/components/common/cpp/src/timer.cpp
@@ -220,10 +220,13 @@ static void trigger_jobs() {
 
 		// If last job in list then do in this thread
 		if (active_jobs == jobs[kTimerMain].size()+1) {
+			lk.unlock();
 			bool doremove = !pj->job.trigger(ts);
 			pj->active = false;
 			active_jobs--;
 			if (doremove) removeJob(pj->id);
+			lk.lock();
+			break;
 		} else {
 			ftl::pool.push([pj,ts](int id) {
 				bool doremove = !pj->job.trigger(ts);
diff --git a/components/net/cpp/CMakeLists.txt b/components/net/cpp/CMakeLists.txt
index c765fa53877c3e29b2bcde904cccda75487f35ea..04e89bdfeabef32a938299a2e720e23b76655ac1 100644
--- a/components/net/cpp/CMakeLists.txt
+++ b/components/net/cpp/CMakeLists.txt
@@ -18,6 +18,8 @@ target_include_directories(ftlnet PUBLIC
 	PRIVATE src)
 target_link_libraries(ftlnet ftlctrl ftlcommon Threads::Threads glog::glog ${UUID_LIBRARIES})
 
+target_precompile_headers(ftlnet REUSE_FROM ftlcommon)
+
 install(TARGETS ftlnet EXPORT ftlnet-config
 	ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
 	LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
diff --git a/components/operators/CMakeLists.txt b/components/operators/CMakeLists.txt
index bc4edb1ea6ac6c10a0f3d14dfaa768e1a7732206..5eb5cb71c41692fb95bbc6c9300396f36766d588 100644
--- a/components/operators/CMakeLists.txt
+++ b/components/operators/CMakeLists.txt
@@ -57,6 +57,10 @@ target_include_directories(ftloperators PUBLIC
 
 target_link_libraries(ftloperators ftlrender ftlrgbd ftlcommon sgm libstereo Eigen3::Eigen Threads::Threads ${OpenCV_LIBS})
 
+target_precompile_headers(ftloperators REUSE_FROM ftldata)
+
+set_property(TARGET ftloperators PROPERTY CUDA_ARCHITECTURES OFF)
+
 if (BUILD_TESTS)
 	add_subdirectory(test)
 endif()
diff --git a/components/renderers/cpp/CMakeLists.txt b/components/renderers/cpp/CMakeLists.txt
index bae316acd12308b40d043a69f2805ee5054a69b4..5b720cf7765ad488172e26aaa88ee1ddf601e1ac 100644
--- a/components/renderers/cpp/CMakeLists.txt
+++ b/components/renderers/cpp/CMakeLists.txt
@@ -29,4 +29,8 @@ target_include_directories(ftlrender PUBLIC
 	PRIVATE src)
 target_link_libraries(ftlrender ftlrgbd ftlcommon Eigen3::Eigen Threads::Threads nanogui ${NANOGUI_EXTRA_LIBS} ${OpenCV_LIBS})
 
+target_precompile_headers(ftlrender REUSE_FROM ftldata)
+
+set_property(TARGET ftlrender PROPERTY CUDA_ARCHITECTURES OFF)
+
 #ADD_SUBDIRECTORY(test)
diff --git a/components/rgbd-sources/CMakeLists.txt b/components/rgbd-sources/CMakeLists.txt
index 6c428a23c80b6e7cd9a3ea5e979281cb026a5d0b..726e9960a5d5080a77b68cc5343f33530026ca7b 100644
--- a/components/rgbd-sources/CMakeLists.txt
+++ b/components/rgbd-sources/CMakeLists.txt
@@ -36,7 +36,9 @@ if (CUDA_FOUND)
 set_property(TARGET ftlrgbd PROPERTY CUDA_SEPARABLE_COMPILATION OFF)
 endif()
 
-target_link_libraries(ftlrgbd ftlcalibration ftlcommon ${OpenCV_LIBS} ${LIBSGM_LIBRARIES} ${CUDA_LIBRARIES} Eigen3::Eigen realsense ftlnet ${LibArchive_LIBRARIES} ftlcodecs ftloperators ftldata ${X11_X11_LIB} ${X11_Xext_LIB} ${X11_Xtst_LIB} ${X11_XTest_LIB} Pylon)
+target_link_libraries(ftlrgbd ftlcalibration ftlcommon ${OpenCV_LIBS} ${CUDA_LIBRARIES} Eigen3::Eigen realsense ftlnet ${LibArchive_LIBRARIES} ftlcodecs ftloperators ftldata ${X11_X11_LIB} ${X11_Xext_LIB} ${X11_Xtst_LIB} ${X11_XTest_LIB} Pylon)
+
+target_precompile_headers(ftlrgbd REUSE_FROM ftldata)
 
 if (BUILD_TESTS)
 add_subdirectory(test)
diff --git a/components/streams/CMakeLists.txt b/components/streams/CMakeLists.txt
index 7bb5dc6ac6dda4b07fa9bfa13eed1a3fb56e0379..cdbf7be84e68a78690ac5f5d794066e836f6dcbf 100644
--- a/components/streams/CMakeLists.txt
+++ b/components/streams/CMakeLists.txt
@@ -34,6 +34,8 @@ target_include_directories(ftlstreams PUBLIC
 #target_include_directories(cv-node PUBLIC ${PROJECT_SOURCE_DIR}/include)
 target_link_libraries(ftlstreams ftlrgbd ftlrender ftlcommon ${OpenCV_LIBS} Eigen3::Eigen ftlnet ftlcodecs ftlaudio openvr)
 
+target_precompile_headers(ftlstreams REUSE_FROM ftldata)
+
 if (BUILD_TESTS)
 add_subdirectory(test)
 endif()
diff --git a/components/streams/include/ftl/streams/receiver.hpp b/components/streams/include/ftl/streams/receiver.hpp
index bb78bb3dbbcde50c25c689c8cda5ab3b51124ace..710f256603410687993b196fee0fe262f6918174 100644
--- a/components/streams/include/ftl/streams/receiver.hpp
+++ b/components/streams/include/ftl/streams/receiver.hpp
@@ -43,12 +43,14 @@ class Receiver : public ftl::Configurable, public ftl::data::Generator {
 
 	void processPackets(const ftl::codecs::StreamPacket &spkt, const ftl::codecs::Packet &pkt);
 
+	void removeBuilder(uint32_t id);
+
 	private:
 	ftl::stream::Stream *stream_;
 	ftl::data::Pool *pool_;
 	ftl::SingletonHandler<const ftl::data::FrameSetPtr&> callback_;
 	std::unordered_map<uint32_t, std::shared_ptr<ftl::streams::BaseBuilder>> builders_;
-	std::list<ftl::Handle> handles_;
+	std::unordered_map<uint32_t, ftl::Handle> handles_;
 	ftl::codecs::Channel second_channel_;
 	int64_t timestamp_;
 	SHARED_MUTEX mutex_;
diff --git a/components/streams/src/feed.cpp b/components/streams/src/feed.cpp
index e2566317a79b6aabeb34a5729261686d9545cfb2..c8dff9d32caa900bee9e47fbce7d9d860ef44227 100644
--- a/components/streams/src/feed.cpp
+++ b/components/streams/src/feed.cpp
@@ -366,9 +366,31 @@ void Feed::remove(uint32_t id) {
 
 	// TODO: Actual delete of source
 	// If stream source, remove from muxer
+	if (streams_.count(id)) {
+		auto &streams = streams_[id];
+		for (auto *s : streams) {
+			stream_->remove(s);
+			delete s;
+		}
+
+		streams_.erase(id);
+	} else if (devices_.count(id)) {
+		receiver_->removeBuilder(id);
+		delete devices_[id];
+		devices_.erase(id);
+	} else if (renderers_.count(id)) {
+
+	}
 
-	// If device or render source, remove builder from receiver
+	if (latest_.count(id)) latest_.erase(id);
 
+	for (auto i = fsid_lookup_.begin(); i != fsid_lookup_.end();) {
+		if (i->second == id) {
+			i = fsid_lookup_.erase(i);
+		} else {
+			++i;
+		}
+	}
 }
 
 ftl::operators::Graph* Feed::addPipeline(uint32_t fsid) {
diff --git a/components/streams/src/filestream.cpp b/components/streams/src/filestream.cpp
index b887e028a0a1895d351ebb7052c979f1dfd7f131..501c815cbdea840716afebb659a238e65aebb35d 100644
--- a/components/streams/src/filestream.cpp
+++ b/components/streams/src/filestream.cpp
@@ -387,11 +387,13 @@ bool File::begin(bool dorun) {
 }
 
 bool File::end() {
-	UNIQUE_LOCK(mutex_, lk);
 	if (!active_) return false;
 	active_ = false;
+	
 	timer_.cancel();
 
+	UNIQUE_LOCK(mutex_, lk);
+
 	if (mode_ == Mode::Read) {
 		if (istream_) {
 			istream_->close();
diff --git a/components/streams/src/receiver.cpp b/components/streams/src/receiver.cpp
index 5b6f6b5756bd821c93f37e1c4c034cc73004810d..50f94771ecf1a1c2791d2823a8b29d93052c6884 100644
--- a/components/streams/src/receiver.cpp
+++ b/components/streams/src/receiver.cpp
@@ -73,24 +73,33 @@ ftl::streams::BaseBuilder &Receiver::builder(uint32_t id) {
 		b->setID(id);
 		b->setPool(pool_);
 		fb->setBufferSize(value("frameset_buffer_size", 3));
-		handles_.push_back(std::move(fb->onFrameSet([this](const ftl::data::FrameSetPtr& fs) {
+		handles_[id] = std::move(fb->onFrameSet([this](const ftl::data::FrameSetPtr& fs) {
 			callback_.trigger(fs);
 			return true;
-		})));
+		}));
 		return *b;
 	} else {
 		return *(i->second);
 	}
 }
 
+void Receiver::removeBuilder(uint32_t id) {
+	UNIQUE_LOCK(mutex_, lk);
+	auto i = builders_.find(id);
+	if (i != builders_.end()) {
+		handles_.erase(id);
+		builders_.erase(i);
+	}
+}
+
 void Receiver::registerBuilder(const std::shared_ptr<ftl::streams::BaseBuilder> &b) {
 	auto i = builders_.find(b->id());
 	if (i != builders_.end()) throw FTL_Error("Builder already exists");
 	builders_[b->id()] = b;
-	handles_.push_back(std::move(b->onFrameSet([this](const ftl::data::FrameSetPtr& fs) {
+	handles_[b->id()] = std::move(b->onFrameSet([this](const ftl::data::FrameSetPtr& fs) {
 		callback_.trigger(fs);
 		return true;
-	})));
+	}));
 }
 
 //void Receiver::onAudio(const ftl::audio::FrameSet::Callback &cb) {
diff --git a/components/streams/test/CMakeLists.txt b/components/streams/test/CMakeLists.txt
index 2e229179e3a65baa6c75d8e680b21f8ac16ddadb..272a87a24c301ba893f755f726f1802388a9d228 100644
--- a/components/streams/test/CMakeLists.txt
+++ b/components/streams/test/CMakeLists.txt
@@ -8,6 +8,8 @@ target_include_directories(stream_unit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../in
 target_link_libraries(stream_unit
 	ftlcommon ftlcodecs ftlrgbd)
 
+target_precompile_headers(stream_unit REUSE_FROM ftldata)
+
 add_test(StreamUnitTest stream_unit)
 
 ### File Stream Unit ###########################################################
@@ -21,6 +23,8 @@ target_include_directories(filestream_unit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/.
 target_link_libraries(filestream_unit
 	ftlcommon ftlcodecs ftlrgbd)
 
+target_precompile_headers(filestream_unit REUSE_FROM ftldata)
+
 add_test(FileStreamUnitTest filestream_unit)
 
 ### Net Stream Unit ###########################################################
@@ -48,6 +52,8 @@ target_include_directories(sender_unit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../in
 target_link_libraries(sender_unit
 	ftlcommon ftlcodecs ftlrgbd ftlaudio)
 
+target_precompile_headers(sender_unit REUSE_FROM ftldata)
+
 add_test(SenderUnitTest sender_unit)
 
 ### Receiver Unit ##############################################################
@@ -64,6 +70,8 @@ target_include_directories(receiver_unit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../
 target_link_libraries(receiver_unit
 	ftlcommon ftlcodecs ftlrgbd ftlaudio)
 
+target_precompile_headers(receiver_unit REUSE_FROM ftldata)
+
 add_test(ReceiverUnitTest receiver_unit)
 
 ### Receiver Sender Unit #######################################################
@@ -79,6 +87,8 @@ target_include_directories(recsend_unit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../i
 target_link_libraries(recsend_unit
 	ftlcommon ftlcodecs ftlrgbd ftlaudio)
 
+target_precompile_headers(recsend_unit REUSE_FROM ftldata)
+
 add_test(RecSendUnitTest recsend_unit)
 
 ### Builder Unit ###############################################################
@@ -91,6 +101,8 @@ target_include_directories(builder_unit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../i
 target_link_libraries(builder_unit
 	ftlcommon ftldata)
 
+target_precompile_headers(builder_unit REUSE_FROM ftldata)
+
 add_test(BuilderUnitTest builder_unit)
 
 
@@ -104,4 +116,6 @@ target_include_directories(feed_unit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../incl
 target_link_libraries(feed_unit
 	ftlrgbd ftlstreams ftloperators ftlcommon ftldata)
 
+target_precompile_headers(feed_unit REUSE_FROM ftldata)
+
 add_test(FeedUnitTest feed_unit)
diff --git a/components/structures/CMakeLists.txt b/components/structures/CMakeLists.txt
index 4b1a631d1c1d383a1ace922825a7ea3d33026a24..a7db04f27a208e4600828c38c56a0cf820275f6d 100644
--- a/components/structures/CMakeLists.txt
+++ b/components/structures/CMakeLists.txt
@@ -6,6 +6,16 @@ target_include_directories(ftldata PUBLIC
 
 target_link_libraries(ftldata ftlcommon Eigen3::Eigen ftlcodecs)
 
+target_precompile_headers(ftldata
+	PRIVATE ../common/cpp/include/ftl/utility/msgpack.hpp
+	PRIVATE ../common/cpp/include/ftl/utility/msgpack_optional.hpp
+	PRIVATE ../common/cpp/include/ftl/cuda_common.hpp
+	PRIVATE include/ftl/data/new_frame.hpp
+	PRIVATE include/ftl/data/new_frameset.hpp
+)
+
+set_property(TARGET ftldata PROPERTY CUDA_ARCHITECTURES OFF)
+
 if (BUILD_TESTS)
 add_subdirectory(test)
 endif()
diff --git a/components/structures/test/CMakeLists.txt b/components/structures/test/CMakeLists.txt
index 4a4154d403520eba304125bb12dc28f016aff613..fb67e4e589a6b2dafb51bc3fb957ded5dff01e00 100644
--- a/components/structures/test/CMakeLists.txt
+++ b/components/structures/test/CMakeLists.txt
@@ -7,6 +7,8 @@ target_include_directories(nframe_unit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../in
 target_link_libraries(nframe_unit
 	ftlcommon ftlcodecs)
 
+	target_precompile_headers(nframe_unit REUSE_FROM ftlcommon)
+
 add_test(NFrameUnitTest nframe_unit)
 
 ### Frame Example 1 ############################################################
diff --git a/lib/libsgm/CMakeLists.txt b/lib/libsgm/CMakeLists.txt
index 497411f85b8f667e0bbb3516fa3e61782f3a34ec..6fe014026f1f77fe122bb204ed63cb4e4d6acc03 100644
--- a/lib/libsgm/CMakeLists.txt
+++ b/lib/libsgm/CMakeLists.txt
@@ -1,9 +1,9 @@
-cmake_minimum_required(VERSION 3.1)
+#cmake_minimum_required(VERSION 3.1)
 
-set(CMAKE_CXX_STANDARD 11)
-set(CMAKE_CXX_EXTENSIONS OFF)
+#set(CMAKE_CXX_STANDARD 11)
+#set(CMAKE_CXX_EXTENSIONS OFF)
 
-set(CUDA_ARCH "-arch=sm_50" CACHE STRING "Value of the NVCC -arch option.")
+#set(CUDA_ARCH "-arch=sm_50" CACHE STRING "Value of the NVCC -arch option.")
 
 option(ENABLE_ZED_DEMO      "Build a Demo using ZED Camera" OFF)
 option(ENABLE_SAMPLES       "Build samples" OFF)
@@ -19,10 +19,10 @@ else()
   set(ZED_SDK_INCLUDE_DIR "/usr/local/zed/include" CACHE STRING "ZED SDK include path.")
 endif()
 
-project(libSGM VERSION 2.4.0)
+#project(libSGM VERSION 2.4.0)
 
 if(BUILD_OPENCV_WRAPPER)
-	find_package(OpenCV REQUIRED core)
+	#find_package(OpenCV REQUIRED core)
 	include_directories(${OpenCV_INCLUDE_DIRS})
 endif()
 
@@ -32,20 +32,3 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/libsgm_config.h.in
 
 add_subdirectory(src)
 
-if(ENABLE_SAMPLES)
-    add_subdirectory(sample/image)
-    add_subdirectory(sample/movie)
-#    add_subdirectory(sample/reprojection)
-    add_subdirectory(sample/benchmark)
-    if(BUILD_OPENCV_WRAPPER)
-        add_subdirectory(sample/image_cv_gpumat)
-    endif()
-endif()
-
-if(ENABLE_TESTS)
-	add_subdirectory(test)
-endif()
-
-if(ENABLE_ZED_DEMO)
-	add_subdirectory(sample/zed)
-endif()
diff --git a/lib/libsgm/include/libsgm_config.h b/lib/libsgm/include/libsgm_config.h
index 67444c41f80c77412b25b2109bb764d2e8f57497..eeba490fd6d0a8506007abae9b28c4badd3c9934 100644
--- a/lib/libsgm/include/libsgm_config.h
+++ b/lib/libsgm/include/libsgm_config.h
@@ -3,10 +3,10 @@
 
 /* #undef LIBSGM_SHARED */
 
-#define LIBSGM_VERSION 2.4.0
-#define LIBSGM_VERSION_MAJOR 2
-#define LIBSGM_VERSION_MINOR 4
-#define LIBSGM_VERSION_PATCH 0
+#define LIBSGM_VERSION 
+#define LIBSGM_VERSION_MAJOR 
+#define LIBSGM_VERSION_MINOR 
+#define LIBSGM_VERSION_PATCH 
 
 /* #undef BUILD_OPENCV_WRAPPER */
 
diff --git a/lib/libsgm/src/CMakeLists.txt b/lib/libsgm/src/CMakeLists.txt
index d1bc459e4e7c0547757c883c6c4fc73ba4ca0f8d..6db316464f3f9555459d816c8f8dadbf2ad479c8 100644
--- a/lib/libsgm/src/CMakeLists.txt
+++ b/lib/libsgm/src/CMakeLists.txt
@@ -1,44 +1,47 @@
-cmake_minimum_required(VERSION 3.1)
+#cmake_minimum_required(VERSION 3.1)
 
-find_package(CUDA REQUIRED)
+#find_package(CUDA REQUIRED)
 
 include_directories(../include)
 
-if (CMAKE_COMPILER_IS_GNUCXX)
-	set(CMAKE_CUDA_HOST_COMPILER gcc-7)
-	set(CUDA_HOST_COMPILER gcc-7)
-	set(CMAKE_CXX_FLAGS "-O3 -Wall -fPIC")
-	set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS} -std=c++11")
-endif()
+#if (CMAKE_COMPILER_IS_GNUCXX)
+#	set(CMAKE_CUDA_HOST_COMPILER gcc-7)
+#	set(CUDA_HOST_COMPILER gcc-7)
+#	set(CMAKE_CXX_FLAGS "-O3 -Wall -fPIC")
+#	set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS} -std=c++11")
+#endif()
 
-SET(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS} ${CUDA_ARCH}")
+#SET(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS} ${CUDA_ARCH}")
 
 file(GLOB STEREOSRCS "*.cu" "*.cpp")
 
-if(LIBSGM_SHARED)
-	CUDA_ADD_LIBRARY(sgm stereo_sgm.cpp ${STEREOSRCS} SHARED)
-	target_link_libraries(sgm ${CUDA_LIBRARIES})
-	if(BUILD_OPENCV_WRAPPER)
-		target_link_libraries(sgm ${OpenCV_LIBS})
-	endif()
-else()
-	CUDA_ADD_LIBRARY(sgm stereo_sgm.cpp ${STEREOSRCS} STATIC)
-endif()
-
-install(
-	TARGETS sgm
-	ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
-	LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
-	RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
-)
-
-install(
-	DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../include
-	DESTINATION ${CMAKE_INSTALL_PREFIX}
-	FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp"
-)
-
-install(
-	FILES ${CMAKE_CURRENT_SOURCE_DIR}/../FindLibSGM.cmake
-	DESTINATION ${CMAKE_INSTALL_PREFIX}
-)
+#if(LIBSGM_SHARED)
+#	CUDA_ADD_LIBRARY(sgm stereo_sgm.cpp ${STEREOSRCS} SHARED)
+#	target_link_libraries(sgm ${CUDA_LIBRARIES})
+#	if(BUILD_OPENCV_WRAPPER)
+#		target_link_libraries(sgm ${OpenCV_LIBS})
+#	endif()
+#else()
+	#CUDA_ADD_LIBRARY(sgm stereo_sgm.cpp ${STEREOSRCS} STATIC)
+	add_library(sgm stereo_sgm.cpp ${STEREOSRCS})
+#endif()
+
+set_property(TARGET sgm PROPERTY CUDA_ARCHITECTURES "61")
+
+#install(
+#	TARGETS sgm
+#	ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
+#	LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
+#	RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
+#)
+
+#install(
+#	DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../include
+#	DESTINATION ${CMAKE_INSTALL_PREFIX}
+#	FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp"
+#)
+
+#install(
+#	FILES ${CMAKE_CURRENT_SOURCE_DIR}/../FindLibSGM.cmake
+#	DESTINATION ${CMAKE_INSTALL_PREFIX}
+#)
diff --git a/lib/libstereo/CMakeLists.txt b/lib/libstereo/CMakeLists.txt
index 7095e16799d648ec41eb46c9906922d2c90f6fa3..f60cc79a1b7f55d237c911fc97833b8db465da4c 100644
--- a/lib/libstereo/CMakeLists.txt
+++ b/lib/libstereo/CMakeLists.txt
@@ -119,6 +119,7 @@ endif()
 target_include_directories(libstereo PRIVATE src/ include/)
 target_include_directories(libstereo PUBLIC ${OpenCV_INCLUDE_DIRS})
 target_link_libraries(libstereo Threads::Threads ${OpenCV_LIBS} ${CUDA_LIBRARIES})
+set_property(TARGET libstereo PROPERTY CUDA_ARCHITECTURES OFF)
 
 if (BUILD_MIDDLEBURY)
     add_subdirectory(middlebury/)
diff --git a/lib/libstereo/test/CMakeLists.txt b/lib/libstereo/test/CMakeLists.txt
index ee222cd762895cbbd4c6154ad848f1f914dfd370..d5e6f318dcdcc5337516c84540137f32ef75da87 100644
--- a/lib/libstereo/test/CMakeLists.txt
+++ b/lib/libstereo/test/CMakeLists.txt
@@ -7,6 +7,7 @@ $<TARGET_OBJECTS:CatchTest>
 target_include_directories(dsi_cpu_unit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../include")
 target_include_directories(dsi_cpu_unit PUBLIC ${OpenCV_INCLUDE_DIRS})
 target_link_libraries(dsi_cpu_unit Threads::Threads ${OpenCV_LIBS})
+#set_property(TARGET dsi_cpu_unit PROPERTY CUDA_ARCHITECTURES OFF)
 
 add_test(DSICPUUnitTest dsi_cpu_unit)
 
@@ -18,6 +19,7 @@ target_include_directories(dsi_gpu_unit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../i
 target_include_directories(dsi_gpu_unit PUBLIC ${OpenCV_INCLUDE_DIRS})
 target_compile_definitions(dsi_gpu_unit PUBLIC USE_GPU)
 target_link_libraries(dsi_gpu_unit Threads::Threads ${OpenCV_LIBS})
+set_property(TARGET dsi_gpu_unit PROPERTY CUDA_ARCHITECTURES OFF)
 
 add_test(DSIGPUUnitTest dsi_gpu_unit)
 
@@ -28,6 +30,7 @@ $<TARGET_OBJECTS:CatchTest>
 target_include_directories(array2d_unit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../include")
 target_include_directories(array2d_unit PUBLIC ${OpenCV_INCLUDE_DIRS})
 target_link_libraries(array2d_unit Threads::Threads ${OpenCV_LIBS})
+set_property(TARGET array2d_unit PROPERTY CUDA_ARCHITECTURES OFF)
 
 add_test(Array2DUnitTest array2d_unit)
 
@@ -41,6 +44,7 @@ $<TARGET_OBJECTS:CatchTest>
 target_include_directories(matching_cost_unit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../include" "${CMAKE_CURRENT_SOURCE_DIR}/../src")
 target_include_directories(matching_cost_unit PUBLIC ${OpenCV_INCLUDE_DIRS})
 target_link_libraries(matching_cost_unit Threads::Threads ${OpenCV_LIBS})
+set_property(TARGET matching_cost_unit PROPERTY CUDA_ARCHITECTURES OFF)
 
 add_test(MatchingCostUnitTest matching_cost_unit)
 
@@ -51,6 +55,7 @@ $<TARGET_OBJECTS:CatchTest>
 target_include_directories(aggregation_unit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../include")
 target_include_directories(aggregation_unit PUBLIC ${OpenCV_INCLUDE_DIRS})
 target_link_libraries(aggregation_unit Threads::Threads ${OpenCV_LIBS})
+set_property(TARGET aggregation_unit PROPERTY CUDA_ARCHITECTURES OFF)
 
 add_test(AggregationUnitTest aggregation_unit)
 
@@ -61,5 +66,6 @@ $<TARGET_OBJECTS:CatchTest>
 target_include_directories(wta_unit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../include")
 target_include_directories(wta_unit PUBLIC ${OpenCV_INCLUDE_DIRS})
 target_link_libraries(wta_unit Threads::Threads ${OpenCV_LIBS})
+set_property(TARGET wta_unit PROPERTY CUDA_ARCHITECTURES OFF)
 
 add_test(WTAUnitTest wta_unit)