diff --git a/src/android/camera_device.h b/src/android/camera_device.h
index 0bd570a1..e3f3fe7c 100644
--- a/src/android/camera_device.h
+++ b/src/android/camera_device.h
@@ -27,6 +27,7 @@
 #include <libcamera/request.h>
 #include <libcamera/stream.h>
 
+#include "camera_buffer.h"
 #include "camera_capabilities.h"
 #include "camera_metadata.h"
 #include "camera_stream.h"
@@ -55,6 +56,7 @@ struct Camera3RequestDescriptor {
 	CameraMetadata settings_;
 	std::unique_ptr<CaptureRequest> request_;
 	std::unique_ptr<CameraMetadata> resultMetadata_;
+	std::unique_ptr<CameraBuffer> destBuffer_;
 
 	camera3_capture_result_t captureResult_ = {};
 	libcamera::FrameBuffer *internalBuffer_;
diff --git a/src/android/camera_stream.cpp b/src/android/camera_stream.cpp
index c18c7041..6578ce09 100644
--- a/src/android/camera_stream.cpp
+++ b/src/android/camera_stream.cpp
@@ -55,6 +55,9 @@ CameraStream::CameraStream(CameraDevice *const cameraDevice,
 		 * is what we instantiate here.
 		 */
 		postProcessor_ = std::make_unique<PostProcessorJpeg>(cameraDevice_);
+		thread_ = std::make_unique<libcamera::Thread>();
+		postProcessor_->moveToThread(thread_.get());
+		thread_->start();
 	}
 
 	if (type == Type::Internal) {
@@ -63,6 +66,14 @@ CameraStream::CameraStream(CameraDevice *const cameraDevice,
 	}
 }
 
+CameraStream::~CameraStream()
+{
+	if (thread_) {
+		thread_->exit();
+		thread_->wait();
+	}
+}
+
 const StreamConfiguration &CameraStream::configuration() const
 {
 	return config_->at(index_);
@@ -111,21 +122,23 @@ void CameraStream::process(const FrameBuffer *source,
 		return;
 	}
 
-	/*
-	 * \todo Buffer mapping and processing should be moved to a
-	 * separate thread.
-	 */
 	const StreamConfiguration &output = configuration();
-	CameraBuffer dest(camera3Dest, formats::MJPEG, output.size,
-			  PROT_READ | PROT_WRITE);
-	if (!dest.isValid()) {
+	std::unique_ptr<CameraBuffer> dest =
+		std::make_unique<CameraBuffer>(camera3Dest, formats::MJPEG,
+					       output.size, PROT_READ | PROT_WRITE);
+
+	if (!dest->isValid()) {
 		LOG(HAL, Error) << "Failed to map android blob buffer";
 		request->status_ = Camera3RequestDescriptor::ProcessStatus::Error;
 		handleProcessComplete(request);
 		return;
 	}
+	request->destBuffer_ = std::move(dest);
 
-	postProcessor_->process(source, &dest, request);
+	/* \todo Use ConnectionTypeQueued instead of ConnectionTypeBlocking */
+	postProcessor_->invokeMethod(&PostProcessor::process,
+				     ConnectionTypeBlocking, source,
+				     request->destBuffer_.get(), request);
 }
 
 void CameraStream::handleProcessComplete(Camera3RequestDescriptor *request)
diff --git a/src/android/camera_stream.h b/src/android/camera_stream.h
index d4ec5c25..42db72d8 100644
--- a/src/android/camera_stream.h
+++ b/src/android/camera_stream.h
@@ -13,6 +13,8 @@
 
 #include <hardware/camera3.h>
 
+#include <libcamera/base/thread.h>
+
 #include <libcamera/camera.h>
 #include <libcamera/framebuffer.h>
 #include <libcamera/framebuffer_allocator.h>
@@ -113,6 +115,8 @@ public:
 	CameraStream(CameraDevice *const cameraDevice,
 		     libcamera::CameraConfiguration *config, Type type,
 		     camera3_stream_t *camera3Stream, unsigned int index);
+	CameraStream(CameraStream &&other) = default;
+	~CameraStream();
 
 	Type type() const { return type_; }
 	const camera3_stream_t &camera3Stream() const { return *camera3Stream_; }
@@ -143,6 +147,7 @@ private:
 	 */
 	std::unique_ptr<std::mutex> mutex_;
 	std::unique_ptr<PostProcessor> postProcessor_;
+	std::unique_ptr<libcamera::Thread> thread_;
 };
 
 #endif /* __ANDROID_CAMERA_STREAM__ */
diff --git a/src/android/post_processor.h b/src/android/post_processor.h
index 48ddd8ac..fdfd52d3 100644
--- a/src/android/post_processor.h
+++ b/src/android/post_processor.h
@@ -7,6 +7,7 @@
 #ifndef __ANDROID_POST_PROCESSOR_H__
 #define __ANDROID_POST_PROCESSOR_H__
 
+#include <libcamera/base/object.h>
 #include <libcamera/base/signal.h>
 
 #include <libcamera/framebuffer.h>
@@ -18,7 +19,7 @@ class CameraMetadata;
 
 struct Camera3RequestDescriptor;
 
-class PostProcessor
+class PostProcessor : public libcamera::Object
 {
 public:
 	virtual ~PostProcessor() = default;
