diff options
-rw-r--r-- | src/qcam/main_window.cpp | 110 | ||||
-rw-r--r-- | src/qcam/main_window.h | 8 |
2 files changed, 79 insertions, 39 deletions
diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index b9348111..0bd9f358 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -281,17 +281,30 @@ void MainWindow::toggleCapture(bool start) int MainWindow::startCapture() { StreamRoles roles = StreamKeyValueParser::roles(options_[OptStream]); + std::vector<Request *> requests; int ret; /* Verify roles are supported. */ - if (roles.size() != 1) { - qCritical() << "Only one stream supported"; - return -EINVAL; - } - - if (roles[0] != StreamRole::Viewfinder) { - qCritical() << "Only viewfinder supported"; - return -EINVAL; + switch (roles.size()) { + case 1: + if (roles[0] != StreamRole::Viewfinder) { + qWarning() << "Only viewfinder supported for single stream"; + return -EINVAL; + } + break; + case 2: + if (roles[0] != StreamRole::Viewfinder || + roles[1] != StreamRole::StillCaptureRaw) { + qWarning() << "Only viewfinder + raw supported for dual streams"; + return -EINVAL; + } + break; + default: + if (roles.size() != 1) { + qWarning() << "Unsuported stream configuration"; + return -EINVAL; + } + break; } /* Configure the camera. */ @@ -301,17 +314,17 @@ int MainWindow::startCapture() return -EINVAL; } - StreamConfiguration &cfg = config_->at(0); + StreamConfiguration &vfConfig = config_->at(0); /* Use a format supported by the viewfinder if available. */ - std::vector<PixelFormat> formats = cfg.formats().pixelformats(); + std::vector<PixelFormat> formats = vfConfig.formats().pixelformats(); for (const PixelFormat &format : viewfinder_->nativeFormats()) { auto match = std::find_if(formats.begin(), formats.end(), [&](const PixelFormat &f) { return f == format; }); if (match != formats.end()) { - cfg.pixelFormat = format; + vfConfig.pixelFormat = format; break; } } @@ -331,7 +344,7 @@ int MainWindow::startCapture() if (validation == CameraConfiguration::Adjusted) qInfo() << "Stream configuration adjusted to " - << cfg.toString().c_str(); + << vfConfig.toString().c_str(); ret = camera_->configure(config_.get()); if (ret < 0) { @@ -339,10 +352,16 @@ int MainWindow::startCapture() return ret; } + /* Store stream allocation. */ + vfStream_ = config_->at(0).stream(); + if (config_->size() == 2) + rawStream_ = config_->at(1).stream(); + else + rawStream_ = nullptr; + /* Configure the viewfinder. */ - Stream *stream = cfg.stream(); - ret = viewfinder_->setFormat(cfg.pixelFormat, - QSize(cfg.size.width, cfg.size.height)); + ret = viewfinder_->setFormat(vfConfig.pixelFormat, + QSize(vfConfig.size.width, vfConfig.size.height)); if (ret < 0) { qInfo() << "Failed to set viewfinder format"; return ret; @@ -350,16 +369,33 @@ int MainWindow::startCapture() adjustSize(); - /* Allocate buffers and requests. */ + /* Allocate and map buffers. */ allocator_ = new FrameBufferAllocator(camera_); - ret = allocator_->allocate(stream); - if (ret < 0) { - qWarning() << "Failed to allocate capture buffers"; - return ret; + for (StreamConfiguration &config : *config_) { + Stream *stream = config.stream(); + + ret = allocator_->allocate(stream); + if (ret < 0) { + qWarning() << "Failed to allocate capture buffers"; + goto error; + } + + for (const std::unique_ptr<FrameBuffer> &buffer : allocator_->buffers(stream)) { + /* Map memory buffers and cache the mappings. */ + const FrameBuffer::Plane &plane = buffer->planes().front(); + void *memory = mmap(NULL, plane.length, PROT_READ, MAP_SHARED, + plane.fd.fd(), 0); + mappedBuffers_[buffer.get()] = { memory, plane.length }; + + /* Store buffers on the free list. */ + freeBuffers_[stream].enqueue(buffer.get()); + } } - std::vector<Request *> requests; - for (const std::unique_ptr<FrameBuffer> &buffer : allocator_->buffers(stream)) { + /* Create requests and fill them with buffers from the viewfinder. */ + while (!freeBuffers_[vfStream_].isEmpty()) { + FrameBuffer *buffer = freeBuffers_[vfStream_].dequeue(); + Request *request = camera_->createRequest(); if (!request) { qWarning() << "Can't create request"; @@ -367,19 +403,13 @@ int MainWindow::startCapture() goto error; } - ret = request->addBuffer(stream, buffer.get()); + ret = request->addBuffer(vfStream_, buffer); if (ret < 0) { qWarning() << "Can't set buffer for request"; goto error; } requests.push_back(request); - - /* Map memory buffers and cache the mappings. */ - const FrameBuffer::Plane &plane = buffer->planes().front(); - void *memory = mmap(NULL, plane.length, PROT_READ, MAP_SHARED, - plane.fd.fd(), 0); - mappedBuffers_[buffer.get()] = { memory, plane.length }; } /* Start the title timer and the camera. */ @@ -424,6 +454,8 @@ error: } mappedBuffers_.clear(); + freeBuffers_.clear(); + delete allocator_; allocator_ = nullptr; @@ -466,6 +498,7 @@ void MainWindow::stopCapture() * but not processed yet. Clear the queue of done buffers to avoid * racing with the event handler. */ + freeBuffers_.clear(); doneQueue_.clear(); titleTimer_.stop(); @@ -505,12 +538,9 @@ void MainWindow::requestComplete(Request *request) * are not allowed. Add the buffer to the done queue and post a * CaptureEvent for the application thread to handle. */ - const std::map<Stream *, FrameBuffer *> &buffers = request->buffers(); - FrameBuffer *buffer = buffers.begin()->second; - { QMutexLocker locker(&mutex_); - doneQueue_.enqueue(buffer); + doneQueue_.enqueue(request->buffers()); } QCoreApplication::postEvent(this, new CaptureEvent); @@ -523,16 +553,23 @@ void MainWindow::processCapture() * if stopCapture() has been called while a CaptureEvent was posted but * not processed yet. Return immediately in that case. */ - FrameBuffer *buffer; + std::map<Stream *, FrameBuffer *> buffers; { QMutexLocker locker(&mutex_); if (doneQueue_.isEmpty()) return; - buffer = doneQueue_.dequeue(); + buffers = doneQueue_.dequeue(); } + /* Process buffers. */ + if (buffers.count(vfStream_)) + processViewfinder(buffers[vfStream_]); +} + +void MainWindow::processViewfinder(FrameBuffer *buffer) +{ framesCaptured_++; const FrameMetadata &metadata = buffer->metadata(); @@ -559,8 +596,7 @@ void MainWindow::queueRequest(FrameBuffer *buffer) return; } - Stream *stream = config_->at(0).stream(); - request->addBuffer(stream, buffer); + request->addBuffer(vfStream_, buffer); camera_->queueRequest(request); } diff --git a/src/qcam/main_window.h b/src/qcam/main_window.h index aea1f1de..4856ecc1 100644 --- a/src/qcam/main_window.h +++ b/src/qcam/main_window.h @@ -69,6 +69,7 @@ private: void requestComplete(Request *request); void processCapture(); + void processViewfinder(FrameBuffer *buffer); /* UI elements */ QToolBar *toolbar_; @@ -95,8 +96,11 @@ private: /* Capture state, buffers queue and statistics */ bool isCapturing_; - QQueue<FrameBuffer *> doneQueue_; - QMutex mutex_; /* Protects doneQueue_ */ + Stream *vfStream_; + Stream *rawStream_; + std::map<Stream *, QQueue<FrameBuffer *>> freeBuffers_; + QQueue<std::map<Stream *, FrameBuffer *>> doneQueue_; + QMutex mutex_; /* Protects freeBuffers_ and doneQueue_ */ uint64_t lastBufferTime_; QElapsedTimer frameRateInterval_; |