diff options
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) |