|
6 | 6 | #include <libcamera/formats.h> |
7 | 7 | #include <libcamera/framebuffer_allocator.h> |
8 | 8 | #include <QDebug> |
| 9 | +#include <sys/mman.h> |
9 | 10 |
|
10 | 11 | using namespace libcamera; |
11 | 12 |
|
@@ -285,16 +286,82 @@ void LibCameraWorker::captureImage() |
285 | 286 |
|
286 | 287 | void LibCameraWorker::queueViewfinderRequest() |
287 | 288 | { |
288 | | - if (!mCamera) return; |
289 | | - // Similar to captureImage but re-use buffers and emit frameReady for previews. |
290 | | - // TODO: implement re-queueing multiple requests, handle Request::completed, reuse buffers |
| 289 | + if (!mCamera || mBuffers.empty()) return; |
| 290 | + |
| 291 | + // Create a request |
| 292 | + std::shared_ptr<Request> request = mCamera->createRequest(); |
| 293 | + if (!request) { |
| 294 | + Q_EMIT errorOccurred("libcamera: createRequest failed for preview"); |
| 295 | + return; |
| 296 | + } |
| 297 | + |
| 298 | + // Get next buffer (rotate through available buffers) |
| 299 | + FrameBuffer *fb = mBuffers[mBufferIndex % mBuffers.size()].get(); |
| 300 | + mBufferIndex++; |
| 301 | + |
| 302 | + // Attach buffer to stream |
| 303 | + Stream *stream = *mCamera->streams().begin(); |
| 304 | + if (request->addBuffer(stream, fb) < 0) { |
| 305 | + Q_EMIT errorOccurred("libcamera: addBuffer failed for preview"); |
| 306 | + return; |
| 307 | + } |
| 308 | + |
| 309 | + // Store request to keep it alive |
| 310 | + mPendingRequests.push_back(request); |
| 311 | + |
| 312 | + // Queue the request (async completion via event loop) |
| 313 | + if (mCamera->queueRequest(request.get()) < 0) { |
| 314 | + Q_EMIT errorOccurred("libcamera: queueRequest failed for preview"); |
| 315 | + mPendingRequests.pop_back(); |
| 316 | + return; |
| 317 | + } |
| 318 | + |
| 319 | + // In production libcamera, you'd use a callback/event loop. |
| 320 | + // For now, use a simple timer-based poll as fallback: |
| 321 | + QTimer::singleShot(50, this, [this, request]() { |
| 322 | + if (request->status() == Request::RequestComplete) { |
| 323 | + processCompletedRequest(request.get()); |
| 324 | + // Remove completed request from pending list |
| 325 | + auto it = std::find(mPendingRequests.begin(), mPendingRequests.end(), request); |
| 326 | + if (it != mPendingRequests.end()) |
| 327 | + mPendingRequests.erase(it); |
| 328 | + // Queue next preview |
| 329 | + if (mRunning) |
| 330 | + queueViewfinderRequest(); |
| 331 | + } |
| 332 | + }); |
| 333 | +} |
| 334 | + |
| 335 | +void LibCameraWorker::processCompletedRequest(Request *request) |
| 336 | +{ |
| 337 | + if (!request || request->buffers().empty()) return; |
| 338 | + |
| 339 | + auto it = request->buffers().begin(); |
| 340 | + FrameBuffer *completedFb = it->second; |
| 341 | + |
| 342 | + // Convert buffer to QImage and emit preview |
| 343 | + QImage preview = convertBufferToImage(*completedFb); |
| 344 | + if (!preview.isNull()) |
| 345 | + Q_EMIT frameReady(preview); |
291 | 346 | } |
292 | 347 |
|
293 | 348 | QImage LibCameraWorker::convertBufferToImage(const FrameBuffer &fb) |
294 | 349 | { |
295 | | - // TODO: implement conversion from FrameBuffer payload to QImage. |
296 | | - // If fb.pixelFormat() == formats::RGB888 you can construct QImage directly from buffer. |
297 | | - // If YUV, use conversion (libyuv/opencv) to RGB. |
298 | | - // Placeholder empty image: |
299 | | - return QImage(); |
| 350 | + if (fb.planes().empty()) return QImage(); |
| 351 | + |
| 352 | + const FrameMetadata &metadata = fb.metadata(); |
| 353 | + uint32_t width = metadata.planes()[0].bytesused / 3; // Assume RGB888 (3 bytes per pixel) |
| 354 | + uint32_t height = fb.planes()[0].length / metadata.planes()[0].bytesused; |
| 355 | + |
| 356 | + if (width == 0 || height == 0) return QImage(); |
| 357 | + |
| 358 | + // Map buffer to accessible |
| 359 | + void *data = mmap(NULL, fb.planes()[0].length, PROT_READ | PROT_WRITE, MAP_SHARED, fb.planes()[0].fd.get(), 0); |
| 360 | + |
| 361 | + // Create QImage from RGB888 data (copy data) |
| 362 | + QImage image(width, height, QImage::Format_RGB888); |
| 363 | + std::memcpy(image.bits(), data, image.sizeInBytes()); |
| 364 | + |
| 365 | + return image; |
300 | 366 | } |
| 367 | + |
0 commit comments