diff --git a/CMakeLists.txt b/CMakeLists.txt
index b0aecb25a357a5c978db35a80cb20487adb5d08d..17ef352e58e8191f84a7a9388f6d3e823d5a1535 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -220,6 +220,7 @@ add_subdirectory(components/rgbd-sources)
 add_subdirectory(components/control/cpp)
 add_subdirectory(applications/calibration)
 add_subdirectory(applications/groupview)
+add_subdirectory(applications/player)
 
 if (BUILD_RENDERER)
 	add_subdirectory(components/renderers)
diff --git a/applications/player/CMakeLists.txt b/applications/player/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c501c882464a5fbd2a13f2d1561de19b74a3cd76
--- /dev/null
+++ b/applications/player/CMakeLists.txt
@@ -0,0 +1,11 @@
+set(PLAYERSRC
+	src/main.cpp
+)
+
+add_executable(ftl-player ${PLAYERSRC})
+
+target_include_directories(ftl-player PRIVATE src)
+
+target_link_libraries(ftl-player ftlcommon ftlcodecs ftlrgbd Threads::Threads ${OpenCV_LIBS})
+
+
diff --git a/applications/player/src/main.cpp b/applications/player/src/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..78d66a8db7e70a82759c8cd28826b09ba555077c
--- /dev/null
+++ b/applications/player/src/main.cpp
@@ -0,0 +1,64 @@
+#include <loguru.hpp>
+#include <ftl/configuration.hpp>
+#include <ftl/codecs/reader.hpp>
+#include <ftl/codecs/decoder.hpp>
+#include <ftl/codecs/packet.hpp>
+
+#include <fstream>
+
+static ftl::codecs::Decoder *decoder;
+
+static void createDecoder(const ftl::codecs::Packet &pkt) {
+	if (decoder) {
+		if (!decoder->accepts(pkt)) {
+			ftl::codecs::free(decoder);
+		} else {
+			return;
+		}
+	}
+
+	decoder = ftl::codecs::allocateDecoder(pkt);
+}
+
+int main(int argc, char **argv) {
+    std::string filename(argv[1]);
+    LOG(INFO) << "Playing: " << filename;
+
+	auto root = ftl::configure(argc, argv, "player_default");
+
+	std::ifstream f;
+    f.open(filename);
+    if (!f.is_open()) LOG(ERROR) << "Could not open file";
+
+    ftl::codecs::Reader r(f);
+    if (!r.begin()) LOG(ERROR) << "Bad ftl file";
+
+    LOG(INFO) << "Playing...";
+
+    bool res = r.read(90000000000000, [](const ftl::codecs::StreamPacket &spkt, const ftl::codecs::Packet &pkt) {
+        if (spkt.channel & 0x1 > 0) return;
+
+        LOG(INFO) << "Reading packet: (" << (int)spkt.streamID << "," << (int)spkt.channel << ") " << (int)pkt.codec << ", " << (int)pkt.definition;
+
+        cv::Mat frame(cv::Size(ftl::codecs::getWidth(pkt.definition),ftl::codecs::getHeight(pkt.definition)), CV_8UC3);
+        createDecoder(pkt);
+
+        try {
+            decoder->decode(pkt, frame);
+        } catch (std::exception &e) {
+            LOG(INFO) << "Decoder exception: " << e.what();
+        }
+
+        if (!frame.empty()) {
+            cv::imshow("Player", frame);
+            cv::waitKey(20);
+        }
+    });
+
+    if (!res) LOG(ERROR) << "No frames left";
+
+    r.end();
+
+	ftl::running = false;
+	return 0;
+}
diff --git a/components/codecs/src/reader.cpp b/components/codecs/src/reader.cpp
index 1cd570143374ebf8bada2d209dcdae7a2a6c194d..6280d93918abfd1f7abe248f9e95b1d9f5c9c4b1 100644
--- a/components/codecs/src/reader.cpp
+++ b/components/codecs/src/reader.cpp
@@ -1,3 +1,4 @@
+#include <loguru.hpp>
 #include <ftl/codecs/reader.hpp>
 
 #include <tuple>
@@ -30,19 +31,26 @@ bool Reader::read(int64_t ts, const std::function<void(const ftl::codecs::Stream
 		return false;
 	}
 
+	bool partial = false;
+
 	while (stream_->good() || buffer_.nonparsed_size() > 0) {
-		if (buffer_.nonparsed_size() == 0) {
-			buffer_.reserve_buffer(100000);
-			stream_->read(buffer_.buffer(), 100000);
+		if (buffer_.nonparsed_size() == 0 || partial) {
+			buffer_.reserve_buffer(10000000);
+			stream_->read(buffer_.buffer(), 10000000);
 			//if (stream_->bad()) return false;
 
 			int bytes = stream_->gcount();
 			if (bytes == 0) return false;
 			buffer_.buffer_consumed(bytes);
+			partial = false;
 		}
 
 		msgpack::object_handle msg;
-		if (!buffer_.next(msg)) continue;
+		if (!buffer_.next(msg)) {
+			LOG(INFO) << "NO Message: " << buffer_.nonparsed_size();
+			partial = true;
+			continue;
+		}
 
 		std::tuple<StreamPacket,Packet> data;
 		msgpack::object obj = msg.get();
@@ -53,6 +61,7 @@ bool Reader::read(int64_t ts, const std::function<void(const ftl::codecs::Stream
 		} else {
 			data_ = data;
 			has_data_ = true;
+			return true;
 		}
 	}