From 5e8933eeebcedda55d4c4e84db9b4983eecefe1b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 25 Mar 2020 09:36:35 +0200 Subject: libcamera: pipeline: Move uvcvideo and vimc to subdirectories MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Give a subdirectory to all pipeline handlers to make the structure of the source tree more consistent. This will also simplify the implementation of pipeline handlers selection at build time. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Reviewed-by: Niklas Söderlund --- src/libcamera/pipeline/meson.build | 7 +- src/libcamera/pipeline/uvcvideo.cpp | 394 ---------------------- src/libcamera/pipeline/uvcvideo/meson.build | 3 + src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 394 ++++++++++++++++++++++ src/libcamera/pipeline/vimc.cpp | 467 --------------------------- src/libcamera/pipeline/vimc/meson.build | 3 + src/libcamera/pipeline/vimc/vimc.cpp | 467 +++++++++++++++++++++++++++ 7 files changed, 869 insertions(+), 866 deletions(-) delete mode 100644 src/libcamera/pipeline/uvcvideo.cpp create mode 100644 src/libcamera/pipeline/uvcvideo/meson.build create mode 100644 src/libcamera/pipeline/uvcvideo/uvcvideo.cpp delete mode 100644 src/libcamera/pipeline/vimc.cpp create mode 100644 src/libcamera/pipeline/vimc/meson.build create mode 100644 src/libcamera/pipeline/vimc/vimc.cpp diff --git a/src/libcamera/pipeline/meson.build b/src/libcamera/pipeline/meson.build index 0d466225..c1a6ab04 100644 --- a/src/libcamera/pipeline/meson.build +++ b/src/libcamera/pipeline/meson.build @@ -1,7 +1,4 @@ -libcamera_sources += files([ - 'uvcvideo.cpp', - 'vimc.cpp', -]) - subdir('ipu3') subdir('rkisp1') +subdir('uvcvideo') +subdir('vimc') diff --git a/src/libcamera/pipeline/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo.cpp deleted file mode 100644 index ffbddf27..00000000 --- a/src/libcamera/pipeline/uvcvideo.cpp +++ /dev/null @@ -1,394 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2019, Google Inc. - * - * uvcvideo.cpp - Pipeline handler for uvcvideo devices - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "device_enumerator.h" -#include "log.h" -#include "media_device.h" -#include "pipeline_handler.h" -#include "utils.h" -#include "v4l2_controls.h" -#include "v4l2_videodevice.h" - -namespace libcamera { - -LOG_DEFINE_CATEGORY(UVC) - -class UVCCameraData : public CameraData -{ -public: - UVCCameraData(PipelineHandler *pipe) - : CameraData(pipe), video_(nullptr) - { - } - - ~UVCCameraData() - { - delete video_; - } - - int init(MediaEntity *entity); - void bufferReady(FrameBuffer *buffer); - - V4L2VideoDevice *video_; - Stream stream_; -}; - -class UVCCameraConfiguration : public CameraConfiguration -{ -public: - UVCCameraConfiguration(); - - Status validate() override; -}; - -class PipelineHandlerUVC : public PipelineHandler -{ -public: - PipelineHandlerUVC(CameraManager *manager); - - CameraConfiguration *generateConfiguration(Camera *camera, - const StreamRoles &roles) override; - int configure(Camera *camera, CameraConfiguration *config) override; - - int exportFrameBuffers(Camera *camera, Stream *stream, - std::vector> *buffers) override; - - int start(Camera *camera) override; - void stop(Camera *camera) override; - - int queueRequestDevice(Camera *camera, Request *request) override; - - bool match(DeviceEnumerator *enumerator) override; - -private: - int processControls(UVCCameraData *data, Request *request); - - UVCCameraData *cameraData(const Camera *camera) - { - return static_cast( - PipelineHandler::cameraData(camera)); - } -}; - -UVCCameraConfiguration::UVCCameraConfiguration() - : CameraConfiguration() -{ -} - -CameraConfiguration::Status UVCCameraConfiguration::validate() -{ - Status status = Valid; - - if (config_.empty()) - return Invalid; - - /* Cap the number of entries to the available streams. */ - if (config_.size() > 1) { - config_.resize(1); - status = Adjusted; - } - - StreamConfiguration &cfg = config_[0]; - const StreamFormats &formats = cfg.formats(); - const PixelFormat pixelFormat = cfg.pixelFormat; - const Size size = cfg.size; - - const std::vector pixelFormats = formats.pixelformats(); - auto iter = std::find(pixelFormats.begin(), pixelFormats.end(), pixelFormat); - if (iter == pixelFormats.end()) { - cfg.pixelFormat = pixelFormats.front(); - LOG(UVC, Debug) - << "Adjusting pixel format from " - << pixelFormat.toString() << " to " - << cfg.pixelFormat.toString(); - status = Adjusted; - } - - const std::vector &formatSizes = formats.sizes(cfg.pixelFormat); - cfg.size = formatSizes.front(); - for (const Size &formatsSize : formatSizes) { - if (formatsSize > size) - break; - - cfg.size = formatsSize; - } - - if (cfg.size != size) { - LOG(UVC, Debug) - << "Adjusting size from " << size.toString() - << " to " << cfg.size.toString(); - status = Adjusted; - } - - cfg.bufferCount = 4; - - return status; -} - -PipelineHandlerUVC::PipelineHandlerUVC(CameraManager *manager) - : PipelineHandler(manager) -{ -} - -CameraConfiguration *PipelineHandlerUVC::generateConfiguration(Camera *camera, - const StreamRoles &roles) -{ - UVCCameraData *data = cameraData(camera); - CameraConfiguration *config = new UVCCameraConfiguration(); - - if (roles.empty()) - return config; - - std::map> v4l2Formats = - data->video_->formats(); - std::map> deviceFormats; - std::transform(v4l2Formats.begin(), v4l2Formats.end(), - std::inserter(deviceFormats, deviceFormats.begin()), - [&](const decltype(v4l2Formats)::value_type &format) { - return decltype(deviceFormats)::value_type{ - data->video_->toPixelFormat(format.first), - format.second - }; - }); - - StreamFormats formats(deviceFormats); - StreamConfiguration cfg(formats); - - cfg.pixelFormat = formats.pixelformats().front(); - cfg.size = formats.sizes(cfg.pixelFormat).back(); - cfg.bufferCount = 4; - - config->addConfiguration(cfg); - - config->validate(); - - return config; -} - -int PipelineHandlerUVC::configure(Camera *camera, CameraConfiguration *config) -{ - UVCCameraData *data = cameraData(camera); - StreamConfiguration &cfg = config->at(0); - int ret; - - V4L2DeviceFormat format = {}; - format.fourcc = data->video_->toV4L2PixelFormat(cfg.pixelFormat); - format.size = cfg.size; - - ret = data->video_->setFormat(&format); - if (ret) - return ret; - - if (format.size != cfg.size || - format.fourcc != data->video_->toV4L2PixelFormat(cfg.pixelFormat)) - return -EINVAL; - - cfg.setStream(&data->stream_); - - return 0; -} - -int PipelineHandlerUVC::exportFrameBuffers(Camera *camera, Stream *stream, - std::vector> *buffers) -{ - UVCCameraData *data = cameraData(camera); - unsigned int count = stream->configuration().bufferCount; - - return data->video_->exportBuffers(count, buffers); -} - -int PipelineHandlerUVC::start(Camera *camera) -{ - UVCCameraData *data = cameraData(camera); - unsigned int count = data->stream_.configuration().bufferCount; - - int ret = data->video_->importBuffers(count); - if (ret < 0) - return ret; - - ret = data->video_->streamOn(); - if (ret < 0) { - data->video_->releaseBuffers(); - return ret; - } - - return 0; -} - -void PipelineHandlerUVC::stop(Camera *camera) -{ - UVCCameraData *data = cameraData(camera); - data->video_->streamOff(); - data->video_->releaseBuffers(); -} - -int PipelineHandlerUVC::processControls(UVCCameraData *data, Request *request) -{ - ControlList controls(data->video_->controls()); - - for (auto it : request->controls()) { - unsigned int id = it.first; - ControlValue &value = it.second; - - if (id == controls::Brightness) { - controls.set(V4L2_CID_BRIGHTNESS, value); - } else if (id == controls::Contrast) { - controls.set(V4L2_CID_CONTRAST, value); - } else if (id == controls::Saturation) { - controls.set(V4L2_CID_SATURATION, value); - } else if (id == controls::ManualExposure) { - controls.set(V4L2_CID_EXPOSURE_AUTO, static_cast(1)); - controls.set(V4L2_CID_EXPOSURE_ABSOLUTE, value); - } else if (id == controls::ManualGain) { - controls.set(V4L2_CID_GAIN, value); - } - } - - for (const auto &ctrl : controls) - LOG(UVC, Debug) - << "Setting control " << utils::hex(ctrl.first) - << " to " << ctrl.second.toString(); - - int ret = data->video_->setControls(&controls); - if (ret) { - LOG(UVC, Error) << "Failed to set controls: " << ret; - return ret < 0 ? ret : -EINVAL; - } - - return ret; -} - -int PipelineHandlerUVC::queueRequestDevice(Camera *camera, Request *request) -{ - UVCCameraData *data = cameraData(camera); - FrameBuffer *buffer = request->findBuffer(&data->stream_); - if (!buffer) { - LOG(UVC, Error) - << "Attempt to queue request with invalid stream"; - - return -ENOENT; - } - - int ret = processControls(data, request); - if (ret < 0) - return ret; - - ret = data->video_->queueBuffer(buffer); - if (ret < 0) - return ret; - - return 0; -} - -bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator) -{ - MediaDevice *media; - DeviceMatch dm("uvcvideo"); - - media = acquireMediaDevice(enumerator, dm); - if (!media) - return false; - - std::unique_ptr data = std::make_unique(this); - - /* Locate and initialise the camera data with the default video node. */ - const std::vector &entities = media->entities(); - auto entity = std::find_if(entities.begin(), entities.end(), - [](MediaEntity *entity) { - return entity->flags() & MEDIA_ENT_FL_DEFAULT; - }); - if (entity == entities.end()) { - LOG(UVC, Error) << "Could not find a default video device"; - return false; - } - - if (data->init(*entity)) - return false; - - dev_t devnum = makedev((*entity)->deviceMajor(), (*entity)->deviceMinor()); - - /* Create and register the camera. */ - std::set streams{ &data->stream_ }; - std::shared_ptr camera = Camera::create(this, media->model(), streams); - registerCamera(std::move(camera), std::move(data), devnum); - - /* Enable hot-unplug notifications. */ - hotplugMediaDevice(media); - - return true; -} - -int UVCCameraData::init(MediaEntity *entity) -{ - int ret; - - /* Create and open the video device. */ - video_ = new V4L2VideoDevice(entity); - ret = video_->open(); - if (ret) - return ret; - - video_->bufferReady.connect(this, &UVCCameraData::bufferReady); - - /* Initialise the supported controls. */ - const ControlInfoMap &controls = video_->controls(); - ControlInfoMap::Map ctrls; - - for (const auto &ctrl : controls) { - const ControlInfo &info = ctrl.second; - const ControlId *id; - - switch (ctrl.first->id()) { - case V4L2_CID_BRIGHTNESS: - id = &controls::Brightness; - break; - case V4L2_CID_CONTRAST: - id = &controls::Contrast; - break; - case V4L2_CID_SATURATION: - id = &controls::Saturation; - break; - case V4L2_CID_EXPOSURE_ABSOLUTE: - id = &controls::ManualExposure; - break; - case V4L2_CID_GAIN: - id = &controls::ManualGain; - break; - default: - continue; - } - - ctrls.emplace(id, info); - } - - controlInfo_ = std::move(ctrls); - - return 0; -} - -void UVCCameraData::bufferReady(FrameBuffer *buffer) -{ - Request *request = buffer->request(); - - pipe_->completeBuffer(camera_, request, buffer); - pipe_->completeRequest(camera_, request); -} - -REGISTER_PIPELINE_HANDLER(PipelineHandlerUVC); - -} /* namespace libcamera */ diff --git a/src/libcamera/pipeline/uvcvideo/meson.build b/src/libcamera/pipeline/uvcvideo/meson.build new file mode 100644 index 00000000..c19ae238 --- /dev/null +++ b/src/libcamera/pipeline/uvcvideo/meson.build @@ -0,0 +1,3 @@ +libcamera_sources += files([ + 'uvcvideo.cpp', +]) diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp new file mode 100644 index 00000000..ffbddf27 --- /dev/null +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp @@ -0,0 +1,394 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * uvcvideo.cpp - Pipeline handler for uvcvideo devices + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "device_enumerator.h" +#include "log.h" +#include "media_device.h" +#include "pipeline_handler.h" +#include "utils.h" +#include "v4l2_controls.h" +#include "v4l2_videodevice.h" + +namespace libcamera { + +LOG_DEFINE_CATEGORY(UVC) + +class UVCCameraData : public CameraData +{ +public: + UVCCameraData(PipelineHandler *pipe) + : CameraData(pipe), video_(nullptr) + { + } + + ~UVCCameraData() + { + delete video_; + } + + int init(MediaEntity *entity); + void bufferReady(FrameBuffer *buffer); + + V4L2VideoDevice *video_; + Stream stream_; +}; + +class UVCCameraConfiguration : public CameraConfiguration +{ +public: + UVCCameraConfiguration(); + + Status validate() override; +}; + +class PipelineHandlerUVC : public PipelineHandler +{ +public: + PipelineHandlerUVC(CameraManager *manager); + + CameraConfiguration *generateConfiguration(Camera *camera, + const StreamRoles &roles) override; + int configure(Camera *camera, CameraConfiguration *config) override; + + int exportFrameBuffers(Camera *camera, Stream *stream, + std::vector> *buffers) override; + + int start(Camera *camera) override; + void stop(Camera *camera) override; + + int queueRequestDevice(Camera *camera, Request *request) override; + + bool match(DeviceEnumerator *enumerator) override; + +private: + int processControls(UVCCameraData *data, Request *request); + + UVCCameraData *cameraData(const Camera *camera) + { + return static_cast( + PipelineHandler::cameraData(camera)); + } +}; + +UVCCameraConfiguration::UVCCameraConfiguration() + : CameraConfiguration() +{ +} + +CameraConfiguration::Status UVCCameraConfiguration::validate() +{ + Status status = Valid; + + if (config_.empty()) + return Invalid; + + /* Cap the number of entries to the available streams. */ + if (config_.size() > 1) { + config_.resize(1); + status = Adjusted; + } + + StreamConfiguration &cfg = config_[0]; + const StreamFormats &formats = cfg.formats(); + const PixelFormat pixelFormat = cfg.pixelFormat; + const Size size = cfg.size; + + const std::vector pixelFormats = formats.pixelformats(); + auto iter = std::find(pixelFormats.begin(), pixelFormats.end(), pixelFormat); + if (iter == pixelFormats.end()) { + cfg.pixelFormat = pixelFormats.front(); + LOG(UVC, Debug) + << "Adjusting pixel format from " + << pixelFormat.toString() << " to " + << cfg.pixelFormat.toString(); + status = Adjusted; + } + + const std::vector &formatSizes = formats.sizes(cfg.pixelFormat); + cfg.size = formatSizes.front(); + for (const Size &formatsSize : formatSizes) { + if (formatsSize > size) + break; + + cfg.size = formatsSize; + } + + if (cfg.size != size) { + LOG(UVC, Debug) + << "Adjusting size from " << size.toString() + << " to " << cfg.size.toString(); + status = Adjusted; + } + + cfg.bufferCount = 4; + + return status; +} + +PipelineHandlerUVC::PipelineHandlerUVC(CameraManager *manager) + : PipelineHandler(manager) +{ +} + +CameraConfiguration *PipelineHandlerUVC::generateConfiguration(Camera *camera, + const StreamRoles &roles) +{ + UVCCameraData *data = cameraData(camera); + CameraConfiguration *config = new UVCCameraConfiguration(); + + if (roles.empty()) + return config; + + std::map> v4l2Formats = + data->video_->formats(); + std::map> deviceFormats; + std::transform(v4l2Formats.begin(), v4l2Formats.end(), + std::inserter(deviceFormats, deviceFormats.begin()), + [&](const decltype(v4l2Formats)::value_type &format) { + return decltype(deviceFormats)::value_type{ + data->video_->toPixelFormat(format.first), + format.second + }; + }); + + StreamFormats formats(deviceFormats); + StreamConfiguration cfg(formats); + + cfg.pixelFormat = formats.pixelformats().front(); + cfg.size = formats.sizes(cfg.pixelFormat).back(); + cfg.bufferCount = 4; + + config->addConfiguration(cfg); + + config->validate(); + + return config; +} + +int PipelineHandlerUVC::configure(Camera *camera, CameraConfiguration *config) +{ + UVCCameraData *data = cameraData(camera); + StreamConfiguration &cfg = config->at(0); + int ret; + + V4L2DeviceFormat format = {}; + format.fourcc = data->video_->toV4L2PixelFormat(cfg.pixelFormat); + format.size = cfg.size; + + ret = data->video_->setFormat(&format); + if (ret) + return ret; + + if (format.size != cfg.size || + format.fourcc != data->video_->toV4L2PixelFormat(cfg.pixelFormat)) + return -EINVAL; + + cfg.setStream(&data->stream_); + + return 0; +} + +int PipelineHandlerUVC::exportFrameBuffers(Camera *camera, Stream *stream, + std::vector> *buffers) +{ + UVCCameraData *data = cameraData(camera); + unsigned int count = stream->configuration().bufferCount; + + return data->video_->exportBuffers(count, buffers); +} + +int PipelineHandlerUVC::start(Camera *camera) +{ + UVCCameraData *data = cameraData(camera); + unsigned int count = data->stream_.configuration().bufferCount; + + int ret = data->video_->importBuffers(count); + if (ret < 0) + return ret; + + ret = data->video_->streamOn(); + if (ret < 0) { + data->video_->releaseBuffers(); + return ret; + } + + return 0; +} + +void PipelineHandlerUVC::stop(Camera *camera) +{ + UVCCameraData *data = cameraData(camera); + data->video_->streamOff(); + data->video_->releaseBuffers(); +} + +int PipelineHandlerUVC::processControls(UVCCameraData *data, Request *request) +{ + ControlList controls(data->video_->controls()); + + for (auto it : request->controls()) { + unsigned int id = it.first; + ControlValue &value = it.second; + + if (id == controls::Brightness) { + controls.set(V4L2_CID_BRIGHTNESS, value); + } else if (id == controls::Contrast) { + controls.set(V4L2_CID_CONTRAST, value); + } else if (id == controls::Saturation) { + controls.set(V4L2_CID_SATURATION, value); + } else if (id == controls::ManualExposure) { + controls.set(V4L2_CID_EXPOSURE_AUTO, static_cast(1)); + controls.set(V4L2_CID_EXPOSURE_ABSOLUTE, value); + } else if (id == controls::ManualGain) { + controls.set(V4L2_CID_GAIN, value); + } + } + + for (const auto &ctrl : controls) + LOG(UVC, Debug) + << "Setting control " << utils::hex(ctrl.first) + << " to " << ctrl.second.toString(); + + int ret = data->video_->setControls(&controls); + if (ret) { + LOG(UVC, Error) << "Failed to set controls: " << ret; + return ret < 0 ? ret : -EINVAL; + } + + return ret; +} + +int PipelineHandlerUVC::queueRequestDevice(Camera *camera, Request *request) +{ + UVCCameraData *data = cameraData(camera); + FrameBuffer *buffer = request->findBuffer(&data->stream_); + if (!buffer) { + LOG(UVC, Error) + << "Attempt to queue request with invalid stream"; + + return -ENOENT; + } + + int ret = processControls(data, request); + if (ret < 0) + return ret; + + ret = data->video_->queueBuffer(buffer); + if (ret < 0) + return ret; + + return 0; +} + +bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator) +{ + MediaDevice *media; + DeviceMatch dm("uvcvideo"); + + media = acquireMediaDevice(enumerator, dm); + if (!media) + return false; + + std::unique_ptr data = std::make_unique(this); + + /* Locate and initialise the camera data with the default video node. */ + const std::vector &entities = media->entities(); + auto entity = std::find_if(entities.begin(), entities.end(), + [](MediaEntity *entity) { + return entity->flags() & MEDIA_ENT_FL_DEFAULT; + }); + if (entity == entities.end()) { + LOG(UVC, Error) << "Could not find a default video device"; + return false; + } + + if (data->init(*entity)) + return false; + + dev_t devnum = makedev((*entity)->deviceMajor(), (*entity)->deviceMinor()); + + /* Create and register the camera. */ + std::set streams{ &data->stream_ }; + std::shared_ptr camera = Camera::create(this, media->model(), streams); + registerCamera(std::move(camera), std::move(data), devnum); + + /* Enable hot-unplug notifications. */ + hotplugMediaDevice(media); + + return true; +} + +int UVCCameraData::init(MediaEntity *entity) +{ + int ret; + + /* Create and open the video device. */ + video_ = new V4L2VideoDevice(entity); + ret = video_->open(); + if (ret) + return ret; + + video_->bufferReady.connect(this, &UVCCameraData::bufferReady); + + /* Initialise the supported controls. */ + const ControlInfoMap &controls = video_->controls(); + ControlInfoMap::Map ctrls; + + for (const auto &ctrl : controls) { + const ControlInfo &info = ctrl.second; + const ControlId *id; + + switch (ctrl.first->id()) { + case V4L2_CID_BRIGHTNESS: + id = &controls::Brightness; + break; + case V4L2_CID_CONTRAST: + id = &controls::Contrast; + break; + case V4L2_CID_SATURATION: + id = &controls::Saturation; + break; + case V4L2_CID_EXPOSURE_ABSOLUTE: + id = &controls::ManualExposure; + break; + case V4L2_CID_GAIN: + id = &controls::ManualGain; + break; + default: + continue; + } + + ctrls.emplace(id, info); + } + + controlInfo_ = std::move(ctrls); + + return 0; +} + +void UVCCameraData::bufferReady(FrameBuffer *buffer) +{ + Request *request = buffer->request(); + + pipe_->completeBuffer(camera_, request, buffer); + pipe_->completeRequest(camera_, request); +} + +REGISTER_PIPELINE_HANDLER(PipelineHandlerUVC); + +} /* namespace libcamera */ diff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp deleted file mode 100644 index b04a9726..00000000 --- a/src/libcamera/pipeline/vimc.cpp +++ /dev/null @@ -1,467 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2018, Google Inc. - * - * vimc.cpp - Pipeline handler for the vimc device - */ - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "camera_sensor.h" -#include "device_enumerator.h" -#include "ipa_manager.h" -#include "log.h" -#include "media_device.h" -#include "pipeline_handler.h" -#include "utils.h" -#include "v4l2_controls.h" -#include "v4l2_subdevice.h" -#include "v4l2_videodevice.h" - -namespace libcamera { - -LOG_DEFINE_CATEGORY(VIMC) - -class VimcCameraData : public CameraData -{ -public: - VimcCameraData(PipelineHandler *pipe) - : CameraData(pipe), sensor_(nullptr), debayer_(nullptr), - scaler_(nullptr), video_(nullptr), raw_(nullptr) - { - } - - ~VimcCameraData() - { - delete sensor_; - delete debayer_; - delete scaler_; - delete video_; - delete raw_; - } - - int init(MediaDevice *media); - void bufferReady(FrameBuffer *buffer); - - CameraSensor *sensor_; - V4L2Subdevice *debayer_; - V4L2Subdevice *scaler_; - V4L2VideoDevice *video_; - V4L2VideoDevice *raw_; - Stream stream_; -}; - -class VimcCameraConfiguration : public CameraConfiguration -{ -public: - VimcCameraConfiguration(); - - Status validate() override; -}; - -class PipelineHandlerVimc : public PipelineHandler -{ -public: - PipelineHandlerVimc(CameraManager *manager); - - CameraConfiguration *generateConfiguration(Camera *camera, - const StreamRoles &roles) override; - int configure(Camera *camera, CameraConfiguration *config) override; - - int exportFrameBuffers(Camera *camera, Stream *stream, - std::vector> *buffers) override; - - int start(Camera *camera) override; - void stop(Camera *camera) override; - - int queueRequestDevice(Camera *camera, Request *request) override; - - bool match(DeviceEnumerator *enumerator) override; - -private: - int processControls(VimcCameraData *data, Request *request); - - VimcCameraData *cameraData(const Camera *camera) - { - return static_cast( - PipelineHandler::cameraData(camera)); - } -}; - -namespace { - -static const std::array pixelformats{ - PixelFormat(DRM_FORMAT_RGB888), - PixelFormat(DRM_FORMAT_BGR888), - PixelFormat(DRM_FORMAT_BGRA8888), -}; - -} /* namespace */ - -VimcCameraConfiguration::VimcCameraConfiguration() - : CameraConfiguration() -{ -} - -CameraConfiguration::Status VimcCameraConfiguration::validate() -{ - Status status = Valid; - - if (config_.empty()) - return Invalid; - - /* Cap the number of entries to the available streams. */ - if (config_.size() > 1) { - config_.resize(1); - status = Adjusted; - } - - StreamConfiguration &cfg = config_[0]; - - /* Adjust the pixel format. */ - if (std::find(pixelformats.begin(), pixelformats.end(), cfg.pixelFormat) == - pixelformats.end()) { - LOG(VIMC, Debug) << "Adjusting format to RGB24"; - cfg.pixelFormat = PixelFormat(DRM_FORMAT_BGR888); - status = Adjusted; - } - - /* Clamp the size based on the device limits. */ - const Size size = cfg.size; - - /* The scaler hardcodes a x3 scale-up ratio. */ - cfg.size.width = std::max(48U, std::min(4096U, cfg.size.width)); - cfg.size.height = std::max(48U, std::min(2160U, cfg.size.height)); - cfg.size.width -= cfg.size.width % 3; - cfg.size.height -= cfg.size.height % 3; - - if (cfg.size != size) { - LOG(VIMC, Debug) - << "Adjusting size to " << cfg.size.toString(); - status = Adjusted; - } - - cfg.bufferCount = 4; - - return status; -} - -PipelineHandlerVimc::PipelineHandlerVimc(CameraManager *manager) - : PipelineHandler(manager) -{ -} - -CameraConfiguration *PipelineHandlerVimc::generateConfiguration(Camera *camera, - const StreamRoles &roles) -{ - CameraConfiguration *config = new VimcCameraConfiguration(); - - if (roles.empty()) - return config; - - std::map> formats; - - for (PixelFormat pixelformat : pixelformats) { - /* The scaler hardcodes a x3 scale-up ratio. */ - std::vector sizes{ - SizeRange{ { 48, 48 }, { 4096, 2160 } } - }; - formats[pixelformat] = sizes; - } - - StreamConfiguration cfg(formats); - - cfg.pixelFormat = PixelFormat(DRM_FORMAT_BGR888); - cfg.size = { 1920, 1080 }; - cfg.bufferCount = 4; - - config->addConfiguration(cfg); - - config->validate(); - - return config; -} - -int PipelineHandlerVimc::configure(Camera *camera, CameraConfiguration *config) -{ - VimcCameraData *data = cameraData(camera); - StreamConfiguration &cfg = config->at(0); - int ret; - - /* The scaler hardcodes a x3 scale-up ratio. */ - V4L2SubdeviceFormat subformat = {}; - subformat.mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8; - subformat.size = { cfg.size.width / 3, cfg.size.height / 3 }; - - ret = data->sensor_->setFormat(&subformat); - if (ret) - return ret; - - ret = data->debayer_->setFormat(0, &subformat); - if (ret) - return ret; - - subformat.mbus_code = MEDIA_BUS_FMT_RGB888_1X24; - ret = data->debayer_->setFormat(1, &subformat); - if (ret) - return ret; - - ret = data->scaler_->setFormat(0, &subformat); - if (ret) - return ret; - - subformat.size = cfg.size; - ret = data->scaler_->setFormat(1, &subformat); - if (ret) - return ret; - - V4L2DeviceFormat format = {}; - format.fourcc = data->video_->toV4L2PixelFormat(cfg.pixelFormat); - format.size = cfg.size; - - ret = data->video_->setFormat(&format); - if (ret) - return ret; - - if (format.size != cfg.size || - format.fourcc != data->video_->toV4L2PixelFormat(cfg.pixelFormat)) - return -EINVAL; - - /* - * Format has to be set on the raw capture video node, otherwise the - * vimc driver will fail pipeline validation. - */ - format.fourcc = V4L2PixelFormat(V4L2_PIX_FMT_SGRBG8); - format.size = { cfg.size.width / 3, cfg.size.height / 3 }; - - ret = data->raw_->setFormat(&format); - if (ret) - return ret; - - cfg.setStream(&data->stream_); - - return 0; -} - -int PipelineHandlerVimc::exportFrameBuffers(Camera *camera, Stream *stream, - std::vector> *buffers) -{ - VimcCameraData *data = cameraData(camera); - unsigned int count = stream->configuration().bufferCount; - - return data->video_->exportBuffers(count, buffers); -} - -int PipelineHandlerVimc::start(Camera *camera) -{ - VimcCameraData *data = cameraData(camera); - unsigned int count = data->stream_.configuration().bufferCount; - - int ret = data->video_->importBuffers(count); - if (ret < 0) - return ret; - - ret = data->video_->streamOn(); - if (ret < 0) { - data->video_->releaseBuffers(); - return ret; - } - - return 0; -} - -void PipelineHandlerVimc::stop(Camera *camera) -{ - VimcCameraData *data = cameraData(camera); - data->video_->streamOff(); - data->video_->releaseBuffers(); -} - -int PipelineHandlerVimc::processControls(VimcCameraData *data, Request *request) -{ - ControlList controls(data->sensor_->controls()); - - for (auto it : request->controls()) { - unsigned int id = it.first; - ControlValue &value = it.second; - - if (id == controls::Brightness) - controls.set(V4L2_CID_BRIGHTNESS, value); - else if (id == controls::Contrast) - controls.set(V4L2_CID_CONTRAST, value); - else if (id == controls::Saturation) - controls.set(V4L2_CID_SATURATION, value); - } - - for (const auto &ctrl : controls) - LOG(VIMC, Debug) - << "Setting control " << utils::hex(ctrl.first) - << " to " << ctrl.second.toString(); - - int ret = data->sensor_->setControls(&controls); - if (ret) { - LOG(VIMC, Error) << "Failed to set controls: " << ret; - return ret < 0 ? ret : -EINVAL; - } - - return ret; -} - -int PipelineHandlerVimc::queueRequestDevice(Camera *camera, Request *request) -{ - VimcCameraData *data = cameraData(camera); - FrameBuffer *buffer = request->findBuffer(&data->stream_); - if (!buffer) { - LOG(VIMC, Error) - << "Attempt to queue request with invalid stream"; - - return -ENOENT; - } - - int ret = processControls(data, request); - if (ret < 0) - return ret; - - ret = data->video_->queueBuffer(buffer); - if (ret < 0) - return ret; - - return 0; -} - -bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator) -{ - DeviceMatch dm("vimc"); - - dm.add("Raw Capture 0"); - dm.add("Raw Capture 1"); - dm.add("RGB/YUV Capture"); - dm.add("Sensor A"); - dm.add("Sensor B"); - dm.add("Debayer A"); - dm.add("Debayer B"); - dm.add("RGB/YUV Input"); - dm.add("Scaler"); - - MediaDevice *media = acquireMediaDevice(enumerator, dm); - if (!media) - return false; - - std::unique_ptr data = std::make_unique(this); - - data->ipa_ = IPAManager::instance()->createIPA(this, 0, 0); - if (data->ipa_ == nullptr) - LOG(VIMC, Warning) << "no matching IPA found"; - else - data->ipa_->init(); - - /* Locate and open the capture video node. */ - if (data->init(media)) - return false; - - /* Create and register the camera. */ - std::set streams{ &data->stream_ }; - std::shared_ptr camera = Camera::create(this, "VIMC Sensor B", - streams); - registerCamera(std::move(camera), std::move(data)); - - return true; -} - -int VimcCameraData::init(MediaDevice *media) -{ - int ret; - - ret = media->disableLinks(); - if (ret < 0) - return ret; - - MediaLink *link = media->link("Debayer B", 1, "Scaler", 0); - if (!link) - return -ENODEV; - - ret = link->setEnabled(true); - if (ret < 0) - return ret; - - /* Create and open the camera sensor, debayer, scaler and video device. */ - sensor_ = new CameraSensor(media->getEntityByName("Sensor B")); - ret = sensor_->init(); - if (ret) - return ret; - - debayer_ = new V4L2Subdevice(media->getEntityByName("Debayer B")); - if (debayer_->open()) - return -ENODEV; - - scaler_ = new V4L2Subdevice(media->getEntityByName("Scaler")); - if (scaler_->open()) - return -ENODEV; - - video_ = new V4L2VideoDevice(media->getEntityByName("RGB/YUV Capture")); - if (video_->open()) - return -ENODEV; - - video_->bufferReady.connect(this, &VimcCameraData::bufferReady); - - raw_ = new V4L2VideoDevice(media->getEntityByName("Raw Capture 1")); - if (raw_->open()) - return -ENODEV; - - /* Initialise the supported controls. */ - const ControlInfoMap &controls = sensor_->controls(); - ControlInfoMap::Map ctrls; - - for (const auto &ctrl : controls) { - const ControlInfo &info = ctrl.second; - const ControlId *id; - - switch (ctrl.first->id()) { - case V4L2_CID_BRIGHTNESS: - id = &controls::Brightness; - break; - case V4L2_CID_CONTRAST: - id = &controls::Contrast; - break; - case V4L2_CID_SATURATION: - id = &controls::Saturation; - break; - default: - continue; - } - - ctrls.emplace(id, info); - } - - controlInfo_ = std::move(ctrls); - - /* Initialize the camera properties. */ - properties_ = sensor_->properties(); - - return 0; -} - -void VimcCameraData::bufferReady(FrameBuffer *buffer) -{ - Request *request = buffer->request(); - - pipe_->completeBuffer(camera_, request, buffer); - pipe_->completeRequest(camera_, request); -} - -REGISTER_PIPELINE_HANDLER(PipelineHandlerVimc); - -} /* namespace libcamera */ diff --git a/src/libcamera/pipeline/vimc/meson.build b/src/libcamera/pipeline/vimc/meson.build new file mode 100644 index 00000000..615ecd20 --- /dev/null +++ b/src/libcamera/pipeline/vimc/meson.build @@ -0,0 +1,3 @@ +libcamera_sources += files([ + 'vimc.cpp', +]) diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp new file mode 100644 index 00000000..b04a9726 --- /dev/null +++ b/src/libcamera/pipeline/vimc/vimc.cpp @@ -0,0 +1,467 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2018, Google Inc. + * + * vimc.cpp - Pipeline handler for the vimc device + */ + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "camera_sensor.h" +#include "device_enumerator.h" +#include "ipa_manager.h" +#include "log.h" +#include "media_device.h" +#include "pipeline_handler.h" +#include "utils.h" +#include "v4l2_controls.h" +#include "v4l2_subdevice.h" +#include "v4l2_videodevice.h" + +namespace libcamera { + +LOG_DEFINE_CATEGORY(VIMC) + +class VimcCameraData : public CameraData +{ +public: + VimcCameraData(PipelineHandler *pipe) + : CameraData(pipe), sensor_(nullptr), debayer_(nullptr), + scaler_(nullptr), video_(nullptr), raw_(nullptr) + { + } + + ~VimcCameraData() + { + delete sensor_; + delete debayer_; + delete scaler_; + delete video_; + delete raw_; + } + + int init(MediaDevice *media); + void bufferReady(FrameBuffer *buffer); + + CameraSensor *sensor_; + V4L2Subdevice *debayer_; + V4L2Subdevice *scaler_; + V4L2VideoDevice *video_; + V4L2VideoDevice *raw_; + Stream stream_; +}; + +class VimcCameraConfiguration : public CameraConfiguration +{ +public: + VimcCameraConfiguration(); + + Status validate() override; +}; + +class PipelineHandlerVimc : public PipelineHandler +{ +public: + PipelineHandlerVimc(CameraManager *manager); + + CameraConfiguration *generateConfiguration(Camera *camera, + const StreamRoles &roles) override; + int configure(Camera *camera, CameraConfiguration *config) override; + + int exportFrameBuffers(Camera *camera, Stream *stream, + std::vector> *buffers) override; + + int start(Camera *camera) override; + void stop(Camera *camera) override; + + int queueRequestDevice(Camera *camera, Request *request) override; + + bool match(DeviceEnumerator *enumerator) override; + +private: + int processControls(VimcCameraData *data, Request *request); + + VimcCameraData *cameraData(const Camera *camera) + { + return static_cast( + PipelineHandler::cameraData(camera)); + } +}; + +namespace { + +static const std::array pixelformats{ + PixelFormat(DRM_FORMAT_RGB888), + PixelFormat(DRM_FORMAT_BGR888), + PixelFormat(DRM_FORMAT_BGRA8888), +}; + +} /* namespace */ + +VimcCameraConfiguration::VimcCameraConfiguration() + : CameraConfiguration() +{ +} + +CameraConfiguration::Status VimcCameraConfiguration::validate() +{ + Status status = Valid; + + if (config_.empty()) + return Invalid; + + /* Cap the number of entries to the available streams. */ + if (config_.size() > 1) { + config_.resize(1); + status = Adjusted; + } + + StreamConfiguration &cfg = config_[0]; + + /* Adjust the pixel format. */ + if (std::find(pixelformats.begin(), pixelformats.end(), cfg.pixelFormat) == + pixelformats.end()) { + LOG(VIMC, Debug) << "Adjusting format to RGB24"; + cfg.pixelFormat = PixelFormat(DRM_FORMAT_BGR888); + status = Adjusted; + } + + /* Clamp the size based on the device limits. */ + const Size size = cfg.size; + + /* The scaler hardcodes a x3 scale-up ratio. */ + cfg.size.width = std::max(48U, std::min(4096U, cfg.size.width)); + cfg.size.height = std::max(48U, std::min(2160U, cfg.size.height)); + cfg.size.width -= cfg.size.width % 3; + cfg.size.height -= cfg.size.height % 3; + + if (cfg.size != size) { + LOG(VIMC, Debug) + << "Adjusting size to " << cfg.size.toString(); + status = Adjusted; + } + + cfg.bufferCount = 4; + + return status; +} + +PipelineHandlerVimc::PipelineHandlerVimc(CameraManager *manager) + : PipelineHandler(manager) +{ +} + +CameraConfiguration *PipelineHandlerVimc::generateConfiguration(Camera *camera, + const StreamRoles &roles) +{ + CameraConfiguration *config = new VimcCameraConfiguration(); + + if (roles.empty()) + return config; + + std::map> formats; + + for (PixelFormat pixelformat : pixelformats) { + /* The scaler hardcodes a x3 scale-up ratio. */ + std::vector sizes{ + SizeRange{ { 48, 48 }, { 4096, 2160 } } + }; + formats[pixelformat] = sizes; + } + + StreamConfiguration cfg(formats); + + cfg.pixelFormat = PixelFormat(DRM_FORMAT_BGR888); + cfg.size = { 1920, 1080 }; + cfg.bufferCount = 4; + + config->addConfiguration(cfg); + + config->validate(); + + return config; +} + +int PipelineHandlerVimc::configure(Camera *camera, CameraConfiguration *config) +{ + VimcCameraData *data = cameraData(camera); + StreamConfiguration &cfg = config->at(0); + int ret; + + /* The scaler hardcodes a x3 scale-up ratio. */ + V4L2SubdeviceFormat subformat = {}; + subformat.mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8; + subformat.size = { cfg.size.width / 3, cfg.size.height / 3 }; + + ret = data->sensor_->setFormat(&subformat); + if (ret) + return ret; + + ret = data->debayer_->setFormat(0, &subformat); + if (ret) + return ret; + + subformat.mbus_code = MEDIA_BUS_FMT_RGB888_1X24; + ret = data->debayer_->setFormat(1, &subformat); + if (ret) + return ret; + + ret = data->scaler_->setFormat(0, &subformat); + if (ret) + return ret; + + subformat.size = cfg.size; + ret = data->scaler_->setFormat(1, &subformat); + if (ret) + return ret; + + V4L2DeviceFormat format = {}; + format.fourcc = data->video_->toV4L2PixelFormat(cfg.pixelFormat); + format.size = cfg.size; + + ret = data->video_->setFormat(&format); + if (ret) + return ret; + + if (format.size != cfg.size || + format.fourcc != data->video_->toV4L2PixelFormat(cfg.pixelFormat)) + return -EINVAL; + + /* + * Format has to be set on the raw capture video node, otherwise the + * vimc driver will fail pipeline validation. + */ + format.fourcc = V4L2PixelFormat(V4L2_PIX_FMT_SGRBG8); + format.size = { cfg.size.width / 3, cfg.size.height / 3 }; + + ret = data->raw_->setFormat(&format); + if (ret) + return ret; + + cfg.setStream(&data->stream_); + + return 0; +} + +int PipelineHandlerVimc::exportFrameBuffers(Camera *camera, Stream *stream, + std::vector> *buffers) +{ + VimcCameraData *data = cameraData(camera); + unsigned int count = stream->configuration().bufferCount; + + return data->video_->exportBuffers(count, buffers); +} + +int PipelineHandlerVimc::start(Camera *camera) +{ + VimcCameraData *data = cameraData(camera); + unsigned int count = data->stream_.configuration().bufferCount; + + int ret = data->video_->importBuffers(count); + if (ret < 0) + return ret; + + ret = data->video_->streamOn(); + if (ret < 0) { + data->video_->releaseBuffers(); + return ret; + } + + return 0; +} + +void PipelineHandlerVimc::stop(Camera *camera) +{ + VimcCameraData *data = cameraData(camera); + data->video_->streamOff(); + data->video_->releaseBuffers(); +} + +int PipelineHandlerVimc::processControls(VimcCameraData *data, Request *request) +{ + ControlList controls(data->sensor_->controls()); + + for (auto it : request->controls()) { + unsigned int id = it.first; + ControlValue &value = it.second; + + if (id == controls::Brightness) + controls.set(V4L2_CID_BRIGHTNESS, value); + else if (id == controls::Contrast) + controls.set(V4L2_CID_CONTRAST, value); + else if (id == controls::Saturation) + controls.set(V4L2_CID_SATURATION, value); + } + + for (const auto &ctrl : controls) + LOG(VIMC, Debug) + << "Setting control " << utils::hex(ctrl.first) + << " to " << ctrl.second.toString(); + + int ret = data->sensor_->setControls(&controls); + if (ret) { + LOG(VIMC, Error) << "Failed to set controls: " << ret; + return ret < 0 ? ret : -EINVAL; + } + + return ret; +} + +int PipelineHandlerVimc::queueRequestDevice(Camera *camera, Request *request) +{ + VimcCameraData *data = cameraData(camera); + FrameBuffer *buffer = request->findBuffer(&data->stream_); + if (!buffer) { + LOG(VIMC, Error) + << "Attempt to queue request with invalid stream"; + + return -ENOENT; + } + + int ret = processControls(data, request); + if (ret < 0) + return ret; + + ret = data->video_->queueBuffer(buffer); + if (ret < 0) + return ret; + + return 0; +} + +bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator) +{ + DeviceMatch dm("vimc"); + + dm.add("Raw Capture 0"); + dm.add("Raw Capture 1"); + dm.add("RGB/YUV Capture"); + dm.add("Sensor A"); + dm.add("Sensor B"); + dm.add("Debayer A"); + dm.add("Debayer B"); + dm.add("RGB/YUV Input"); + dm.add("Scaler"); + + MediaDevice *media = acquireMediaDevice(enumerator, dm); + if (!media) + return false; + + std::unique_ptr data = std::make_unique(this); + + data->ipa_ = IPAManager::instance()->createIPA(this, 0, 0); + if (data->ipa_ == nullptr) + LOG(VIMC, Warning) << "no matching IPA found"; + else + data->ipa_->init(); + + /* Locate and open the capture video node. */ + if (data->init(media)) + return false; + + /* Create and register the camera. */ + std::set streams{ &data->stream_ }; + std::shared_ptr camera = Camera::create(this, "VIMC Sensor B", + streams); + registerCamera(std::move(camera), std::move(data)); + + return true; +} + +int VimcCameraData::init(MediaDevice *media) +{ + int ret; + + ret = media->disableLinks(); + if (ret < 0) + return ret; + + MediaLink *link = media->link("Debayer B", 1, "Scaler", 0); + if (!link) + return -ENODEV; + + ret = link->setEnabled(true); + if (ret < 0) + return ret; + + /* Create and open the camera sensor, debayer, scaler and video device. */ + sensor_ = new CameraSensor(media->getEntityByName("Sensor B")); + ret = sensor_->init(); + if (ret) + return ret; + + debayer_ = new V4L2Subdevice(media->getEntityByName("Debayer B")); + if (debayer_->open()) + return -ENODEV; + + scaler_ = new V4L2Subdevice(media->getEntityByName("Scaler")); + if (scaler_->open()) + return -ENODEV; + + video_ = new V4L2VideoDevice(media->getEntityByName("RGB/YUV Capture")); + if (video_->open()) + return -ENODEV; + + video_->bufferReady.connect(this, &VimcCameraData::bufferReady); + + raw_ = new V4L2VideoDevice(media->getEntityByName("Raw Capture 1")); + if (raw_->open()) + return -ENODEV; + + /* Initialise the supported controls. */ + const ControlInfoMap &controls = sensor_->controls(); + ControlInfoMap::Map ctrls; + + for (const auto &ctrl : controls) { + const ControlInfo &info = ctrl.second; + const ControlId *id; + + switch (ctrl.first->id()) { + case V4L2_CID_BRIGHTNESS: + id = &controls::Brightness; + break; + case V4L2_CID_CONTRAST: + id = &controls::Contrast; + break; + case V4L2_CID_SATURATION: + id = &controls::Saturation; + break; + default: + continue; + } + + ctrls.emplace(id, info); + } + + controlInfo_ = std::move(ctrls); + + /* Initialize the camera properties. */ + properties_ = sensor_->properties(); + + return 0; +} + +void VimcCameraData::bufferReady(FrameBuffer *buffer) +{ + Request *request = buffer->request(); + + pipe_->completeBuffer(camera_, request, buffer); + pipe_->completeRequest(camera_, request); +} + +REGISTER_PIPELINE_HANDLER(PipelineHandlerVimc); + +} /* namespace libcamera */ -- cgit v1.2.1