#pragma once
#include <array>
#include <string>
#include <thread>
#include <mutex>
#include <sys/mman.h>
#include "UvcDevicePort.hpp"
#include "stream/StreamProfile.hpp"
#include <linux/uvcvideo.h>
#include <linux/videodev2.h>
#include <linux/usb/video.h>
#ifdef V4L2_META_FMT_UVC
constexpr bool metadata_node = true;
#else
constexpr bool metadata_node = false;
#define V4L2_META_FMT_UVC v4l2_fourcc('U', 'V', 'C', 'H')
#ifndef V4L2_CAP_META_CAPTURE
#define V4L2_CAP_META_CAPTURE 0x00800000
#endif
#endif
namespace libobsensor {
static const uint32_t MAX_META_DATA_SIZE = 255;
static const uint32_t MAX_BUFFER_COUNT = 4;
static const uint32_t LOCAL_V4L2_META_FMT_D4XX = v4l2_fourcc('D', '4', 'X', 'X'); #define LOCAL_V4L2_BUF_TYPE_META_CAPTURE ((v4l2_buf_type)13)
#pragma pack(push, 1)
struct V4L2UvcMetaHeader {
uint64_t ns; uint16_t sof; };
#pragma pack(pop)
struct V4L2FrameBuffer {
~V4L2FrameBuffer() {
if(ptr != nullptr) {
munmap(ptr, length);
ptr = nullptr;
}
}
uint32_t length = 0;
uint32_t actual_length = 0;
uint32_t sequence = 0;
uint8_t *ptr = nullptr;
};
struct V4lDeviceInfo {
std::string name;
v4l2_capability cap; };
struct V4lDeviceHandle {
std::shared_ptr<V4lDeviceInfo> info;
int fd = -1;
std::array<V4L2FrameBuffer, MAX_BUFFER_COUNT> buffers;
std::shared_ptr<V4lDeviceInfo> metadataInfo;
int metadataFd = -1;
std::array<V4L2FrameBuffer, MAX_BUFFER_COUNT> metadataBuffers;
MutableFrameCallback frameCallback;
std::shared_ptr<const VideoStreamProfile> profile = nullptr;
int stopPipeFd[2] = { -1, -1 }; std::shared_ptr<std::thread> captureThread = nullptr;
std::atomic<bool> isCapturing = { false };
std::atomic<std::uint64_t> loopFrameIndex = { 0 };
};
class ObV4lUvcDevicePort : public UvcDevicePort {
public:
explicit ObV4lUvcDevicePort(std::shared_ptr<const USBSourcePortInfo> portInfo);
~ObV4lUvcDevicePort() noexcept override;
virtual std::shared_ptr<const SourcePortInfo> getSourcePortInfo() const override;
StreamProfileList getStreamProfileList() override;
void startStream(std::shared_ptr<const StreamProfile> profile, MutableFrameCallback callback) override;
void stopStream(std::shared_ptr<const StreamProfile> profile) override;
void stopAllStream() override;
bool getPu(uint32_t propertyId, int32_t &value) override;
bool setPu(uint32_t propertyId, int32_t value) override;
UvcControlRange getPuRange(uint32_t propertyId) override;
uint32_t sendAndReceive(const uint8_t *sendData, uint32_t sendLen, uint8_t *recvData, uint32_t exceptedRecvLen) override;
static std::vector<std::shared_ptr<V4lDeviceInfo>> queryRelatedDevices(std::shared_ptr<const USBSourcePortInfo> portInfo);
static bool isContainedMetadataDevice(std::shared_ptr<const USBSourcePortInfo> portInfo);
OBUvcBackendType getBackendType() const override;
#ifdef __ANDROID__
virtual std::string getUsbConnectType() override {return "";}
#endif
private:
static void captureLoop(std::shared_ptr<V4lDeviceHandle> deviceHandle);
bool getXu(uint8_t ctrl, uint8_t *data, uint32_t *len);
bool setXu(uint8_t ctrl, const uint8_t *data, uint32_t len);
UvcControlRange getXuRange(uint8_t control, int len);
bool pendForCtrlStatusEvent() const;
void subscribeToCtrlEvent(uint32_t ctrl_id) const;
void unsubscribeFromCtrlEvent(uint32_t ctrl_id) const;
private:
std::shared_ptr<const USBSourcePortInfo> portInfo_ = nullptr;
std::vector<std::shared_ptr<V4lDeviceHandle>> deviceHandles_;
std::recursive_mutex ctrlMutex_;
};
}