diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2020-05-12 00:58:34 +0300 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2020-05-16 03:38:11 +0300 |
commit | 93e72b695e477ac1efc22a0bdddb177199cf2fb9 (patch) | |
tree | 7ba4b9fe0d5442ad7ca4e25aee1bc17b830a98ed /include | |
parent | 79c5df21ddde12f98eacf2ece8e3091e4f845d38 (diff) |
libcamera: Move internal headers to include/libcamera/internal/
The libcamera internal headers are located in src/libcamera/include/.
The directory is added to the compiler headers search path with a meson
include_directories() directive, and internal headers are included with
(e.g. for the internal semaphore.h header)
#include "semaphore.h"
All was well, until libcxx decided to implement the C++20
synchronization library. The __threading_support header gained a
#include <semaphore.h>
to include the pthread's semaphore support. As include_directories()
adds src/libcamera/include/ to the compiler search path with -I, the
internal semaphore.h is included instead of the pthread version.
Needless to say, the compiler isn't happy.
Three options have been considered to fix this issue:
- Use -iquote instead of -I. The -iquote option instructs gcc to only
consider the header search path for headers included with the ""
version. Meson unfortunately doesn't support this option.
- Rename the internal semaphore.h header. This was deemed to be the
beginning of a long whack-a-mole game, where namespace clashes with
system libraries would appear over time (possibly dependent on
particular system configurations) and would need to be constantly
fixed.
- Move the internal headers to another directory to create a unique
namespace through path components. This causes lots of churn in all
the existing source files through the all project.
The first option would be best, but isn't available to us due to missing
support in meson. Even if -iquote support was added, we would need to
fix the problem before a new version of meson containing the required
support would be released.
The third option is thus the only practical solution available. Bite the
bullet, and do it, moving headers to include/libcamera/internal/.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Jacopo Mondi <jacopo@jmondi.org>
Diffstat (limited to 'include')
33 files changed, 2432 insertions, 0 deletions
diff --git a/include/libcamera/internal/byte_stream_buffer.h b/include/libcamera/internal/byte_stream_buffer.h new file mode 100644 index 00000000..b3aaa8b9 --- /dev/null +++ b/include/libcamera/internal/byte_stream_buffer.h @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * byte_stream_buffer.h - Byte stream buffer + */ +#ifndef __LIBCAMERA_BYTE_STREAM_BUFFER_H__ +#define __LIBCAMERA_BYTE_STREAM_BUFFER_H__ + +#include <stddef.h> +#include <stdint.h> +#include <type_traits> + +#include <libcamera/span.h> + +namespace libcamera { + +class ByteStreamBuffer +{ +public: + ByteStreamBuffer(const uint8_t *base, size_t size); + ByteStreamBuffer(uint8_t *base, size_t size); + ByteStreamBuffer(ByteStreamBuffer &&other); + ByteStreamBuffer &operator=(ByteStreamBuffer &&other); + + const uint8_t *base() const { return base_; } + uint32_t offset() const { return (write_ ? write_ : read_) - base_; } + size_t size() const { return size_; } + bool overflow() const { return overflow_; } + + ByteStreamBuffer carveOut(size_t size); + int skip(size_t size); + + template<typename T> + int read(T *t) + { + return read(reinterpret_cast<uint8_t *>(t), sizeof(*t)); + } + + template<typename T> + int read(const Span<T> &data) + { + return read(reinterpret_cast<uint8_t *>(data.data()), + data.size_bytes()); + } + + template<typename T> + const std::remove_reference_t<T> *read(size_t count = 1) + { + using return_type = const std::remove_reference_t<T> *; + return reinterpret_cast<return_type>(read(sizeof(T), count)); + } + + template<typename T> + int write(const T *t) + { + return write(reinterpret_cast<const uint8_t *>(t), sizeof(*t)); + } + + template<typename T> + int write(const Span<T> &data) + { + return write(reinterpret_cast<const uint8_t *>(data.data()), + data.size_bytes()); + } + +private: + ByteStreamBuffer(const ByteStreamBuffer &other) = delete; + ByteStreamBuffer &operator=(const ByteStreamBuffer &other) = delete; + + void setOverflow(); + + int read(uint8_t *data, size_t size); + const uint8_t *read(size_t size, size_t count); + int write(const uint8_t *data, size_t size); + + ByteStreamBuffer *parent_; + + const uint8_t *base_; + size_t size_; + bool overflow_; + + const uint8_t *read_; + uint8_t *write_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_BYTE_STREAM_BUFFER_H__ */ diff --git a/include/libcamera/internal/camera_controls.h b/include/libcamera/internal/camera_controls.h new file mode 100644 index 00000000..dc8b3ba8 --- /dev/null +++ b/include/libcamera/internal/camera_controls.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * camera_controls.h - Camera controls + */ +#ifndef __LIBCAMERA_CAMERA_CONTROLS_H__ +#define __LIBCAMERA_CAMERA_CONTROLS_H__ + +#include "libcamera/internal/control_validator.h" + +namespace libcamera { + +class Camera; + +class CameraControlValidator final : public ControlValidator +{ +public: + CameraControlValidator(Camera *camera); + + const std::string &name() const override; + bool validate(unsigned int id) const override; + +private: + Camera *camera_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_CAMERA_CONTROLS_H__ */ diff --git a/include/libcamera/internal/camera_sensor.h b/include/libcamera/internal/camera_sensor.h new file mode 100644 index 00000000..d79bd9ce --- /dev/null +++ b/include/libcamera/internal/camera_sensor.h @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * camera_sensor.h - A camera sensor + */ +#ifndef __LIBCAMERA_CAMERA_SENSOR_H__ +#define __LIBCAMERA_CAMERA_SENSOR_H__ + +#include <memory> +#include <string> +#include <vector> + +#include <libcamera/controls.h> +#include <libcamera/geometry.h> + +#include "libcamera/internal/formats.h" +#include "libcamera/internal/log.h" + +namespace libcamera { + +class MediaEntity; +class V4L2Subdevice; + +struct V4L2SubdeviceFormat; + +struct CameraSensorInfo { + std::string model; + + uint32_t bitsPerPixel; + + Size activeAreaSize; + Rectangle analogCrop; + Size outputSize; + + uint64_t pixelRate; + uint32_t lineLength; +}; + +class CameraSensor : protected Loggable +{ +public: + explicit CameraSensor(const MediaEntity *entity); + ~CameraSensor(); + + CameraSensor(const CameraSensor &) = delete; + CameraSensor &operator=(const CameraSensor &) = delete; + + int init(); + + const std::string &model() const { return model_; } + const MediaEntity *entity() const { return entity_; } + const std::vector<unsigned int> &mbusCodes() const { return mbusCodes_; } + const std::vector<Size> &sizes() const { return sizes_; } + const Size &resolution() const { return resolution_; } + + V4L2SubdeviceFormat getFormat(const std::vector<unsigned int> &mbusCodes, + const Size &size) const; + int setFormat(V4L2SubdeviceFormat *format); + + const ControlInfoMap &controls() const; + ControlList getControls(const std::vector<uint32_t> &ids); + int setControls(ControlList *ctrls); + + const ControlList &properties() const { return properties_; } + int sensorInfo(CameraSensorInfo *info) const; + +protected: + std::string logPrefix() const; + +private: + const MediaEntity *entity_; + std::unique_ptr<V4L2Subdevice> subdev_; + unsigned int pad_; + + std::string model_; + + ImageFormats formats_; + Size resolution_; + std::vector<unsigned int> mbusCodes_; + std::vector<Size> sizes_; + + ControlList properties_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_CAMERA_SENSOR_H__ */ diff --git a/include/libcamera/internal/control_serializer.h b/include/libcamera/internal/control_serializer.h new file mode 100644 index 00000000..99bacd92 --- /dev/null +++ b/include/libcamera/internal/control_serializer.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * control_serializer.h - Control (de)serializer + */ +#ifndef __LIBCAMERA_CONTROL_SERIALIZER_H__ +#define __LIBCAMERA_CONTROL_SERIALIZER_H__ + +#include <map> +#include <memory> +#include <vector> + +#include <libcamera/controls.h> + +namespace libcamera { + +class ByteStreamBuffer; + +class ControlSerializer +{ +public: + ControlSerializer(); + + void reset(); + + static size_t binarySize(const ControlInfoMap &infoMap); + static size_t binarySize(const ControlList &list); + + int serialize(const ControlInfoMap &infoMap, ByteStreamBuffer &buffer); + int serialize(const ControlList &list, ByteStreamBuffer &buffer); + + template<typename T> + T deserialize(ByteStreamBuffer &buffer); + +private: + static size_t binarySize(const ControlValue &value); + static size_t binarySize(const ControlInfo &info); + + static void store(const ControlValue &value, ByteStreamBuffer &buffer); + static void store(const ControlInfo &info, ByteStreamBuffer &buffer); + + ControlValue loadControlValue(ControlType type, ByteStreamBuffer &buffer, + bool isArray = false, unsigned int count = 1); + ControlInfo loadControlInfo(ControlType type, ByteStreamBuffer &buffer); + + unsigned int serial_; + std::vector<std::unique_ptr<ControlId>> controlIds_; + std::map<unsigned int, ControlInfoMap> infoMaps_; + std::map<const ControlInfoMap *, unsigned int> infoMapHandles_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_CONTROL_SERIALIZER_H__ */ diff --git a/include/libcamera/internal/control_validator.h b/include/libcamera/internal/control_validator.h new file mode 100644 index 00000000..f1c9110b --- /dev/null +++ b/include/libcamera/internal/control_validator.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * control_validator.h - Control validator + */ +#ifndef __LIBCAMERA_CONTROL_VALIDATOR_H__ +#define __LIBCAMERA_CONTROL_VALIDATOR_H__ + +#include <string> + +namespace libcamera { + +class ControlId; + +class ControlValidator +{ +public: + virtual ~ControlValidator() {} + + virtual const std::string &name() const = 0; + virtual bool validate(unsigned int id) const = 0; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_CONTROL_VALIDATOR_H__ */ diff --git a/include/libcamera/internal/device_enumerator.h b/include/libcamera/internal/device_enumerator.h new file mode 100644 index 00000000..433e357a --- /dev/null +++ b/include/libcamera/internal/device_enumerator.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2018, Google Inc. + * + * device_enumerator.h - API to enumerate and find media devices + */ +#ifndef __LIBCAMERA_DEVICE_ENUMERATOR_H__ +#define __LIBCAMERA_DEVICE_ENUMERATOR_H__ + +#include <memory> +#include <string> +#include <vector> + +#include <linux/media.h> + +namespace libcamera { + +class MediaDevice; + +class DeviceMatch +{ +public: + DeviceMatch(const std::string &driver); + + void add(const std::string &entity); + + bool match(const MediaDevice *device) const; + +private: + std::string driver_; + std::vector<std::string> entities_; +}; + +class DeviceEnumerator +{ +public: + static std::unique_ptr<DeviceEnumerator> create(); + + virtual ~DeviceEnumerator(); + + virtual int init() = 0; + virtual int enumerate() = 0; + + std::shared_ptr<MediaDevice> search(const DeviceMatch &dm); + +protected: + std::unique_ptr<MediaDevice> createDevice(const std::string &deviceNode); + void addDevice(std::unique_ptr<MediaDevice> &&media); + void removeDevice(const std::string &deviceNode); + +private: + std::vector<std::shared_ptr<MediaDevice>> devices_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_DEVICE_ENUMERATOR_H__ */ diff --git a/include/libcamera/internal/device_enumerator_sysfs.h b/include/libcamera/internal/device_enumerator_sysfs.h new file mode 100644 index 00000000..a63e737a --- /dev/null +++ b/include/libcamera/internal/device_enumerator_sysfs.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * device_enumerator_sysfs.h - sysfs-based device enumerator + */ +#ifndef __LIBCAMERA_DEVICE_ENUMERATOR_SYSFS_H__ +#define __LIBCAMERA_DEVICE_ENUMERATOR_SYSFS_H__ + +#include <memory> +#include <string> + +#include "libcamera/internal/device_enumerator.h" + +class MediaDevice; + +namespace libcamera { + +class DeviceEnumeratorSysfs final : public DeviceEnumerator +{ +public: + int init(); + int enumerate(); + +private: + int populateMediaDevice(MediaDevice *media); + std::string lookupDeviceNode(int major, int minor); +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_DEVICE_ENUMERATOR_SYSFS_H__ */ diff --git a/include/libcamera/internal/device_enumerator_udev.h b/include/libcamera/internal/device_enumerator_udev.h new file mode 100644 index 00000000..fdaa2096 --- /dev/null +++ b/include/libcamera/internal/device_enumerator_udev.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2018-2019, Google Inc. + * + * device_enumerator_udev.h - udev-based device enumerator + */ +#ifndef __LIBCAMERA_DEVICE_ENUMERATOR_UDEV_H__ +#define __LIBCAMERA_DEVICE_ENUMERATOR_UDEV_H__ + +#include <list> +#include <map> +#include <memory> +#include <set> +#include <string> +#include <sys/types.h> + +#include "libcamera/internal/device_enumerator.h" + +struct udev; +struct udev_device; +struct udev_monitor; + +namespace libcamera { + +class EventNotifier; +class MediaDevice; +class MediaEntity; + +class DeviceEnumeratorUdev : public DeviceEnumerator +{ +public: + DeviceEnumeratorUdev(); + ~DeviceEnumeratorUdev(); + + int init() final; + int enumerate() final; + +private: + struct udev *udev_; + struct udev_monitor *monitor_; + EventNotifier *notifier_; + + using DependencyMap = std::map<dev_t, std::list<MediaEntity *>>; + + struct MediaDeviceDeps { + MediaDeviceDeps(std::unique_ptr<MediaDevice> &&media, + DependencyMap &&deps) + : media_(std::move(media)), deps_(std::move(deps)) + { + } + + bool operator==(const MediaDeviceDeps &other) const + { + return media_ == other.media_; + } + + std::unique_ptr<MediaDevice> media_; + DependencyMap deps_; + }; + + std::set<dev_t> orphans_; + std::list<MediaDeviceDeps> pending_; + std::map<dev_t, MediaDeviceDeps *> devMap_; + + int addUdevDevice(struct udev_device *dev); + int populateMediaDevice(MediaDevice *media, DependencyMap *deps); + std::string lookupDeviceNode(dev_t devnum); + + int addV4L2Device(dev_t devnum); + void udevNotify(EventNotifier *notifier); +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_DEVICE_ENUMERATOR_UDEV_H__ */ diff --git a/include/libcamera/internal/event_dispatcher_poll.h b/include/libcamera/internal/event_dispatcher_poll.h new file mode 100644 index 00000000..1f073861 --- /dev/null +++ b/include/libcamera/internal/event_dispatcher_poll.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * event_dispatcher_poll.h - Poll-based event dispatcher + */ +#ifndef __LIBCAMERA_EVENT_DISPATCHER_POLL_H__ +#define __LIBCAMERA_EVENT_DISPATCHER_POLL_H__ + +#include <list> +#include <map> +#include <vector> + +#include <libcamera/event_dispatcher.h> + +struct pollfd; + +namespace libcamera { + +class EventNotifier; +class Timer; + +class EventDispatcherPoll final : public EventDispatcher +{ +public: + EventDispatcherPoll(); + ~EventDispatcherPoll(); + + void registerEventNotifier(EventNotifier *notifier); + void unregisterEventNotifier(EventNotifier *notifier); + + void registerTimer(Timer *timer); + void unregisterTimer(Timer *timer); + + void processEvents(); + void interrupt(); + +private: + struct EventNotifierSetPoll { + short events() const; + EventNotifier *notifiers[3]; + }; + + std::map<int, EventNotifierSetPoll> notifiers_; + std::list<Timer *> timers_; + int eventfd_; + + bool processingEvents_; + + int poll(std::vector<struct pollfd> *pollfds); + void processInterrupt(const struct pollfd &pfd); + void processNotifiers(const std::vector<struct pollfd> &pollfds); + void processTimers(); +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_EVENT_DISPATCHER_POLL_H__ */ diff --git a/include/libcamera/internal/file.h b/include/libcamera/internal/file.h new file mode 100644 index 00000000..f020f2cc --- /dev/null +++ b/include/libcamera/internal/file.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2020, Google Inc. + * + * file.h - File I/O operations + */ +#ifndef __LIBCAMERA_FILE_H__ +#define __LIBCAMERA_FILE_H__ + +#include <map> +#include <string> +#include <sys/types.h> + +#include <libcamera/span.h> + +namespace libcamera { + +class File +{ +public: + enum MapFlag { + MapNoOption = 0, + MapPrivate = (1 << 0), + }; + + enum OpenMode { + NotOpen = 0, + ReadOnly = (1 << 0), + WriteOnly = (1 << 1), + ReadWrite = ReadOnly | WriteOnly, + }; + + File(const std::string &name); + File(); + ~File(); + + File(const File &) = delete; + File &operator=(const File &) = delete; + + const std::string &fileName() const { return name_; } + void setFileName(const std::string &name); + bool exists() const; + + bool open(OpenMode mode); + bool isOpen() const { return fd_ != -1; } + OpenMode openMode() const { return mode_; } + void close(); + + int error() const { return error_; } + ssize_t size() const; + + Span<uint8_t> map(off_t offset = 0, ssize_t size = -1, + MapFlag flags = MapNoOption); + bool unmap(uint8_t *addr); + + static bool exists(const std::string &name); + +private: + void unmapAll(); + + std::string name_; + int fd_; + OpenMode mode_; + + int error_; + std::map<void *, size_t> maps_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_FILE_H__ */ diff --git a/include/libcamera/internal/formats.h b/include/libcamera/internal/formats.h new file mode 100644 index 00000000..4092a93e --- /dev/null +++ b/include/libcamera/internal/formats.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * formats.h - libcamera image formats + */ + +#ifndef __LIBCAMERA_FORMATS_H__ +#define __LIBCAMERA_FORMATS_H__ + +#include <map> +#include <vector> + +#include <libcamera/geometry.h> +#include <libcamera/pixelformats.h> + +#include "libcamera/internal/v4l2_pixelformat.h" + +namespace libcamera { + +class ImageFormats +{ +public: + int addFormat(unsigned int format, const std::vector<SizeRange> &sizes); + + bool isEmpty() const; + std::vector<unsigned int> formats() const; + const std::vector<SizeRange> &sizes(unsigned int format) const; + const std::map<unsigned int, std::vector<SizeRange>> &data() const; + +private: + std::map<unsigned int, std::vector<SizeRange>> data_; +}; + +class PixelFormatInfo +{ +public: + enum ColourEncoding { + ColourEncodingRGB, + ColourEncodingYUV, + ColourEncodingRAW, + }; + + bool isValid() const { return format.isValid(); } + + static const PixelFormatInfo &info(const PixelFormat &format); + + /* \todo Add support for non-contiguous memory planes */ + PixelFormat format; + V4L2PixelFormat v4l2Format; + unsigned int bitsPerPixel; + enum ColourEncoding colourEncoding; + bool packed; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_FORMATS_H__ */ diff --git a/include/libcamera/internal/ipa_context_wrapper.h b/include/libcamera/internal/ipa_context_wrapper.h new file mode 100644 index 00000000..a717d406 --- /dev/null +++ b/include/libcamera/internal/ipa_context_wrapper.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * ipa_context_wrapper.h - Image Processing Algorithm context wrapper + */ +#ifndef __LIBCAMERA_IPA_CONTEXT_WRAPPER_H__ +#define __LIBCAMERA_IPA_CONTEXT_WRAPPER_H__ + +#include <ipa/ipa_interface.h> + +#include "libcamera/internal/control_serializer.h" + +namespace libcamera { + +class IPAContextWrapper final : public IPAInterface +{ +public: + IPAContextWrapper(struct ipa_context *context); + ~IPAContextWrapper(); + + int init(const IPASettings &settings) override; + int start() override; + void stop() override; + void configure(const CameraSensorInfo &sensorInfo, + const std::map<unsigned int, IPAStream> &streamConfig, + const std::map<unsigned int, const ControlInfoMap &> &entityControls) override; + + void mapBuffers(const std::vector<IPABuffer> &buffers) override; + void unmapBuffers(const std::vector<unsigned int> &ids) override; + + virtual void processEvent(const IPAOperationData &data) override; + +private: + static void queue_frame_action(void *ctx, unsigned int frame, + struct ipa_operation_data &data); + static const struct ipa_callback_ops callbacks_; + + void doQueueFrameAction(unsigned int frame, + const IPAOperationData &data); + + struct ipa_context *ctx_; + IPAInterface *intf_; + + ControlSerializer serializer_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_IPA_CONTEXT_WRAPPER_H__ */ diff --git a/include/libcamera/internal/ipa_manager.h b/include/libcamera/internal/ipa_manager.h new file mode 100644 index 00000000..f07d91fc --- /dev/null +++ b/include/libcamera/internal/ipa_manager.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * ipa_manager.h - Image Processing Algorithm module manager + */ +#ifndef __LIBCAMERA_IPA_MANAGER_H__ +#define __LIBCAMERA_IPA_MANAGER_H__ + +#include <stdint.h> +#include <vector> + +#include <ipa/ipa_interface.h> +#include <ipa/ipa_module_info.h> + +#include "libcamera/internal/ipa_module.h" +#include "libcamera/internal/pipeline_handler.h" +#include "libcamera/internal/pub_key.h" + +namespace libcamera { + +class IPAManager +{ +public: + static IPAManager *instance(); + + std::unique_ptr<IPAProxy> createIPA(PipelineHandler *pipe, + uint32_t maxVersion, + uint32_t minVersion); + +private: + std::vector<IPAModule *> modules_; + + IPAManager(); + ~IPAManager(); + + void parseDir(const char *libDir, unsigned int maxDepth, + std::vector<std::string> &files); + unsigned int addDir(const char *libDir, unsigned int maxDepth = 0); + + bool isSignatureValid(IPAModule *ipa) const; + +#if HAVE_IPA_PUBKEY + static const uint8_t publicKeyData_[]; + static const PubKey pubKey_; +#endif +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_IPA_MANAGER_H__ */ diff --git a/include/libcamera/internal/ipa_module.h b/include/libcamera/internal/ipa_module.h new file mode 100644 index 00000000..2f569db0 --- /dev/null +++ b/include/libcamera/internal/ipa_module.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * ipa_module.h - Image Processing Algorithm module + */ +#ifndef __LIBCAMERA_IPA_MODULE_H__ +#define __LIBCAMERA_IPA_MODULE_H__ + +#include <stdint.h> +#include <string> +#include <vector> + +#include <ipa/ipa_interface.h> +#include <ipa/ipa_module_info.h> + +#include "libcamera/internal/log.h" +#include "libcamera/internal/pipeline_handler.h" + +namespace libcamera { + +class IPAModule : public Loggable +{ +public: + explicit IPAModule(const std::string &libPath); + ~IPAModule(); + + bool isValid() const; + + const struct IPAModuleInfo &info() const; + const std::vector<uint8_t> signature() const; + const std::string &path() const; + + bool load(); + + struct ipa_context *createContext(); + + bool match(PipelineHandler *pipe, + uint32_t minVersion, uint32_t maxVersion) const; + +protected: + std::string logPrefix() const override; + +private: + struct IPAModuleInfo info_; + std::vector<uint8_t> signature_; + + std::string libPath_; + bool valid_; + bool loaded_; + + void *dlHandle_; + typedef struct ipa_context *(*IPAIntfFactory)(void); + IPAIntfFactory ipaCreate_; + + int loadIPAModuleInfo(); +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_IPA_MODULE_H__ */ diff --git a/include/libcamera/internal/ipa_proxy.h b/include/libcamera/internal/ipa_proxy.h new file mode 100644 index 00000000..1111065b --- /dev/null +++ b/include/libcamera/internal/ipa_proxy.h @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * ipa_proxy.h - Image Processing Algorithm proxy + */ +#ifndef __LIBCAMERA_IPA_PROXY_H__ +#define __LIBCAMERA_IPA_PROXY_H__ + +#include <memory> +#include <string> +#include <vector> + +#include <ipa/ipa_interface.h> + +namespace libcamera { + +class IPAModule; + +class IPAProxy : public IPAInterface +{ +public: + IPAProxy(IPAModule *ipam); + ~IPAProxy(); + + bool isValid() const { return valid_; } + + std::string configurationFile(const std::string &file) const; + +protected: + std::string resolvePath(const std::string &file) const; + + bool valid_; + +private: + IPAModule *ipam_; +}; + +class IPAProxyFactory +{ +public: + IPAProxyFactory(const char *name); + virtual ~IPAProxyFactory() {} + + virtual std::unique_ptr<IPAProxy> create(IPAModule *ipam) = 0; + + const std::string &name() const { return name_; } + + static void registerType(IPAProxyFactory *factory); + static std::vector<IPAProxyFactory *> &factories(); + +private: + std::string name_; +}; + +#define REGISTER_IPA_PROXY(proxy) \ +class proxy##Factory final : public IPAProxyFactory \ +{ \ +public: \ + proxy##Factory() : IPAProxyFactory(#proxy) {} \ + std::unique_ptr<IPAProxy> create(IPAModule *ipam) \ + { \ + return std::make_unique<proxy>(ipam); \ + } \ +}; \ +static proxy##Factory global_##proxy##Factory; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_IPA_PROXY_H__ */ diff --git a/include/libcamera/internal/ipc_unixsocket.h b/include/libcamera/internal/ipc_unixsocket.h new file mode 100644 index 00000000..820d0561 --- /dev/null +++ b/include/libcamera/internal/ipc_unixsocket.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * ipc_unixsocket.h - IPC mechanism based on Unix sockets + */ + +#ifndef __LIBCAMERA_IPC_UNIXSOCKET_H__ +#define __LIBCAMERA_IPC_UNIXSOCKET_H__ + +#include <stdint.h> +#include <sys/types.h> +#include <vector> + +#include <libcamera/event_notifier.h> + +namespace libcamera { + +class IPCUnixSocket +{ +public: + struct Payload { + std::vector<uint8_t> data; + std::vector<int32_t> fds; + }; + + IPCUnixSocket(); + ~IPCUnixSocket(); + + int create(); + int bind(int fd); + void close(); + bool isBound() const; + + int send(const Payload &payload); + int receive(Payload *payload); + + Signal<IPCUnixSocket *> readyRead; + +private: + struct Header { + uint32_t data; + uint8_t fds; + }; + + int sendData(const void *buffer, size_t length, const int32_t *fds, unsigned int num); + int recvData(void *buffer, size_t length, int32_t *fds, unsigned int num); + + void dataNotifier(EventNotifier *notifier); + + int fd_; + bool headerReceived_; + struct Header header_; + EventNotifier *notifier_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_IPC_UNIXSOCKET_H__ */ diff --git a/include/libcamera/internal/log.h b/include/libcamera/internal/log.h new file mode 100644 index 00000000..cab2034a --- /dev/null +++ b/include/libcamera/internal/log.h @@ -0,0 +1,130 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2018, Google Inc. + * + * log.h - Logging infrastructure + */ +#ifndef __LIBCAMERA_LOG_H__ +#define __LIBCAMERA_LOG_H__ + +#include <chrono> +#include <sstream> + +#include "libcamera/internal/utils.h" + +namespace libcamera { + +enum LogSeverity { + LogInvalid = -1, + LogDebug = 0, + LogInfo, + LogWarning, + LogError, + LogFatal, +}; + +class LogCategory +{ +public: + explicit LogCategory(const char *name); + ~LogCategory(); + + const char *name() const { return name_; } + LogSeverity severity() const { return severity_; } + void setSeverity(LogSeverity severity); + + static const LogCategory &defaultCategory(); + +private: + const char *name_; + LogSeverity severity_; +}; + +#define LOG_DECLARE_CATEGORY(name) \ +extern const LogCategory &_LOG_CATEGORY(name)(); + +#define LOG_DEFINE_CATEGORY(name) \ +const LogCategory &_LOG_CATEGORY(name)() \ +{ \ + static LogCategory category(#name); \ + return category; \ +} + +class LogMessage +{ +public: + LogMessage(const char *fileName, unsigned int line, + LogSeverity severity); + LogMessage(const char *fileName, unsigned int line, + const LogCategory &category, LogSeverity severity); + LogMessage(const LogMessage &) = delete; + LogMessage(LogMessage &&); + ~LogMessage(); + + std::ostream &stream() { return msgStream_; } + + const utils::time_point ×tamp() const { return timestamp_; } + LogSeverity severity() const { return severity_; } + const LogCategory &category() const { return category_; } + const std::string &fileInfo() const { return fileInfo_; } + const std::string msg() const { return msgStream_.str(); } + +private: + void init(const char *fileName, unsigned int line); + + std::ostringstream msgStream_; + const LogCategory &category_; + LogSeverity severity_; + utils::time_point timestamp_; + std::string fileInfo_; +}; + +class Loggable +{ +public: + virtual ~Loggable(); + +protected: + virtual std::string logPrefix() const = 0; + + LogMessage _log(const char *file, unsigned int line, + LogSeverity severity) const; + LogMessage _log(const char *file, unsigned int line, + const LogCategory &category, + LogSeverity severity) const; +}; + +LogMessage _log(const char *file, unsigned int line, LogSeverity severity); +LogMessage _log(const char *file, unsigned int line, + const LogCategory &category, LogSeverity severity); + +#ifndef __DOXYGEN__ +#define _LOG_CATEGORY(name) logCategory##name + +#define _LOG1(severity) \ + _log(__FILE__, __LINE__, Log##severity).stream() +#define _LOG2(category, severity) \ + _log(__FILE__, __LINE__, _LOG_CATEGORY(category)(), Log##severity).stream() + +/* + * Expand the LOG() macro to _LOG1() or _LOG2() based on the number of + * arguments. + */ +#define _LOG_MACRO(_1, _2, NAME, ...) NAME +#define LOG(...) _LOG_MACRO(__VA_ARGS__, _LOG2, _LOG1)(__VA_ARGS__) +#else /* __DOXYGEN___ */ +#define LOG(category, severity) +#endif /* __DOXYGEN__ */ + +#ifndef NDEBUG +#define ASSERT(condition) static_cast<void>(({ \ + if (!(condition)) \ + LOG(Fatal) << "assertion \"" #condition "\" failed"; \ +})) +#else +#define ASSERT(condition) static_cast<void>(false && (condition)) +#endif + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_LOG_H__ */ diff --git a/include/libcamera/internal/media_device.h b/include/libcamera/internal/media_device.h new file mode 100644 index 00000000..9fe76c51 --- /dev/null +++ b/include/libcamera/internal/media_device.h @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2018, Google Inc. + * + * media_device.h - Media device handler + */ +#ifndef __LIBCAMERA_MEDIA_DEVICE_H__ +#define __LIBCAMERA_MEDIA_DEVICE_H__ + +#include <map> +#include <sstream> +#include <string> +#include <vector> + +#include <linux/media.h> + +#include <libcamera/signal.h> + +#include "libcamera/internal/log.h" +#include "libcamera/internal/media_object.h" + +namespace libcamera { + +class MediaDevice : protected Loggable +{ +public: + MediaDevice(const std::string &deviceNode); + ~MediaDevice(); + + bool acquire(); + void release(); + bool busy() const { return acquired_; } + + bool lock(); + void unlock(); + + int populate(); + bool valid() const { return valid_; } + + const std::string driver() const { return driver_; } + const std::string deviceNode() const { return deviceNode_; } + const std::string model() const { return model_; } + unsigned int version() const { return version_; } + + const std::vector<MediaEntity *> &entities() const { return entities_; } + MediaEntity *getEntityByName(const std::string &name) const; + + MediaLink *link(const std::string &sourceName, unsigned int sourceIdx, + const std::string &sinkName, unsigned int sinkIdx); + MediaLink *link(const MediaEntity *source, unsigned int sourceIdx, + const MediaEntity *sink, unsigned int sinkIdx); + MediaLink *link(const MediaPad *source, const MediaPad *sink); + int disableLinks(); + + Signal<MediaDevice *> disconnected; + +protected: + std::string logPrefix() const; + +private: + std::string driver_; + std::string deviceNode_; + std::string model_; + unsigned int version_; + + int fd_; + bool valid_; + bool acquired_; + bool lockOwner_; + + int open(); + void close(); + + std::map<unsigned int, MediaObject *> objects_; + MediaObject *object(unsigned int id); + bool addObject(MediaObject *object); + void clear(); + + std::vector<MediaEntity *> entities_; + + struct media_v2_interface *findInterface(const struct media_v2_topology &topology, + unsigned int entityId); + bool populateEntities(const struct media_v2_topology &topology); + bool populatePads(const struct media_v2_topology &topology); + bool populateLinks(const struct media_v2_topology &topology); + void fixupEntityFlags(struct media_v2_entity *entity); + + friend int MediaLink::setEnabled(bool enable); + int setupLink(const MediaLink *link, unsigned int flags); +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_MEDIA_DEVICE_H__ */ diff --git a/include/libcamera/internal/media_object.h b/include/libcamera/internal/media_object.h new file mode 100644 index 00000000..748eafdc --- /dev/null +++ b/include/libcamera/internal/media_object.h @@ -0,0 +1,124 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2018, Google Inc. + * + * media_object.h - Media Device objects: entities, pads and links. + */ +#ifndef __LIBCAMERA_MEDIA_OBJECT_H__ +#define __LIBCAMERA_MEDIA_OBJECT_H__ + +#include <string> +#include <vector> + +#include <linux/media.h> + +namespace libcamera { + +class MediaDevice; +class MediaEntity; +class MediaPad; + +class MediaObject +{ +public: + MediaDevice *device() { return dev_; } + unsigned int id() const { return id_; } + +protected: + friend class MediaDevice; + + MediaObject(MediaDevice *dev, unsigned int id) + : dev_(dev), id_(id) + { + } + virtual ~MediaObject() {} + + MediaDevice *dev_; + unsigned int id_; +}; + +class MediaLink : public MediaObject +{ +public: + MediaPad *source() const { return source_; } + MediaPad *sink() const { return sink_; } + unsigned int flags() const { return flags_; } + int setEnabled(bool enable); + +private: + friend class MediaDevice; + + MediaLink(const struct media_v2_link *link, + MediaPad *source, MediaPad *sink); + MediaLink(const MediaLink &) = delete; + ~MediaLink() {} + + MediaPad *source_; + MediaPad *sink_; + unsigned int flags_; +}; + +class MediaPad : public MediaObject +{ +public: + unsigned int index() const { return index_; } + MediaEntity *entity() const { return entity_; } + unsigned int flags() const { return flags_; } + const std::vector<MediaLink *> &links() const { return links_; } + + void addLink(MediaLink *link); + +private: + friend class MediaDevice; + + MediaPad(const struct media_v2_pad *pad, MediaEntity *entity); + MediaPad(const MediaPad &) = delete; + ~MediaPad(); + + unsigned int index_; + MediaEntity *entity_; + unsigned int flags_; + + std::vector<MediaLink *> links_; +}; + +class MediaEntity : public MediaObject +{ +public: + const std::string &name() const { return name_; } + unsigned int function() const { return function_; } + unsigned int flags() const { return flags_; } + const std::string &deviceNode() const { return deviceNode_; } + unsigned int deviceMajor() const { return major_; } + unsigned int deviceMinor() const { return minor_; } + + const std::vector<MediaPad *> &pads() const { return pads_; } + + const MediaPad *getPadByIndex(unsigned int index) const; + const MediaPad *getPadById(unsigned int id) const; + + int setDeviceNode(const std::string &deviceNode); + +private: + friend class MediaDevice; + + MediaEntity(MediaDevice *dev, const struct media_v2_entity *entity, + unsigned int major = 0, unsigned int minor = 0); + MediaEntity(const MediaEntity &) = delete; + ~MediaEntity(); + + std::string name_; + unsigned int function_; + unsigned int flags_; + std::string deviceNode_; + unsigned int major_; + unsigned int minor_; + + std::vector<MediaPad *> pads_; + + void addPad(MediaPad *pad); +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_MEDIA_OBJECT_H__ */ diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build new file mode 100644 index 00000000..1f6af579 --- /dev/null +++ b/include/libcamera/internal/meson.build @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: CC0-1.0 + +libcamera_headers = files([ + 'byte_stream_buffer.h', + 'camera_controls.h', + 'camera_sensor.h', + 'control_serializer.h', + 'control_validator.h', + 'device_enumerator.h', + 'device_enumerator_sysfs.h', + 'device_enumerator_udev.h', + 'event_dispatcher_poll.h', + 'file.h', + 'formats.h', + 'ipa_context_wrapper.h', + 'ipa_manager.h', + 'ipa_module.h', + 'ipa_proxy.h', + 'ipc_unixsocket.h', + 'log.h', + 'media_device.h', + 'media_object.h', + 'message.h', + 'pipeline_handler.h', + 'process.h', + 'pub_key.h', + 'semaphore.h', + 'thread.h', + 'utils.h', + 'v4l2_controls.h', + 'v4l2_device.h', + 'v4l2_pixelformat.h', + 'v4l2_subdevice.h', + 'v4l2_videodevice.h', +]) diff --git a/include/libcamera/internal/message.h b/include/libcamera/internal/message.h new file mode 100644 index 00000000..8e8b013d --- /dev/null +++ b/include/libcamera/internal/message.h @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * message.h - Message queue support + */ +#ifndef __LIBCAMERA_MESSAGE_H__ +#define __LIBCAMERA_MESSAGE_H__ + +#include <atomic> + +#include <libcamera/bound_method.h> + +namespace libcamera { + +class BoundMethodBase; +class Object; +class Semaphore; +class Thread; + +class Message +{ +public: + enum Type { + None = 0, + InvokeMessage = 1, + ThreadMoveMessage = 2, + UserMessage = 1000, + }; + + Message(Type type); + virtual ~Message(); + + Type type() const { return type_; } + Object *receiver() const { return receiver_; } + + static Type registerMessageType(); + +private: + friend class Thread; + + Type type_; + Object *receiver_; + + static std::atomic_uint nextUserType_; +}; + +class InvokeMessage : public Message +{ +public: + InvokeMessage(BoundMethodBase *method, + std::shared_ptr<BoundMethodPackBase> pack, + Semaphore *semaphore = nullptr, + bool deleteMethod = false); + ~InvokeMessage(); + + Semaphore *semaphore() const { return semaphore_; } + + void invoke(); + +private: + BoundMethodBase *method_; + std::shared_ptr<BoundMethodPackBase> pack_; + Semaphore *semaphore_; + bool deleteMethod_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_MESSAGE_H__ */ diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h new file mode 100644 index 00000000..428f5887 --- /dev/null +++ b/include/libcamera/internal/pipeline_handler.h @@ -0,0 +1,151 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2018, Google Inc. + * + * pipeline_handler.h - Pipeline handler infrastructure + */ +#ifndef __LIBCAMERA_PIPELINE_HANDLER_H__ +#define __LIBCAMERA_PIPELINE_HANDLER_H__ + +#include <list> +#include <map> +#include <memory> +#include <set> +#include <string> +#include <sys/types.h> +#include <vector> + +#include <libcamera/controls.h> +#include <libcamera/object.h> +#include <libcamera/stream.h> + +#include "libcamera/internal/ipa_proxy.h" + +namespace libcamera { + +class Camera; +class CameraConfiguration; +class CameraManager; +class DeviceEnumerator; +class DeviceMatch; +class FrameBuffer; +class MediaDevice; +class PipelineHandler; +class Request; + +class CameraData +{ +public: + explicit CameraData(PipelineHandler *pipe) + : pipe_(pipe) + { + } + virtual ~CameraData() {} + + Camera *camera_; + PipelineHandler *pipe_; + std::list<Request *> queuedRequests_; + ControlInfoMap controlInfo_; + ControlList properties_; + std::unique_ptr<IPAProxy> ipa_; + +private: + CameraData(const CameraData &) = delete; + CameraData &operator=(const CameraData &) = delete; +}; + +class PipelineHandler : public std::enable_shared_from_this<PipelineHandler>, + public Object +{ +public: + PipelineHandler(CameraManager *manager); + virtual ~PipelineHandler(); + + virtual bool match(DeviceEnumerator *enumerator) = 0; + MediaDevice *acquireMediaDevice(DeviceEnumerator *enumerator, + const DeviceMatch &dm); + + bool lock(); + void unlock(); + + const ControlInfoMap &controls(Camera *camera); + const ControlList &properties(Camera *camera); + + virtual CameraConfiguration *generateConfiguration(Camera *camera, + const StreamRoles &roles) = 0; + virtual int configure(Camera *camera, CameraConfiguration *config) = 0; + + virtual int exportFrameBuffers(Camera *camera, Stream *stream, + std::vector<std::unique_ptr<FrameBuffer>> *buffers) = 0; + + virtual int start(Camera *camera) = 0; + virtual void stop(Camera *camera) = 0; + + int queueRequest(Camera *camera, Request *request); + + bool completeBuffer(Camera *camera, Request *request, + FrameBuffer *buffer); + void completeRequest(Camera *camera, Request *request); + + const char *name() const { return name_; } + +protected: + void registerCamera(std::shared_ptr<Camera> camera, + std::unique_ptr<CameraData> data, dev_t devnum = 0); + void hotplugMediaDevice(MediaDevice *media); + + virtual int queueRequestDevice(Camera *camera, Request *request) = 0; + + CameraData *cameraData(const Camera *camera); + + CameraManager *manager_; + +private: + void mediaDeviceDisconnected(MediaDevice *media); + virtual void disconnect(); + + std::vector<std::shared_ptr<MediaDevice>> mediaDevices_; + std::vector<std::weak_ptr<Camera>> cameras_; + std::map<const Camera *, std::unique_ptr<CameraData>> cameraData_; + + const char *name_; + + friend class PipelineHandlerFactory; +}; + +class PipelineHandlerFactory +{ +public: + PipelineHandlerFactory(const char *name); + virtual ~PipelineHandlerFactory() {} + + std::shared_ptr<PipelineHandler> create(CameraManager *manager); + + const std::string &name() const { return name_; } + + static void registerType(PipelineHandlerFactory *factory); + static std::vector<PipelineHandlerFactory *> &factories(); + +private: + virtual PipelineHandler *createInstance(CameraManager *manager) = 0; + + std::string name_; +}; + +#define REGISTER_PIPELINE_HANDLER(handler) \ +class handler##Factory final : public PipelineHandlerFactory \ +{ \ +public: \ + handler##Factory() : PipelineHandlerFactory(#handler) {} \ + \ +private: \ + PipelineHandler *createInstance(CameraManager *manager) \ + { \ + return new handler(manager); \ + } \ +}; \ +static handler##Factory global_##handler##Factory; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_PIPELINE_HANDLER_H__ */ diff --git a/include/libcamera/internal/process.h b/include/libcamera/internal/process.h new file mode 100644 index 00000000..d322fce1 --- /dev/null +++ b/include/libcamera/internal/process.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * process.h - Process object + */ +#ifndef __LIBCAMERA_PROCESS_H__ +#define __LIBCAMERA_PROCESS_H__ + +#include <string> +#include <vector> + +#include <libcamera/event_notifier.h> + +namespace libcamera { + +class Process final +{ +public: + enum ExitStatus { + NotExited, + NormalExit, + SignalExit, + }; + + Process(); + ~Process(); + + int start(const std::string &path, + const std::vector<std::string> &args = std::vector<std::string>(), + const std::vector<int> &fds = std::vector<int>()); + + ExitStatus exitStatus() const { return exitStatus_; } + int exitCode() const { return exitCode_; } + + void kill(); + + Signal<Process *, enum ExitStatus, int> finished; + +private: + void closeAllFdsExcept(const std::vector<int> &fds); + int isolate(); + void died(int wstatus); + + pid_t pid_; + bool running_; + enum ExitStatus exitStatus_; + int exitCode_; + + friend class ProcessManager; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_PROCESS_H__ */ diff --git a/include/libcamera/internal/pub_key.h b/include/libcamera/internal/pub_key.h new file mode 100644 index 00000000..f35bf373 --- /dev/null +++ b/include/libcamera/internal/pub_key.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2020, Google Inc. + * + * pub_key.h - Public key signature verification + */ +#ifndef __LIBCAMERA_PUB_KEY_H__ +#define __LIBCAMERA_PUB_KEY_H__ + +#include <stdint.h> + +#include <libcamera/span.h> + +#if HAVE_GNUTLS +struct gnutls_pubkey_st; +#endif + +namespace libcamera { + +class PubKey +{ +public: + PubKey(Span<const uint8_t> key); + ~PubKey(); + + bool isValid() const { return valid_; } + bool verify(Span<const uint8_t> data, Span<const uint8_t> sig) const; + +private: + bool valid_; +#if HAVE_GNUTLS + struct gnutls_pubkey_st *pubkey_; +#endif +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_PUB_KEY_H__ */ diff --git a/include/libcamera/internal/semaphore.h b/include/libcamera/internal/semaphore.h new file mode 100644 index 00000000..4d93077c --- /dev/null +++ b/include/libcamera/internal/semaphore.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * semaphore.h - General-purpose counting semaphore + */ +#ifndef __LIBCAMERA_SEMAPHORE_H__ +#define __LIBCAMERA_SEMAPHORE_H__ + +#include <condition_variable> + +#include "libcamera/internal/thread.h" + +namespace libcamera { + +class Semaphore +{ +public: + Semaphore(unsigned int n = 0); + + unsigned int available(); + void acquire(unsigned int n = 1); + bool tryAcquire(unsigned int n = 1); + void release(unsigned int n = 1); + +private: + Mutex mutex_; + std::condition_variable cv_; + unsigned int available_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_SEMAPHORE_H__ */ diff --git a/include/libcamera/internal/thread.h b/include/libcamera/internal/thread.h new file mode 100644 index 00000000..6594c9b0 --- /dev/null +++ b/include/libcamera/internal/thread.h @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * thread.h - Thread support + */ +#ifndef __LIBCAMERA_THREAD_H__ +#define __LIBCAMERA_THREAD_H__ + +#include <memory> +#include <mutex> +#include <sys/types.h> +#include <thread> + +#include <libcamera/signal.h> + +#include "libcamera/internal/utils.h" + +namespace libcamera { + +class EventDispatcher; +class Message; +class Object; +class ThreadData; +class ThreadMain; + +using Mutex = std::mutex; +using MutexLocker = std::unique_lock<std::mutex>; + +class Thread +{ +public: + Thread(); + virtual ~Thread(); + + void start(); + void exit(int code = 0); + bool wait(utils::duration duration = utils::duration::max()); + + bool isRunning(); + + Signal<Thread *> finished; + + static Thread *current(); + static pid_t currentId(); + + EventDispatcher *eventDispatcher(); + void setEventDispatcher(std::unique_ptr<EventDispatcher> dispatcher); + + void dispatchMessages(); + +protected: + int exec(); + virtual void run(); + +private: + void startThread(); + void finishThread(); + + void postMessage(std::unique_ptr<Message> msg, Object *receiver); + void removeMessages(Object *receiver); + + friend class Object; + friend class ThreadData; + friend class ThreadMain; + + void moveObject(Object *object); + void moveObject(Object *object, ThreadData *currentData, + ThreadData *targetData); + + std::thread thread_; + ThreadData *data_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_THREAD_H__ */ diff --git a/include/libcamera/internal/utils.h b/include/libcamera/internal/utils.h new file mode 100644 index 00000000..3334ff16 --- /dev/null +++ b/include/libcamera/internal/utils.h @@ -0,0 +1,197 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2018, Google Inc. + * + * utils.h - Miscellaneous utility functions + */ +#ifndef __LIBCAMERA_UTILS_H__ +#define __LIBCAMERA_UTILS_H__ + +#include <algorithm> +#include <chrono> +#include <memory> +#include <ostream> +#include <sstream> +#include <string> +#include <string.h> +#include <sys/time.h> + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +#ifndef __DOXYGEN__ + +/* uClibc and uClibc-ng don't provide O_TMPFILE */ +#ifndef O_TMPFILE +#define O_TMPFILE (020000000 | O_DIRECTORY) +#endif + +#endif + +namespace libcamera { + +namespace utils { + +const char *basename(const char *path); + +char *secure_getenv(const char *name); +std::string dirname(const std::string &path); + +template<class InputIt1, class InputIt2> +unsigned int set_overlap(InputIt1 first1, InputIt1 last1, + InputIt2 first2, InputIt2 last2) +{ + unsigned int count = 0; + + while (first1 != last1 && first2 != last2) { + if (*first1 < *first2) { + ++first1; + } else { + if (!(*first2 < *first1)) + count++; + ++first2; + } + } + + return count; +} + +/* C++11 doesn't provide std::clamp */ +template <typename T> +const T& clamp(const T& v, const T& lo, const T& hi) +{ + return std::max(lo, std::min(v, hi)); +} + +using clock = std::chrono::steady_clock; +using duration = std::chrono::steady_clock::duration; +using time_point = std::chrono::steady_clock::time_point; + +struct timespec duration_to_timespec(const duration &value); +std::string time_point_to_string(const time_point &time); + +#ifndef __DOXYGEN__ +struct _hex { + uint64_t v; + unsigned int w; +}; + +std::basic_ostream<char, std::char_traits<char>> & +operator<<(std::basic_ostream<char, std::char_traits<char>> &stream, const _hex &h); +#endif + +template<typename T> +_hex hex(T value, unsigned int width = 0); + +#ifndef __DOXYGEN__ +template<> +inline _hex hex<int32_t>(int32_t value, unsigned int width) +{ + return { static_cast<uint64_t>(value), width ? width : 8 }; +} + +template<> +inline _hex hex<uint32_t>(uint32_t value, unsigned int width) +{ + return { static_cast<uint64_t>(value), width ? width : 8 }; +} + +template<> +inline _hex hex<int64_t>(int64_t value, unsigned int width) +{ + return { static_cast<uint64_t>(value), width ? width : 16 }; +} + +template<> +inline _hex hex<uint64_t>(uint64_t value, unsigned int width) +{ + return { static_cast<uint64_t>(value), width ? width : 16 }; +} +#endif + +size_t strlcpy(char *dst, const char *src, size_t size); + +#ifndef __DOXYGEN__ +template<typename Container, typename UnaryOp> +std::string join(const Container &items, const std::string &sep, UnaryOp op) +{ + std::ostringstream ss; + bool first = true; + + for (typename Container::const_iterator it = std::begin(items); + it != std::end(items); ++it) { + if (!first) + ss << sep; + else + first = false; + + ss << op(*it); + } + + return ss.str(); +} + +template<typename Container> +std::string join(const Container &items, const std::string &sep) +{ + std::ostringstream ss; + bool first = true; + + for (typename Container::const_iterator it = std::begin(items); + it != std::end(items); ++it) { + if (!first) + ss << sep; + else + first = false; + + ss << *it; + } + + return ss.str(); +} +#else +template<typename Container, typename UnaryOp> +std::string join(const Container &items, const std::string &sep, UnaryOp op = nullptr); +#endif + +namespace details { + +class StringSplitter +{ +public: + StringSplitter(const std::string &str, const std::string &delim); + + class iterator + { + public: + iterator(const StringSplitter *ss, std::string::size_type pos); + + iterator &operator++(); + std::string operator*() const; + bool operator!=(const iterator &other) const; + + private: + const StringSplitter *ss_; + std::string::size_type pos_; + std::string::size_type next_; + }; + + iterator begin() const; + iterator end() const; + +private: + std::string str_; + std::string delim_; +}; + +} /* namespace details */ + +details::StringSplitter split(const std::string &str, const std::string &delim); + +std::string libcameraBuildPath(); +std::string libcameraSourcePath(); + +} /* namespace utils */ + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_UTILS_H__ */ diff --git a/include/libcamera/internal/v4l2_controls.h b/include/libcamera/internal/v4l2_controls.h new file mode 100644 index 00000000..cffe9efd --- /dev/null +++ b/include/libcamera/internal/v4l2_controls.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * v4l2_controls.h - V4L2 Controls Support + */ + +#ifndef __LIBCAMERA_V4L2_CONTROLS_H__ +#define __LIBCAMERA_V4L2_CONTROLS_H__ + +#include <linux/videodev2.h> + +#include <libcamera/controls.h> + +namespace libcamera { + +class V4L2ControlId : public ControlId +{ +public: + V4L2ControlId(const struct v4l2_query_ext_ctrl &ctrl); +}; + +class V4L2ControlInfo : public ControlInfo +{ +public: + V4L2ControlInfo(const struct v4l2_query_ext_ctrl &ctrl); +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_V4L2_CONTROLS_H__ */ diff --git a/include/libcamera/internal/v4l2_device.h b/include/libcamera/internal/v4l2_device.h new file mode 100644 index 00000000..d491eafd --- /dev/null +++ b/include/libcamera/internal/v4l2_device.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * v4l2_device.h - Common base for V4L2 video devices and subdevices + */ +#ifndef __LIBCAMERA_V4L2_DEVICE_H__ +#define __LIBCAMERA_V4L2_DEVICE_H__ + +#include <map> +#include <memory> +#include <vector> + +#include <linux/videodev2.h> + +#include "libcamera/internal/log.h" +#include "libcamera/internal/v4l2_controls.h" + +namespace libcamera { + +class V4L2Device : protected Loggable +{ +public: + void close(); + bool isOpen() const { return fd_ != -1; } + + const ControlInfoMap &controls() const { return controls_; } + + ControlList getControls(const std::vector<uint32_t> &ids); + int setControls(ControlList *ctrls); + + const std::string &deviceNode() const { return deviceNode_; } + +protected: + V4L2Device(const std::string &deviceNode); + ~V4L2Device(); + + int open(unsigned int flags); + int setFd(int fd); + + int ioctl(unsigned long request, void *argp); + + int fd() { return fd_; } + +private: + void listControls(); + void updateControls(ControlList *ctrls, + const struct v4l2_ext_control *v4l2Ctrls, + unsigned int count); + + std::map<unsigned int, struct v4l2_query_ext_ctrl> controlInfo_; + std::vector<std::unique_ptr<V4L2ControlId>> controlIds_; + ControlInfoMap controls_; + std::string deviceNode_; + int fd_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_V4L2_DEVICE_H__ */ diff --git a/include/libcamera/internal/v4l2_pixelformat.h b/include/libcamera/internal/v4l2_pixelformat.h new file mode 100644 index 00000000..0fe8a017 --- /dev/null +++ b/include/libcamera/internal/v4l2_pixelformat.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * Copyright (C) 2020, Raspberry Pi (Trading) Ltd. + * + * v4l2_pixelformat.h - V4L2 Pixel Format + */ +#ifndef __LIBCAMERA_V4L2_PIXELFORMAT_H__ +#define __LIBCAMERA_V4L2_PIXELFORMAT_H__ + +#include <stdint.h> +#include <string> + +#include <linux/videodev2.h> + +#include <libcamera/pixelformats.h> + +namespace libcamera { + +class V4L2PixelFormat +{ +public: + V4L2PixelFormat() + : fourcc_(0) + { + } + + explicit V4L2PixelFormat(uint32_t fourcc) + : fourcc_(fourcc) + { + } + + bool isValid() const { return fourcc_ != 0; } + uint32_t fourcc() const { return fourcc_; } + operator uint32_t() const { return fourcc_; } + + std::string toString() const; + + PixelFormat toPixelFormat() const; + static V4L2PixelFormat fromPixelFormat(const PixelFormat &pixelFormat, + bool multiplanar); + +private: + uint32_t fourcc_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_V4L2_PIXELFORMAT_H__ */ diff --git a/include/libcamera/internal/v4l2_subdevice.h b/include/libcamera/internal/v4l2_subdevice.h new file mode 100644 index 00000000..1be454f0 --- /dev/null +++ b/include/libcamera/internal/v4l2_subdevice.h @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * v4l2_subdevice.h - V4L2 Subdevice + */ +#ifndef __LIBCAMERA_V4L2_SUBDEVICE_H__ +#define __LIBCAMERA_V4L2_SUBDEVICE_H__ + +#include <string> +#include <vector> + +#include <libcamera/geometry.h> + +#include "libcamera/internal/formats.h" +#include "libcamera/internal/log.h" +#include "libcamera/internal/media_object.h" +#include "libcamera/internal/v4l2_device.h" + +namespace libcamera { + +class MediaDevice; + +struct V4L2SubdeviceFormat { + uint32_t mbus_code; + Size size; + + const std::string toString() const; + uint8_t bitsPerPixel() const; +}; + +class V4L2Subdevice : public V4L2Device +{ +public: + enum Whence { + ActiveFormat, + TryFormat, + }; + + explicit V4L2Subdevice(const MediaEntity *entity); + V4L2Subdevice(const V4L2Subdevice &) = delete; + V4L2Subdevice &operator=(const V4L2Subdevice &) = delete; + ~V4L2Subdevice(); + + int open(); + + const MediaEntity *entity() const { return entity_; } + + int getSelection(unsigned int pad, unsigned int target, + Rectangle *rect); + int setSelection(unsigned int pad, unsigned int target, + Rectangle *rect); + + ImageFormats formats(unsigned int pad); + + int getFormat(unsigned int pad, V4L2SubdeviceFormat *format, + Whence whence = ActiveFormat); + int setFormat(unsigned int pad, V4L2SubdeviceFormat *format, + Whence whence = ActiveFormat); + + static V4L2Subdevice *fromEntityName(const MediaDevice *media, + const std::string &entity); + +protected: + std::string logPrefix() const; + +private: + std::vector<unsigned int> enumPadCodes(unsigned int pad); + std::vector<SizeRange> enumPadSizes(unsigned int pad, + unsigned int code); + + const MediaEntity *entity_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_V4L2_SUBDEVICE_H__ */ diff --git a/include/libcamera/internal/v4l2_videodevice.h b/include/libcamera/internal/v4l2_videodevice.h new file mode 100644 index 00000000..dc259523 --- /dev/null +++ b/include/libcamera/internal/v4l2_videodevice.h @@ -0,0 +1,277 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * v4l2_videodevice.h - V4L2 Video Device + */ +#ifndef __LIBCAMERA_V4L2_VIDEODEVICE_H__ +#define __LIBCAMERA_V4L2_VIDEODEVICE_H__ + +#include <atomic> +#include <memory> +#include <stdint.h> +#include <string> +#include <vector> + +#include <linux/videodev2.h> + +#include <libcamera/buffer.h> +#include <libcamera/geometry.h> +#include <libcamera/pixelformats.h> +#include <libcamera/signal.h> + +#include "libcamera/internal/formats.h" +#include "libcamera/internal/log.h" +#include "libcamera/internal/v4l2_device.h" +#include "libcamera/internal/v4l2_pixelformat.h" + +namespace libcamera { + +class EventNotifier; +class FileDescriptor; +class MediaDevice; +class MediaEntity; + +struct V4L2Capability final : v4l2_capability { + const char *driver() const + { + return reinterpret_cast<const char *>(v4l2_capability::driver); + } + const char *card() const + { + return reinterpret_cast<const char *>(v4l2_capability::card); + } + const char *bus_info() const + { + return reinterpret_cast<const char *>(v4l2_capability::bus_info); + } + unsigned int device_caps() const + { + return capabilities & V4L2_CAP_DEVICE_CAPS + ? v4l2_capability::device_caps + : v4l2_capability::capabilities; + } + bool isMultiplanar() const + { + return device_caps() & (V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_VIDEO_OUTPUT_MPLANE | + V4L2_CAP_VIDEO_M2M_MPLANE); + } + bool isCapture() const + { + return device_caps() & (V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_META_CAPTURE); + } + bool isOutput() const + { + return device_caps() & (V4L2_CAP_VIDEO_OUTPUT | + V4L2_CAP_VIDEO_OUTPUT_MPLANE | + V4L2_CAP_META_OUTPUT); + } + bool isVideo() const + { + return device_caps() & (V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_VIDEO_OUTPUT | + V4L2_CAP_VIDEO_OUTPUT_MPLANE); + } + bool isM2M() const + { + return device_caps() & (V4L2_CAP_VIDEO_M2M | + V4L2_CAP_VIDEO_M2M_MPLANE); + } + bool isMeta() const + { + return device_caps() & (V4L2_CAP_META_CAPTURE | + V4L2_CAP_META_OUTPUT); + } + bool isVideoCapture() const + { + return isVideo() && isCapture(); + } + bool isVideoOutput() const + { + return isVideo() && isOutput(); + } + bool isMetaCapture() const + { + return isMeta() && isCapture(); + } + bool isMetaOutput() const + { + return isMeta() && isOutput(); + } + bool hasStreaming() const + { + return device_caps() & V4L2_CAP_STREAMING; + } +}; + +class V4L2BufferCache +{ +public: + V4L2BufferCache(unsigned int numEntries); + V4L2BufferCache(const std::vector<std::unique_ptr<FrameBuffer>> &buffers); + ~V4L2BufferCache(); + + int get(const FrameBuffer &buffer); + void put(unsigned int index); + +private: + class Entry + { + public: + Entry(); + Entry(bool free, uint64_t lastUsed, const FrameBuffer &buffer); + + bool operator==(const FrameBuffer &buffer) const; + + bool free; + uint64_t lastUsed; + + private: + struct Plane { + Plane(const FrameBuffer::Plane &plane) + : fd(plane.fd.fd()), length(plane.length) + { + } + + int fd; + unsigned int length; + }; + + std::vector<Plane> planes_; + }; + + std::atomic<uint64_t> lastUsedCounter_; + std::vector<Entry> cache_; + /* \todo Expose the miss counter through an instrumentation API. */ + unsigned int missCounter_; +}; + +class V4L2DeviceFormat +{ +public: + V4L2PixelFormat fourcc; + Size size; + + struct { + uint32_t size; + uint32_t bpl; + } planes[3]; + unsigned int planesCount; + + const std::string toString() const; +}; + +class V4L2VideoDevice : public V4L2Device +{ +public: + explicit V4L2VideoDevice(const std::string &deviceNode); + explicit V4L2VideoDevice(const MediaEntity *entity); + V4L2VideoDevice(const V4L2VideoDevice &) = delete; + ~V4L2VideoDevice(); + + V4L2VideoDevice &operator=(const V4L2VideoDevice &) = delete; + + int open(); + int open(int handle, enum v4l2_buf_type type); + void close(); + + const char *driverName() const { return caps_.driver(); } + const char *deviceName() const { return caps_.card(); } + const char *busName() const { return caps_.bus_info(); } + + const V4L2Capability &caps() const { return caps_; } + + int getFormat(V4L2DeviceFormat *format); + int setFormat(V4L2DeviceFormat *format); + std::map<V4L2PixelFormat, std::vector<SizeRange>> formats(uint32_t code = 0); + + int setSelection(unsigned int target, Rectangle *rect); + + int allocateBuffers(unsigned int count, + std::vector<std::unique_ptr<FrameBuffer>> *buffers); + int exportBuffers(unsigned int count, + std::vector<std::unique_ptr<FrameBuffer>> *buffers); + int importBuffers(unsigned int count); + int releaseBuffers(); + + int queueBuffer(FrameBuffer *buffer); + Signal<FrameBuffer *> bufferReady; + + int setFrameStartEnabled(bool enable); + Signal<uint32_t> frameStart; + + int streamOn(); + int streamOff(); + + static V4L2VideoDevice *fromEntityName(const MediaDevice *media, + const std::string &entity); + + V4L2PixelFormat toV4L2PixelFormat(const PixelFormat &pixelFormat); + +protected: + std::string logPrefix() const; + +private: + int getFormatMeta(V4L2DeviceFormat *format); + int setFormatMeta(V4L2DeviceFormat *format); + + int getFormatMultiplane(V4L2DeviceFormat *format); + int setFormatMultiplane(V4L2DeviceFormat *format); + + int getFormatSingleplane(V4L2DeviceFormat *format); + int setFormatSingleplane(V4L2DeviceFormat *format); + + std::vector<V4L2PixelFormat> enumPixelformats(uint32_t code); + std::vector<SizeRange> enumSizes(V4L2PixelFormat pixelFormat); + + int requestBuffers(unsigned int count, enum v4l2_memory memoryType); + int createBuffers(unsigned int count, + std::vector<std::unique_ptr<FrameBuffer>> *buffers); + std::unique_ptr<FrameBuffer> createBuffer(unsigned int index); + FileDescriptor exportDmabufFd(unsigned int index, unsigned int plane); + + void bufferAvailable(EventNotifier *notifier); + FrameBuffer *dequeueBuffer(); + + void eventAvailable(EventNotifier *notifier); + + V4L2Capability caps_; + + enum v4l2_buf_type bufferType_; + enum v4l2_memory memoryType_; + + V4L2BufferCache *cache_; + std::map<unsigned int, FrameBuffer *> queuedBuffers_; + + EventNotifier *fdBufferNotifier_; + EventNotifier *fdEventNotifier_; + + bool frameStartEnabled_; +}; + +class V4L2M2MDevice +{ +public: + V4L2M2MDevice(const std::string &deviceNode); + ~V4L2M2MDevice(); + + int open(); + void close(); + + V4L2VideoDevice *output() { return output_; } + V4L2VideoDevice *capture() { return capture_; } + +private: + std::string deviceNode_; + + V4L2VideoDevice *output_; + V4L2VideoDevice *capture_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_V4L2_VIDEODEVICE_H__ */ diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build index cea47eb8..f9c8e64b 100644 --- a/include/libcamera/meson.build +++ b/include/libcamera/meson.build @@ -23,6 +23,8 @@ libcamera_api = files([ include_dir = join_paths(libcamera_include_dir, 'libcamera') +subdir('internal') + install_headers(libcamera_api, subdir : include_dir) |