Skip to content

Commit 4839f9b

Browse files
committed
implement libcameradevice
1 parent 6e8edf5 commit 4839f9b

2 files changed

Lines changed: 147 additions & 17 deletions

File tree

src/libcameracamera.cpp

Lines changed: 111 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,105 @@
55
#include <thread>
66
#include <libcamera/formats.h>
77
#include <libcamera/framebuffer_allocator.h>
8+
#include <QDebug>
89

910
using 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+
11107
LibCameraWorker::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
47143
void 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()
134230
void 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
}

src/libcameracamera.h

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,54 @@
1414
#define slots Q_SLOTS
1515
#define emit Q_EMIT
1616

17+
18+
class LibCameraWorker;
19+
20+
class LibcameraDevice : public QObject
21+
{
22+
Q_OBJECT
23+
public:
24+
explicit LibcameraDevice(QObject *parent = nullptr);
25+
~LibcameraDevice() override;
26+
27+
QStringList availableCameras() const;
28+
QString getDefaultCamera() const;
29+
30+
public slots:
31+
void startCamera(const QString &cameraId);
32+
void stopCamera();
33+
void captureImage();
34+
35+
signals:
36+
void frameReady(const QImage &image);
37+
void imageCaptured(const QImage &image);
38+
void errorOccurred(const QString &error);
39+
40+
private slots:
41+
void onFrameReady(const QImage &image);
42+
void onImageCaptured(const QImage &image);
43+
void onErrorOccurred(const QString &error);
44+
45+
private:
46+
std::unique_ptr<QThread> mWorkerThread;
47+
LibCameraWorker *mWorker = nullptr;
48+
};
49+
50+
1751
class LibCameraWorker : public QObject
1852
{
1953
Q_OBJECT
2054
public:
2155
explicit LibCameraWorker(QObject *parent = nullptr);
2256
~LibCameraWorker() override;
2357

24-
public Q_SLOTS:
58+
public slots:
2559
void startCamera(const QString &cameraId); // cameraId as returned by CameraManager
2660
void stopCamera();
2761
void captureImage(); // single capture -> emits imageCaptured
2862
QStringList availableCameras() const;
2963

30-
Q_SIGNALS:
64+
signals:
3165
void frameReady(const QImage &image); // optionally emit preview frames
3266
void imageCaptured(const QImage &image); // emitted after captureImage
3367
void errorOccurred(const QString &err);

0 commit comments

Comments
 (0)