summaryrefslogtreecommitdiff
AgeCommit message (Expand)Author
2022-08-09ipa: ipu3: Add YAML tuning file supportLaurent Pinchart
2022-08-09ipa: ipu3: Register algorithmsLaurent Pinchart
2022-08-09ipa: ipu3: Add an uncalibrated.yaml tuning data fileLaurent Pinchart
2022-08-09pipeline: ipu3: Support IPA tuning fileLaurent Pinchart
2022-08-09libcamera: yaml_parser: Return nullopt on error from YamlObject::get()Laurent Pinchart
2022-08-09cam: sdl_texture: Rename 'pitch' to 'stride'Laurent Pinchart
2022-08-09ipa: rkisp1: Remove unused algorithms includes from rkisp1.cppDaniel Semkowicz
2022-08-09libcamera: Make IPA module signing recommended instead of mandatoryLaurent Pinchart
2022-08-09libcamera: pub_key: Support openssl as an alternative to gnutlsLaurent Pinchart
2022-08-09libcamera: pub_key: Gracefully handle failures to load public keyLaurent Pinchart
2022-08-09libcamera: meson: Use dependency() to find gnutlsLaurent Pinchart
2022-08-09libcamera: controls: Generate and use fixed-sized Span typesChristian Rauch
2022-08-09cam: kms_sink: Scale the frame buffer to full screen if supportedLaurent Pinchart
2022-08-09cam: kms_sink: Make lifetime management of DRM request saferLaurent Pinchart
2022-08-09cam: drm: Add support for test-only commitsLaurent Pinchart
2022-08-08cam: sdl_sink: Fix compilation with SDL2 <2.0.16Laurent Pinchart
2022-08-08cam: sdl_sink: Add NV12 texture supportLaurent Pinchart
2022-08-08cam: sdl_sink: Support multi-planar formatsLaurent Pinchart
2022-08-08cam: Rename sdl_texture_yuyv.{cpp,h} to sdl_texture_yuv.{cpp,h}Laurent Pinchart
2022-08-08cam: sdl_texture_yuyv: Make line stride configurableLaurent Pinchart
2022-08-04libcamera: Correct typos and omissions for packed 10-bit raw monochrome formatDavid Plowman
2022-08-04libcamera: Switch internal YAML files to YAML 1.1Laurent Pinchart
2022-08-04ipa: rkisp1: Use YAML 1.1 for tuning data filesLaurent Pinchart
2022-08-04pipeline: rkisp1: Move ControlInfoMap to IPA moduleLaurent Pinchart
2022-08-03libcamera: pipeline: simple: Add support for NXP ISILaurent Pinchart
2022-08-03libcamera: pipeline: simple: Don't disable links carrying other streamsLaurent Pinchart
2022-08-03libcamera: pipeline: simple: Walk pipeline using subdev internal routingPhi-Bang Nguyen
2022-08-03libcamera: pipeline: simple: Setup links in the context of sink entitiesLaurent Pinchart
2022-08-03libcamera: pipeline: simple: Reset routing table of subdevsJacopo Mondi
2022-08-03libcamera: v4l2_subdevice: Add support for the V4L2 subdev routing APIJacopo Mondi
2022-08-03libcamera: v4l2_subdevice: Collect subdev capabilitiesJacopo Mondi
2022-08-03libcamera: v4l2_subdevice: Change V4L2Subdevice::WhenceJacopo Mondi
2022-08-03include: linux: Add V4L2 subdev internal routing APILaurent Pinchart
2022-08-03libcamera: formats: Add AVUY8888 and XVUY8888 formatsLaurent Pinchart
2022-08-03include: linux: Add V4L2 YUVA32 and YUVX32 pixel formatsLaurent Pinchart
2022-08-03include: drm_fourcc: Add AVUY and XVUY 4:4:4 packet formatsLaurent Pinchart
2022-08-03include: linux: Update kernel headers to version v5.19Laurent Pinchart
2022-08-03libcamera: yaml_parser: Return nullopt on errorJacopo Mondi
2022-08-03libcamera: formats: Map V4L2_PIX_FMT_JPEG to formats::MJPEGJacopo Mondi
2022-08-03libcamera: v4l2_videodevice: Match formats supported by the deviceJacopo Mondi
2022-08-03libcamera: v4l2_pixelformat: Implement std::hash specializationLaurent Pinchart
2022-08-03libcamera: v4l2_pixelformat: Return the list of V4L2 formatsJacopo Mondi
2022-08-03libcamera: v4l2_videodevice: Reintroduce toV4L2PixelFormat()Jacopo Mondi
2022-08-03guides: pipeline handler: Remove rogue spacesJacopo Mondi
2022-08-03libcamera: formats: Merge V4L2 single and multi formatsJacopo Mondi
2022-08-03libcamera: formats: Reimplement V4L2 PixelFormatInfo::info()Jacopo Mondi
2022-08-03utils: raspberrypi: ctt: dng_load_image: Work with DNG files from Picamera2William Vinnicombe
2022-08-02utils: raspberrypi: ctt: Add alsc_only methodWilliam Vinnicombe
2022-08-02ipa: raspberrypi: Reset embedded data parser on configureDavid Plowman
2022-08-01test: yaml-parser: Test YamlObject::get(const T &defaultValue)Laurent Pinchart
kwd">fromStdString(CameraManager::version()); setWindowTitle(title_); connect(&titleTimer_, SIGNAL(timeout()), this, SLOT(updateTitle())); viewfinder_ = new ViewFinder(this); setCentralWidget(viewfinder_); adjustSize(); ret = openCamera(); if (!ret) ret = startCapture(); if (ret < 0) quit(); } MainWindow::~MainWindow() { if (camera_) { stopCapture(); camera_->release(); camera_.reset(); } } int MainWindow::createToolbars() { QAction *action; toolbar_ = addToolBar("Main"); /* Disable right click context menu. */ toolbar_->setContextMenuPolicy(Qt::PreventContextMenu); action = toolbar_->addAction(QIcon(":x-circle.svg"), "Quit"); connect(action, &QAction::triggered, this, &MainWindow::quit); /* Camera selection. */ QComboBox *cameraCombo = new QComboBox(); connect(cameraCombo, QOverload<int>::of(&QComboBox::activated), this, &MainWindow::switchCamera); for (const std::shared_ptr<Camera> &cam : cm_->cameras()) cameraCombo->addItem(QString::fromStdString(cam->name())); toolbar_->addWidget(cameraCombo); toolbar_->addSeparator(); action = toolbar_->addAction(QIcon(":play-circle.svg"), "start"); connect(action, &QAction::triggered, this, &MainWindow::startCapture); action = toolbar_->addAction(QIcon(":stop-circle.svg"), "stop"); connect(action, &QAction::triggered, this, &MainWindow::stopCapture); action = toolbar_->addAction(QIcon(":save.svg"), "saveAs"); connect(action, &QAction::triggered, this, &MainWindow::saveImageAs); return 0; } void MainWindow::quit() { QTimer::singleShot(0, QCoreApplication::instance(), &QCoreApplication::quit); } void MainWindow::updateTitle() { unsigned int duration = frameRateInterval_.elapsed(); unsigned int frames = framesCaptured_ - previousFrames_; double fps = frames * 1000.0 / duration; /* Restart counters. */ frameRateInterval_.start(); previousFrames_ = framesCaptured_; setWindowTitle(title_ + " : " + QString::number(fps, 'f', 2) + " fps"); } void MainWindow::switchCamera(int index) { const auto &cameras = cm_->cameras(); if (static_cast<unsigned int>(index) >= cameras.size()) return; const std::shared_ptr<Camera> &cam = cameras[index]; if (cam->acquire()) { std::cout << "Failed to acquire camera " << cam->name() << std::endl; return; } std::cout << "Switching to camera " << cam->name() << std::endl; stopCapture(); camera_->release(); camera_ = cam; startCapture(); } std::string MainWindow::chooseCamera() { QStringList cameras; bool result; if (cm_->cameras().size() == 1) return cm_->cameras()[0]->name(); for (const std::shared_ptr<Camera> &cam : cm_->cameras()) cameras.append(QString::fromStdString(cam->name())); QString name = QInputDialog::getItem(this, "Select Camera", "Camera:", cameras, 0, false, &result); if (!result) return std::string(); return name.toStdString(); } int MainWindow::openCamera() { std::string cameraName; if (options_.isSet(OptCamera)) cameraName = static_cast<std::string>(options_[OptCamera]); else cameraName = chooseCamera(); if (cameraName == "") return -EINVAL; camera_ = cm_->get(cameraName); if (!camera_) { std::cout << "Camera " << cameraName << " not found" << std::endl; return -ENODEV; } if (camera_->acquire()) { std::cout << "Failed to acquire camera" << std::endl; camera_.reset(); return -EBUSY; } std::cout << "Using camera " << camera_->name() << std::endl; return 0; } int MainWindow::startCapture() { int ret; config_ = camera_->generateConfiguration({ StreamRole::Viewfinder }); StreamConfiguration &cfg = config_->at(0); if (options_.isSet(OptSize)) { const std::vector<OptionValue> &sizeOptions = options_[OptSize].toArray(); /* Set desired stream size if requested. */ for (const auto &value : sizeOptions) { KeyValueParser::Options opt = value.toKeyValues(); if (opt.isSet("width")) cfg.size.width = opt["width"]; if (opt.isSet("height")) cfg.size.height = opt["height"]; } } CameraConfiguration::Status validation = config_->validate(); if (validation == CameraConfiguration::Invalid) { std::cerr << "Failed to create valid camera configuration"; return -EINVAL; } if (validation == CameraConfiguration::Adjusted) { std::cout << "Stream size adjusted to " << cfg.size.toString() << std::endl; } ret = camera_->configure(config_.get()); if (ret < 0) { std::cout << "Failed to configure camera" << std::endl; return ret; } Stream *stream = cfg.stream(); ret = viewfinder_->setFormat(cfg.pixelFormat, cfg.size.width, cfg.size.height); if (ret < 0) { std::cout << "Failed to set viewfinder format" << std::endl; return ret; } adjustSize(); allocator_ = new FrameBufferAllocator(camera_); ret = allocator_->allocate(stream); if (ret < 0) { std::cerr << "Failed to allocate capture buffers" << std::endl; return ret; } std::vector<Request *> requests; for (const std::unique_ptr<FrameBuffer> &buffer : allocator_->buffers(stream)) { Request *request = camera_->createRequest(); if (!request) { std::cerr << "Can't create request" << std::endl; ret = -ENOMEM; goto error; } ret = request->addBuffer(stream, buffer.get()); if (ret < 0) { std::cerr << "Can't set buffer for request" << std::endl; 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_[plane.fd.fd()] = std::make_pair(memory, plane.length); } titleTimer_.start(2000); frameRateInterval_.start(); previousFrames_ = 0; framesCaptured_ = 0; lastBufferTime_ = 0; ret = camera_->start(); if (ret) { std::cout << "Failed to start capture" << std::endl; goto error; } camera_->requestCompleted.connect(this, &MainWindow::requestComplete); for (Request *request : requests) { ret = camera_->queueRequest(request); if (ret < 0) { std::cerr << "Can't queue request" << std::endl; goto error_disconnect; } } isCapturing_ = true; return 0; error_disconnect: camera_->requestCompleted.disconnect(this, &MainWindow::requestComplete); camera_->stop(); error: for (Request *request : requests) delete request; for (auto &iter : mappedBuffers_) { void *memory = iter.second.first; unsigned int length = iter.second.second; munmap(memory, length); } mappedBuffers_.clear(); delete allocator_; allocator_ = nullptr; return ret; } void MainWindow::stopCapture() { if (!isCapturing_) return; int ret = camera_->stop(); if (ret) std::cout << "Failed to stop capture" << std::endl; camera_->requestCompleted.disconnect(this, &MainWindow::requestComplete); for (auto &iter : mappedBuffers_) { void *memory = iter.second.first; unsigned int length = iter.second.second; munmap(memory, length); } mappedBuffers_.clear(); delete allocator_; isCapturing_ = false; config_.reset(); titleTimer_.stop(); setWindowTitle(title_); } void MainWindow::saveImageAs() { QImage image = viewfinder_->getCurrentImage(); QString defaultPath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation); QString filename = QFileDialog::getSaveFileName(this, "Save Image", defaultPath, "Image Files (*.png *.jpg *.jpeg)"); std::cout << "Save image to " << filename.toStdString() << std::endl; if (filename.isEmpty()) return; QImageWriter writer(filename); writer.write(image); } void MainWindow::requestComplete(Request *request) { if (request->status() == Request::RequestCancelled) return; const std::map<Stream *, FrameBuffer *> &buffers = request->buffers(); framesCaptured_++; FrameBuffer *buffer = buffers.begin()->second; const FrameMetadata &metadata = buffer->metadata(); double fps = metadata.timestamp - lastBufferTime_; fps = lastBufferTime_ && fps ? 1000000000.0 / fps : 0.0; lastBufferTime_ = metadata.timestamp; std::cout << "seq: " << std::setw(6) << std::setfill('0') << metadata.sequence << " bytesused: " << metadata.planes[0].bytesused << " timestamp: " << metadata.timestamp << " fps: " << std::fixed << std::setprecision(2) << fps << std::endl; display(buffer); request = camera_->createRequest(); if (!request) { std::cerr << "Can't create request" << std::endl; return; } for (auto it = buffers.begin(); it != buffers.end(); ++it) { Stream *stream = it->first; FrameBuffer *buffer = it->second; request->addBuffer(stream, buffer); } camera_->queueRequest(request); } int MainWindow::display(FrameBuffer *buffer) { if (buffer->planes().size() != 1) return -EINVAL; const FrameBuffer::Plane &plane = buffer->planes().front(); void *memory = mappedBuffers_[plane.fd.fd()].first; unsigned char *raw = static_cast<unsigned char *>(memory); viewfinder_->display(raw, buffer->metadata().planes[0].bytesused); return 0; }