diff --git a/components/operators/include/ftl/operators/mvmls.hpp b/components/operators/include/ftl/operators/mvmls.hpp
index 6b8eff1be304693cfe7dee96152f9aa4cd3452b4..1c250e98574d1bac9182aa950ec7fbda594c5b2e 100644
--- a/components/operators/include/ftl/operators/mvmls.hpp
+++ b/components/operators/include/ftl/operators/mvmls.hpp
@@ -16,10 +16,10 @@ class MultiViewMLS : public ftl::operators::Operator {
 	bool apply(ftl::rgbd::FrameSet &in, ftl::rgbd::FrameSet &out, cudaStream_t stream) override;
 
 	private:
-	std::vector<ftl::cuda::TextureObject<float4>> centroid_horiz_;
-	std::vector<ftl::cuda::TextureObject<float4>> centroid_vert_;
-	std::vector<ftl::cuda::TextureObject<float4>> normals_horiz_;
-    std::vector<ftl::cuda::TextureObject<float>> contributions_;
+	std::vector<ftl::cuda::TextureObject<float4>*> centroid_horiz_;
+	std::vector<ftl::cuda::TextureObject<float4>*> centroid_vert_;
+	std::vector<ftl::cuda::TextureObject<float4>*> normals_horiz_;
+    std::vector<ftl::cuda::TextureObject<float>*> contributions_;
 };
 
 }
diff --git a/components/operators/src/mvmls.cpp b/components/operators/src/mvmls.cpp
index 305bdd98f539cacb39ce063b6f7d3ff1e65af99e..de69a0691441c7661dc3ae23d51639440a83654f 100644
--- a/components/operators/src/mvmls.cpp
+++ b/components/operators/src/mvmls.cpp
@@ -41,22 +41,25 @@ bool MultiViewMLS::apply(ftl::rgbd::FrameSet &in, ftl::rgbd::FrameSet &out, cuda
     params.cost_ratio = config()->value("cost_ratio", 0.2f);
 	params.cost_threshold = config()->value("cost_threshold", 1.0f);
 
+    if (in.frames.size() < 1) return false;
+    auto size = in.frames[0].get<GpuMat>(Channel::Depth).size();
+
     // Make sure we have enough buffers
-    if (normals_horiz_.size() < in.frames.size()) {
-        normals_horiz_.resize(in.frames.size());
-        centroid_horiz_.resize(in.frames.size());
-        centroid_vert_.resize(in.frames.size());
-        contributions_.resize(in.frames.size());
+    while (normals_horiz_.size() < in.frames.size()) {
+        normals_horiz_.push_back(new ftl::cuda::TextureObject<float4>(size.height, size.width));
+        centroid_horiz_.push_back(new ftl::cuda::TextureObject<float4>(size.height, size.width));
+        centroid_vert_.push_back(new ftl::cuda::TextureObject<float4>(size.width, size.height));
+        contributions_.push_back(new ftl::cuda::TextureObject<float>(size.width, size.height));
     }
 
     // Make sure all buffers are at correct resolution and are allocated
     for (size_t i=0; i<in.frames.size(); ++i) {
         auto &f = in.frames[i];
 	    auto size = f.get<GpuMat>(Channel::Depth).size();
-	    centroid_horiz_[i].create(size.height, size.width);
-	    normals_horiz_[i].create(size.height, size.width);
-	    centroid_vert_[i].create(size.width, size.height);
-        contributions_[i].create(size.width, size.height);
+	    centroid_horiz_[i]->create(size.height, size.width);
+	    normals_horiz_[i]->create(size.height, size.width);
+	    centroid_vert_[i]->create(size.width, size.height);
+        contributions_[i]->create(size.width, size.height);
 
         if (!f.hasChannel(Channel::Normals)) {
             throw FTL_Error("Required normals channel missing for MLS");
@@ -201,8 +204,8 @@ bool MultiViewMLS::apply(ftl::rgbd::FrameSet &in, ftl::rgbd::FrameSet &out, cuda
             //auto *s = in.sources[i];
 
             // Clear data
-            cv::cuda::GpuMat data(contributions_[i].height(), contributions_[i].width(), CV_32F, contributions_[i].pixelPitch());
-            data.setTo(cv::Scalar(0.0f), cvstream);
+            //cv::cuda::GpuMat data(contributions_[i]->height(), contributions_[i]->width(), CV_32F, contributions_[i]->devicePtr(), contributions_[i]->pixelPitch());
+            //data.setTo(cv::Scalar(0.0f), cvstream);
 
 			if (cull_zero && iter == iters-1) {
 				ftl::cuda::zero_confidence(
@@ -215,9 +218,9 @@ bool MultiViewMLS::apply(ftl::rgbd::FrameSet &in, ftl::rgbd::FrameSet &out, cuda
             ftl::cuda::mls_aggr_horiz(
                 f.createTexture<uchar4>(Channel::Support2),
                 f.createTexture<float4>(Channel::Normals),
-                normals_horiz_[i],
+                *normals_horiz_[i],
                 f.createTexture<float>(Channel::Depth),
-                centroid_horiz_[i],
+                *centroid_horiz_[i],
                 f.createTexture<uchar4>(Channel::Colour),
                 thresh,
                 col_smooth,
@@ -228,10 +231,10 @@ bool MultiViewMLS::apply(ftl::rgbd::FrameSet &in, ftl::rgbd::FrameSet &out, cuda
 
             ftl::cuda::mls_aggr_vert(
                 f.getTexture<uchar4>(Channel::Support2),
-                normals_horiz_[i],
+                *normals_horiz_[i],
                 f.getTexture<float4>(Channel::Normals),
-                centroid_horiz_[i],
-                centroid_vert_[i],
+                *centroid_horiz_[i],
+                *centroid_vert_[i],
                 f.getTexture<uchar4>(Channel::Colour),
                 f.getTexture<float>(Channel::Depth),
                 thresh,
@@ -242,6 +245,9 @@ bool MultiViewMLS::apply(ftl::rgbd::FrameSet &in, ftl::rgbd::FrameSet &out, cuda
             );
         }
 
+        //return true;
+
+
         // Step 3:
         // Find corresponding points and perform aggregation of any correspondences
         // For each camera combination
@@ -280,8 +286,8 @@ bool MultiViewMLS::apply(ftl::rgbd::FrameSet &in, ftl::rgbd::FrameSet &out, cuda
                     ftl::cuda::aggregate_sources(
                         f1.getTexture<float4>(Channel::Normals),
                         f2.getTexture<float4>(Channel::Normals),
-                        centroid_vert_[i],
-                        centroid_vert_[j],
+                        *centroid_vert_[i],
+                        *centroid_vert_[j],
 						f1.getTexture<float>(Channel::Depth),
                         //contributions_[i],
                         //contributions_[j],
@@ -315,7 +321,7 @@ bool MultiViewMLS::apply(ftl::rgbd::FrameSet &in, ftl::rgbd::FrameSet &out, cuda
 
             ftl::cuda::mls_adjust_depth(
                 f.getTexture<float4>(Channel::Normals),
-                centroid_vert_[i],
+                *centroid_vert_[i],
                 f.getTexture<float>(Channel::Depth),
                 f.createTexture<float>(Channel::Depth2, ftl::rgbd::Format<float>(size)),
                 f.getLeftCamera(),
diff --git a/components/operators/src/operator.cpp b/components/operators/src/operator.cpp
index 080d5c1707c5e7c578746ab7438ae2bf3ee9c35e..9b87fe1d0ae0b0312852bf19b90d62c94d247de3 100644
--- a/components/operators/src/operator.cpp
+++ b/components/operators/src/operator.cpp
@@ -69,7 +69,9 @@ bool Graph::apply(FrameSet &in, FrameSet &out, cudaStream_t stream) {
 					try {
 						instance->apply(in.frames[j], out.frames[j], stream_actual);
 					} catch (const std::exception &e) {
-						LOG(ERROR) << "Operator exception: " << e.what();
+						LOG(ERROR) << "Operator exception for '" << instance->config()->getID() << "': " << e.what();
+						cudaSafeCall(cudaStreamSynchronize(stream_actual));
+						return false;
 					}
 				}
 			}
@@ -80,7 +82,9 @@ bool Graph::apply(FrameSet &in, FrameSet &out, cudaStream_t stream) {
 				try {
 					instance->apply(in, out, stream_actual);
 				} catch (const std::exception &e) {
-					LOG(ERROR) << "Operator exception: " << e.what();
+					LOG(ERROR) << "Operator exception for '" << instance->config()->getID() << "': " << e.what();
+					cudaSafeCall(cudaStreamSynchronize(stream_actual));
+					return false;
 				}
 			}
 		}
@@ -88,7 +92,7 @@ bool Graph::apply(FrameSet &in, FrameSet &out, cudaStream_t stream) {
 
 	if (stream == 0) {
 		cudaSafeCall(cudaStreamSynchronize(stream_actual));
-		cudaSafeCall( cudaGetLastError() );
+		//cudaSafeCall( cudaGetLastError() );
 	}
 
 	return true;
@@ -111,7 +115,9 @@ bool Graph::apply(Frame &in, Frame &out, cudaStream_t stream) {
 			try {
 				instance->apply(in, out, stream_actual);
 			} catch (const std::exception &e) {
-				LOG(ERROR) << "Operator exception: " << e.what();
+				LOG(ERROR) << "Operator exception for '" << instance->config()->getID() << "': " << e.what();
+				cudaSafeCall(cudaStreamSynchronize(stream_actual));
+				return false;
 			}
 		}
 	}
diff --git a/components/rgbd-sources/include/ftl/rgbd/frameset.hpp b/components/rgbd-sources/include/ftl/rgbd/frameset.hpp
index 92ac321ebd2a3915ab40a51af80ac52930f76ad0..a1e5396622017622a5de9dceed80059012b7106a 100644
--- a/components/rgbd-sources/include/ftl/rgbd/frameset.hpp
+++ b/components/rgbd-sources/include/ftl/rgbd/frameset.hpp
@@ -136,6 +136,7 @@ class Builder : public Generator {
 	float fps_;
 	int stats_count_;
 	int64_t last_ts_;
+	int64_t last_frame_;
 	std::atomic<int> jobs_;
 	volatile bool skip_;
 	ftl::timer::TimerHandle main_id_;
diff --git a/components/rgbd-sources/src/frameset.cpp b/components/rgbd-sources/src/frameset.cpp
index 48da2b5dc34b0399cc640485781c19b0d2e429b4..740af42ff10cb35a6af7aab29ecf83be2eca5979 100644
--- a/components/rgbd-sources/src/frameset.cpp
+++ b/components/rgbd-sources/src/frameset.cpp
@@ -64,6 +64,7 @@ Builder::Builder() : head_(0) {
 	skip_ = false;
 	//setFPS(20);
 	size_ = 0;
+	last_frame_ = 0;
 
 	mspf_ = ftl::timer::getInterval();
 	name_ = "NoName";
@@ -71,6 +72,8 @@ Builder::Builder() : head_(0) {
 	latency_ = 0.0f;;
 	stats_count_ = 0;
 	fps_ = 0.0f;
+
+	if (size_ > 0) states_.resize(size_);
 }
 
 Builder::~Builder() {
@@ -84,7 +87,7 @@ Builder::~Builder() {
 }
 
 ftl::rgbd::Frame &Builder::get(int64_t timestamp, size_t ix) {
-	if (timestamp <= 0 || ix >= kMaxFramesInSet) throw ftl::exception("Invalid frame timestamp or index");
+	if (timestamp <= 0 || ix >= kMaxFramesInSet) throw FTL_Error("Invalid frame timestamp or index");
 
 	UNIQUE_LOCK(mutex_, lk);
 
@@ -98,15 +101,27 @@ ftl::rgbd::Frame &Builder::get(int64_t timestamp, size_t ix) {
 	}
 	//states_[ix] = frame.origin();
 
+	if (timestamp <= last_frame_) {
+		throw FTL_Error("Frameset already completed");
+	}
+
 	auto *fs = _findFrameset(timestamp);
 
 	if (!fs) {
 		// Add new frameset
 		fs = _addFrameset(timestamp);
-		if (!fs) throw ftl::exception("Could not add frameset");
+		if (!fs) throw FTL_Error("Could not add frameset");
+	}
+
+	if (fs->stale) {
+		throw FTL_Error("Frameset already completed");
+	}
+
+	if (ix >= fs->frames.size()) {
+		throw FTL_Error("Frame index out-of-bounds");
 	}
 
-	if (fs->frames.size() < size_) fs->frames.resize(size_);
+	//if (fs->frames.size() < size_) fs->frames.resize(size_);
 
 	//lk.unlock();
 	//SHARED_LOCK(fs->mtx, lk2);
@@ -159,7 +174,7 @@ void Builder::_schedule() {
 	if (fs) {
 		//UNIQUE_LOCK(fs->mtx, lk2);
 		// The buffers are invalid after callback so mark stale
-		fs->stale = true;
+		//fs->stale = true;
 		jobs_++;
 		//lk.unlock();
 
@@ -310,6 +325,9 @@ ftl::rgbd::FrameSet *Builder::_getFrameset() {
 		if (!f->stale && static_cast<unsigned int>(f->count) >= size_) {
 			//LOG(INFO) << "GET FRAMESET and remove: " << f->timestamp;
 			auto j = framesets_.erase(i);
+
+			last_frame_ = f->timestamp;
+			f->stale = true;
 			
 			int count = 0;
 			// Merge all previous frames
diff --git a/components/streams/src/receiver.cpp b/components/streams/src/receiver.cpp
index bccd8ce4f517fc23c43e425521ff1ef7b83725d1..37e6467f0578cb7c27d4fb51d7a89acd3b792555 100644
--- a/components/streams/src/receiver.cpp
+++ b/components/streams/src/receiver.cpp
@@ -194,7 +194,8 @@ void Receiver::_processVideo(const StreamPacket &spkt, const Packet &pkt) {
 
 	// Now split the tiles from surface into frames, doing colour conversions
 	// at the same time.
-	for (int i=0; i<pkt.frame_count; ++i) {
+	// Note: Done in reverse to allocate correct number of frames first time round
+	for (int i=pkt.frame_count-1; i>=0; --i) {
 		InternalVideoStates &vidstate = _getVideoFrame(spkt,i);
 		auto &frame = builder_.get(spkt.timestamp, spkt.frame_number+i);