diff --git a/applications/reconstruct/src/main.cpp b/applications/reconstruct/src/main.cpp
index 88c883a35c2f972f4077d726079e36901f04140b..896fe285352ab1b8ef798eb000e314b6614076f9 100644
--- a/applications/reconstruct/src/main.cpp
+++ b/applications/reconstruct/src/main.cpp
@@ -95,6 +95,9 @@ static void writeSourceProperties(ftl::codecs::Writer &writer, int id, ftl::rgbd
 static void run(ftl::Configurable *root) {
 	Universe *net = ftl::create<Universe>(root, "net");
 	ftl::ctrl::Slave slave(net, root);
+
+	// Controls
+	auto *controls = ftl::create<ftl::Configurable>(root, "controls");
 	
 	net->start();
 	net->waitConnections();
@@ -165,10 +168,6 @@ static void run(ftl::Configurable *root) {
 	ftl::rgbd::Group *group = new ftl::rgbd::Group;
 	ftl::ILW *align = ftl::create<ftl::ILW>(root, "merge");
 
-	// Controls
-	auto *controls = ftl::create<ftl::Configurable>(root, "controls");
-	controls->set("paused", false);
-
 	int o = root->value("origin_pose", 0) % sources.size();
 	virt->setPose(sources[o]->getPose());
 
diff --git a/components/rgbd-sources/src/sources/ftlfile/player.cpp b/components/rgbd-sources/src/sources/ftlfile/player.cpp
index 411ed5b180854a687c10dc8e761fde9a71dbd06b..c78790fc13b01e028376a6edff3bc89616d0f65c 100644
--- a/components/rgbd-sources/src/sources/ftlfile/player.cpp
+++ b/components/rgbd-sources/src/sources/ftlfile/player.cpp
@@ -3,28 +3,28 @@
 
 using ftl::rgbd::Player;
 
-Player::Player(std::istream &s) : reader_(s) {
+Player::Player(std::istream &s) : stream_(&s), reader_(s) {
     auto *c = ftl::config::find("/controls");
 	
     if (c) {
         paused_ = c->value("paused", false);
-        c->on("paused", [this](const ftl::config::Event &e) {
-            LOG(INFO) << "PAUSED";
+        c->on("paused", [this,c](const ftl::config::Event &e) {
+            paused_ = c->value("paused", false);
         });
 
-        looping_ = c->value("looping", false);
-        c->on("looping", [this](const ftl::config::Event &e) {
-            LOG(INFO) << "LOOPED";
+        looping_ = c->value("looping", true);
+        c->on("looping", [this,c](const ftl::config::Event &e) {
+            looping_ = c->value("looping", false);
         });
 
         speed_ = c->value("speed", 1.0f);
-        c->on("speed", [this](const ftl::config::Event &e) {
-            LOG(INFO) << "SPEED";
+        c->on("speed", [this,c](const ftl::config::Event &e) {
+            speed_ = c->value("speed", 1.0f);
         });
 
         reversed_ = c->value("reverse", false);
-        c->on("reverse", [this](const ftl::config::Event &e) {
-            LOG(INFO) << "REVERSE";
+        c->on("reverse", [this,c](const ftl::config::Event &e) {
+            reversed_ = c->value("reverse", false);
         });
     }
 }
@@ -34,7 +34,24 @@ Player::~Player() {
 }
 
 bool Player::read(int64_t ts) {
-    return reader_.read(ts);
+    if (paused_) return true;
+
+    int64_t adjusted_ts = int64_t(float(ts - reader_.getStartTime()) * speed_) + reader_.getStartTime();
+    LOG(INFO) << "Adjusted = " << adjusted_ts;
+    bool res = reader_.read(adjusted_ts);
+
+    if (looping_ && !res) {
+        reader_.end();
+        stream_->clear();
+        stream_->seekg(0);
+        if (!reader_.begin()) {
+            LOG(ERROR) << "Could not loop";
+            return false;
+        }
+        return true;
+    }
+
+    return res;
 }
 
 void Player::onPacket(int streamID, const std::function<void(const ftl::codecs::StreamPacket &, ftl::codecs::Packet &)> &f) {
diff --git a/components/rgbd-sources/src/sources/ftlfile/player.hpp b/components/rgbd-sources/src/sources/ftlfile/player.hpp
index 15568eedef11d92f7ce193b4ebfc7c2edb8b406c..d1d342352afea061b688f35c9fbef98b28b1e702 100644
--- a/components/rgbd-sources/src/sources/ftlfile/player.hpp
+++ b/components/rgbd-sources/src/sources/ftlfile/player.hpp
@@ -25,6 +25,7 @@ class Player {
     inline int64_t getStartTime() { return reader_.getStartTime(); }
 
     private:
+    std::istream *stream_;
     ftl::codecs::Reader reader_;
 
     bool paused_;