summaryrefslogtreecommitdiff
path: root/src/cam/options.h
AgeCommit message (Expand)Author
2021-07-22cam: options: Avoid copies of OptionvValue and KeyValueParser::OptionsLaurent Pinchart
2021-07-22cam: options: Add empty() function to OptionValue classLaurent Pinchart
2021-07-22cam: options: Drop some OptionValue cast operatorsLaurent Pinchart
2021-07-22cam: options: Support parent-child relationship between optionsLaurent Pinchart
2021-07-22cam: options: Move key string left in usage() for key-value parserLaurent Pinchart
2021-07-22cam: options: Disable copy for parsersLaurent Pinchart
2021-07-22cam: options: Slit OptionsParser::usage() in two functionsLaurent Pinchart
2021-07-22cam: options: Add optionName() function to Option structureLaurent Pinchart
2021-07-22cam: options: Move OptionValue class after OptionsParserLaurent Pinchart
2021-07-22cam: options: Move Option struct to options.cppLaurent Pinchart
2021-07-22cam: options: Make KeyValueParser::usage() privateLaurent Pinchart
2020-10-23libcamera: Declare empty virtual destructors as defaultedLaurent Pinchart
2020-05-01cam: options: Add public method to invalidate optionsNiklas Söderlund
2020-05-01cam: options: Make KeyValueParser::parse() virtualNiklas Söderlund
2019-03-27cam: Separate options valid() and empty()Laurent Pinchart
2019-03-27cam: options: Add support for repeatable optionsNiklas Söderlund
2019-03-27cam: options: Add an array data type to OptionValueNiklas Söderlund
2019-03-25cam: options: Create separate enum for OptionValue typesNiklas Söderlund
2019-02-13cam: options: Fix coding style issue related to templatesLaurent Pinchart
2019-02-01cam: options: Add explicit conversion methods to OptionValueLaurent Pinchart
2019-02-01cam: options: Add a key=value parserNiklas Söderlund
2019-02-01cam: options: Add option type handling to options parserLaurent Pinchart
2019-02-01cam: options: Store options in a list instead of a vectorLaurent Pinchart
2019-02-01cam: options: Return whether addOption() succeeds or notNiklas Söderlund
2019-02-01cam: options: Create a template class for optionsNiklas Söderlund
2019-02-01cam: options: Move struct OptionLaurent Pinchart
2019-02-01cam: options: Move enum OptionArgumentNiklas Söderlund
2019-01-22cam: options: Don't implement move semantics for OptionsParser::OptionsLaurent Pinchart
2019-01-22cam: Extract option parser to separate fileLaurent Pinchart
an class="hl kwd">SDLSink() : window_(nullptr), renderer_(nullptr), rect_({}), init_(false) { } SDLSink::~SDLSink() { stop(); } int SDLSink::configure(const libcamera::CameraConfiguration &config) { int ret = FrameSink::configure(config); if (ret < 0) return ret; if (config.size() > 1) { std::cerr << "SDL sink only supports one camera stream at present, streaming first camera stream" << std::endl; } else if (config.empty()) { std::cerr << "Require at least one camera stream to process" << std::endl; return -EINVAL; } const libcamera::StreamConfiguration &cfg = config.at(0); rect_.w = cfg.size.width; rect_.h = cfg.size.height; switch (cfg.pixelFormat) { #ifdef HAVE_LIBJPEG case libcamera::formats::MJPEG: texture_ = std::make_unique<SDLTextureMJPG>(rect_); break; #endif case libcamera::formats::YUYV: texture_ = std::make_unique<SDLTextureYUYV>(rect_); break; default: std::cerr << "Unsupported pixel format " << cfg.pixelFormat.toString() << std::endl; return -EINVAL; }; return 0; } int SDLSink::start() { int ret = SDL_Init(SDL_INIT_VIDEO); if (ret) { std::cerr << "Failed to initialize SDL: " << SDL_GetError() << std::endl; return ret; } init_ = true; window_ = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, rect_.w, rect_.h, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); if (!window_) { std::cerr << "Failed to create SDL window: " << SDL_GetError() << std::endl; return -EINVAL; } renderer_ = SDL_CreateRenderer(window_, -1, 0); if (!renderer_) { std::cerr << "Failed to create SDL renderer: " << SDL_GetError() << std::endl; return -EINVAL; } /* * Set for scaling purposes, not critical, don't return in case of * error. */ ret = SDL_RenderSetLogicalSize(renderer_, rect_.w, rect_.h); if (ret) std::cerr << "Failed to set SDL render logical size: " << SDL_GetError() << std::endl; ret = texture_->create(renderer_); if (ret) { return ret; } /* \todo Make the event cancellable to support stop/start cycles. */ EventLoop::instance()->addTimerEvent( 10ms, std::bind(&SDLSink::processSDLEvents, this)); return 0; } int SDLSink::stop() { texture_.reset(); if (renderer_) { SDL_DestroyRenderer(renderer_); renderer_ = nullptr; } if (window_) { SDL_DestroyWindow(window_); window_ = nullptr; } if (init_) { SDL_Quit(); init_ = false; } return FrameSink::stop(); } void SDLSink::mapBuffer(FrameBuffer *buffer) { std::unique_ptr<Image> image = Image::fromFrameBuffer(buffer, Image::MapMode::ReadOnly); assert(image != nullptr); mappedBuffers_[buffer] = std::move(image); } bool SDLSink::processRequest(Request *request) { for (auto [stream, buffer] : request->buffers()) { renderBuffer(buffer); break; /* to be expanded to launch SDL window per buffer */ } return true; } /* * Process SDL events, required for things like window resize and quit button */ void SDLSink::processSDLEvents() { for (SDL_Event e; SDL_PollEvent(&e);) { if (e.type == SDL_QUIT) { /* Click close icon then quit */ EventLoop::instance()->exit(0); } } } void SDLSink::renderBuffer(FrameBuffer *buffer) { Image *image = mappedBuffers_[buffer].get(); /* \todo Implement support for multi-planar formats. */ const FrameMetadata::Plane &meta = buffer->metadata().planes()[0]; Span<uint8_t> data = image->data(0); if (meta.bytesused > data.size()) std::cerr << "payload size " << meta.bytesused << " larger than plane size " << data.size() << std::endl; texture_->update(data); SDL_RenderClear(renderer_); SDL_RenderCopy(renderer_, texture_->get(), nullptr, nullptr); SDL_RenderPresent(renderer_); }