summaryrefslogtreecommitdiff
path: root/include/libcamera/internal/v4l2_videodevice.h
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2020-05-12 00:58:34 +0300
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2020-05-16 03:38:11 +0300
commit93e72b695e477ac1efc22a0bdddb177199cf2fb9 (patch)
tree7ba4b9fe0d5442ad7ca4e25aee1bc17b830a98ed /include/libcamera/internal/v4l2_videodevice.h
parent79c5df21ddde12f98eacf2ece8e3091e4f845d38 (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/libcamera/internal/v4l2_videodevice.h')
-rw-r--r--include/libcamera/internal/v4l2_videodevice.h277
1 files changed, 277 insertions, 0 deletions
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__ */