55#include < thread>
66#include < libcamera/formats.h>
77#include < libcamera/framebuffer_allocator.h>
8+ #include < QDebug>
89
910using namespace libcamera ;
1011
12+ LibcameraDevice::LibcameraDevice (QObject *parent)
13+ : QObject(parent),
14+ mWorkerThread(std::make_unique<QThread>(this ))
15+ {
16+ // Create worker
17+ mWorker = new LibCameraWorker ();
18+ mWorker ->moveToThread (mWorkerThread .get ());
19+
20+ // Connect worker signals to device signals (relay/forward)
21+ connect (mWorker , &LibCameraWorker::frameReady,
22+ this , &LibcameraDevice::onFrameReady);
23+ connect (mWorker , &LibCameraWorker::imageCaptured,
24+ this , &LibcameraDevice::onImageCaptured);
25+ connect (mWorker , &LibCameraWorker::errorOccurred,
26+ this , &LibcameraDevice::onErrorOccurred);
27+
28+ // Connect device slots to worker slots
29+ connect (this , &LibcameraDevice::startCamera,
30+ mWorker , &LibCameraWorker::startCamera);
31+ connect (this , &LibcameraDevice::stopCamera,
32+ mWorker , &LibCameraWorker::stopCamera);
33+ connect (this , &LibcameraDevice::captureImage,
34+ mWorker , &LibCameraWorker::captureImage);
35+
36+ // Clean up when thread finishes
37+ connect (mWorkerThread .get (), &QThread::finished,
38+ mWorker , &QObject::deleteLater);
39+
40+ // Start thread
41+ mWorkerThread ->start ();
42+
43+ qDebug () << " [INFO] LibcameraDevice initialized" ;
44+ }
45+
46+ LibcameraDevice::~LibcameraDevice ()
47+ {
48+ if (mWorkerThread ) {
49+ mWorkerThread ->quit ();
50+ mWorkerThread ->wait (3000 );
51+ }
52+ qDebug () << " [INFO] LibcameraDevice destroyed" ;
53+ }
54+
55+ QStringList LibcameraDevice::availableCameras () const
56+ {
57+ QStringList cameras;
58+ if (mWorker ) {
59+ // Block until worker returns result
60+ QMetaObject::invokeMethod (mWorker , [this , &cameras]() {
61+ cameras = mWorker ->availableCameras ();
62+ }, Qt::BlockingQueuedConnection);
63+ }
64+ return cameras;
65+ }
66+
67+ QString LibcameraDevice::getDefaultCamera () const
68+ {
69+ QStringList cameras = availableCameras ();
70+ return cameras.isEmpty () ? QString () : cameras.first ();
71+ }
72+
73+ void LibcameraDevice::startCamera (const QString &cameraId)
74+ {
75+ QMetaObject::invokeMethod (mWorker , " startCamera" ,
76+ Qt::QueuedConnection,
77+ Q_ARG (QString, cameraId));
78+ }
79+
80+ void LibcameraDevice::stopCamera ()
81+ {
82+ QMetaObject::invokeMethod (mWorker , " stopCamera" ,
83+ Qt::QueuedConnection);
84+ }
85+
86+ void LibcameraDevice::captureImage ()
87+ {
88+ QMetaObject::invokeMethod (mWorker , " captureImage" ,
89+ Qt::QueuedConnection);
90+ }
91+
92+ void LibcameraDevice::onFrameReady (const QImage &image)
93+ {
94+ emit frameReady (image);
95+ }
96+
97+ void LibcameraDevice::onImageCaptured (const QImage &image)
98+ {
99+ emit imageCaptured (image);
100+ }
101+
102+ void LibcameraDevice::onErrorOccurred (const QString &error)
103+ {
104+ emit errorOccurred (error);
105+ }
106+
11107LibCameraWorker::LibCameraWorker (QObject *parent)
12108 : QObject(parent)
13109{
@@ -30,7 +126,7 @@ void LibCameraWorker::initCameraManager()
30126 mCameraManager = std::make_unique<CameraManager>();
31127 int ret = mCameraManager ->start ();
32128 if (ret) {
33- Q_EMIT errorOccurred (QString::asprintf (" libcamera: CameraManager start failed: %d" , ret));
129+ emit errorOccurred (QString::asprintf (" libcamera: CameraManager start failed: %d" , ret));
34130 mCameraManager .reset ();
35131 }
36132}
@@ -47,7 +143,7 @@ QStringList LibCameraWorker::availableCameras() const
47143void LibCameraWorker::startCamera (const QString &cameraId)
48144{
49145 if (!mCameraManager ) {
50- Q_EMIT errorOccurred (" libcamera: CameraManager not initialized" );
146+ emit errorOccurred (" libcamera: CameraManager not initialized" );
51147 return ;
52148 }
53149
@@ -56,7 +152,7 @@ void LibCameraWorker::startCamera(const QString &cameraId)
56152 // find camera by id
57153 std::shared_ptr<Camera> cam = mCameraManager ->get (cameraId.toStdString ());
58154 if (!cam) {
59- Q_EMIT errorOccurred (" libcamera: camera not found: " + cameraId);
155+ emit errorOccurred (" libcamera: camera not found: " + cameraId);
60156 return ;
61157 }
62158 mCamera = cam;
@@ -65,7 +161,7 @@ void LibCameraWorker::startCamera(const QString &cameraId)
65161 std::unique_ptr<CameraConfiguration> config =
66162 mCamera ->generateConfiguration ({ StreamRole::Viewfinder });
67163 if (!config) {
68- Q_EMIT errorOccurred (" libcamera: failed to generate configuration" );
164+ emit errorOccurred (" libcamera: failed to generate configuration" );
69165 mCamera .reset ();
70166 return ;
71167 }
@@ -77,13 +173,13 @@ void LibCameraWorker::startCamera(const QString &cameraId)
77173 config->at (0 ).bufferCount = 4 ;
78174
79175 if (config->validate () == CameraConfiguration::Invalid) {
80- Q_EMIT errorOccurred (" libcamera: configuration invalid" );
176+ emit errorOccurred (" libcamera: configuration invalid" );
81177 mCamera .reset ();
82178 return ;
83179 }
84180
85181 if (mCamera ->configure (config.get ()) < 0 ) {
86- Q_EMIT errorOccurred (" libcamera: camera configure failed" );
182+ emit errorOccurred (" libcamera: camera configure failed" );
87183 mCamera .reset ();
88184 return ;
89185 }
@@ -93,7 +189,7 @@ void LibCameraWorker::startCamera(const QString &cameraId)
93189 for (StreamConfiguration &cfg : *config) {
94190 Stream *stream = cfg.stream ();
95191 if (mAllocator ->allocate (stream) < 0 ) {
96- Q_EMIT errorOccurred (" libcamera: buffer allocation failed" );
192+ emit errorOccurred (" libcamera: buffer allocation failed" );
97193 mCamera .reset ();
98194 return ;
99195 }
@@ -104,7 +200,7 @@ void LibCameraWorker::startCamera(const QString &cameraId)
104200
105201 // start camera
106202 if (mCamera ->start () < 0 ) {
107- Q_EMIT errorOccurred (" libcamera: start failed" );
203+ emit errorOccurred (" libcamera: start failed" );
108204 mCamera .reset ();
109205 return ;
110206 }
@@ -134,32 +230,32 @@ void LibCameraWorker::stopCamera()
134230void LibCameraWorker::captureImage ()
135231{
136232 if (!mRunning || !mCamera ) {
137- Q_EMIT errorOccurred (" libcamera: camera not running" );
233+ emit errorOccurred (" libcamera: camera not running" );
138234 return ;
139235 }
140236
141237 // Create a request and keep it alive until completion
142238 std::unique_ptr<Request> request = mCamera ->createRequest ();
143239 if (!request) {
144- Q_EMIT errorOccurred (" libcamera: createRequest failed" );
240+ emit errorOccurred (" libcamera: createRequest failed" );
145241 return ;
146242 }
147243
148244 // attach first available buffer for viewfinder stream (simplified)
149245 Stream *stream = *mCamera ->streams ().begin ();
150246 if (mBuffers .empty ()) {
151- Q_EMIT errorOccurred (" libcamera: no buffers available" );
247+ emit errorOccurred (" libcamera: no buffers available" );
152248 return ;
153249 }
154250 FrameBuffer *fb = mBuffers .front ().get ();
155251 if (request->addBuffer (stream, fb) < 0 ) {
156- Q_EMIT errorOccurred (" libcamera: addBuffer failed" );
252+ emit errorOccurred (" libcamera: addBuffer failed" );
157253 return ;
158254 }
159255
160256 // queue request
161257 if (mCamera ->queueRequest (request.get ()) < 0 ) {
162- Q_EMIT errorOccurred (" libcamera: queueRequest failed" );
258+ emit errorOccurred (" libcamera: queueRequest failed" );
163259 return ;
164260 }
165261
@@ -172,7 +268,7 @@ void LibCameraWorker::captureImage()
172268 }
173269
174270 if (request->status () != Request::RequestComplete) {
175- Q_EMIT errorOccurred (" libcamera: capture failed or timed out" );
271+ emit errorOccurred (" libcamera: capture failed or timed out" );
176272 // let request be destroyed / cleaned up
177273 return ;
178274 }
@@ -182,7 +278,7 @@ void LibCameraWorker::captureImage()
182278 auto it = request->buffers ().begin ();
183279 FrameBuffer *completedFb = it->second ;
184280 QImage img = convertBufferToImage (*completedFb);
185- Q_EMIT imageCaptured (img);
281+ emit imageCaptured (img);
186282 }
187283 // request destroyed when leaving scope
188284}
0 commit comments