192 lines
6.3 KiB
C
192 lines
6.3 KiB
C
|
|
/*
|
||
|
|
* Copyright (C) 2023 The Android Open Source Project
|
||
|
|
*
|
||
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
|
* you may not use this file except in compliance with the License.
|
||
|
|
* You may obtain a copy of the License at
|
||
|
|
*
|
||
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
|
*
|
||
|
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
|
* See the License for the specific language governing permissions and
|
||
|
|
* limitations under the License.
|
||
|
|
*/
|
||
|
|
|
||
|
|
#pragma once
|
||
|
|
|
||
|
|
#include <Buffer.h>
|
||
|
|
#include <DeviceAsWebcamServiceManager.h>
|
||
|
|
#include <FrameProvider.h>
|
||
|
|
#include <Utils.h>
|
||
|
|
#include <android-base/unique_fd.h>
|
||
|
|
#include <android/hardware_buffer.h>
|
||
|
|
#include <linux/usb/g_uvc.h>
|
||
|
|
#include <linux/usb/video.h>
|
||
|
|
#include <atomic>
|
||
|
|
#include <thread>
|
||
|
|
#include <vector>
|
||
|
|
|
||
|
|
namespace android {
|
||
|
|
namespace webcam {
|
||
|
|
|
||
|
|
typedef std::vector<struct epoll_event> Events;
|
||
|
|
|
||
|
|
using android::base::unique_fd;
|
||
|
|
|
||
|
|
class EpollW {
|
||
|
|
public:
|
||
|
|
Status init();
|
||
|
|
Status add(int fd, uint32_t events);
|
||
|
|
Status modify(int fd, uint32_t events);
|
||
|
|
Status remove(int fd);
|
||
|
|
Events waitForEvents();
|
||
|
|
|
||
|
|
private:
|
||
|
|
unique_fd mEpollFd;
|
||
|
|
};
|
||
|
|
|
||
|
|
struct ConfigFrame {
|
||
|
|
uint32_t index = 0;
|
||
|
|
uint32_t width = 0;
|
||
|
|
uint32_t height = 0;
|
||
|
|
std::vector<uint32_t> intervals;
|
||
|
|
};
|
||
|
|
|
||
|
|
struct ConfigFormat {
|
||
|
|
uint32_t formatIndex = 0;
|
||
|
|
uint32_t fcc;
|
||
|
|
std::vector<ConfigFrame> frames;
|
||
|
|
};
|
||
|
|
|
||
|
|
struct ConfigEndPoint {
|
||
|
|
uint32_t streamingInterval = 0;
|
||
|
|
uint32_t streamingMaxPacketSize = 0;
|
||
|
|
uint32_t streamingMaxBurst = 0;
|
||
|
|
};
|
||
|
|
|
||
|
|
struct ConfigStreaming {
|
||
|
|
ConfigEndPoint ep;
|
||
|
|
std::vector<ConfigFormat> formats;
|
||
|
|
uint32_t interfaceNumber = 0;
|
||
|
|
};
|
||
|
|
|
||
|
|
struct UVCProperties {
|
||
|
|
std::string videoNode;
|
||
|
|
std::string udc;
|
||
|
|
ConfigStreaming streaming;
|
||
|
|
uint32_t controlInterfaceNumber = 0;
|
||
|
|
};
|
||
|
|
|
||
|
|
// This struct has the information needed to uniquely identify a 'chosen' format : the format index
|
||
|
|
// which indexes into the format list advertised by the UVC V4L2 node, the frame index which indexes
|
||
|
|
// the frame size in the frame size list per format, and finally the frame interval for the
|
||
|
|
// particular format and size chosen.
|
||
|
|
struct FormatTriplet {
|
||
|
|
// Note: These are '1' indexed.
|
||
|
|
uint8_t formatIndex = 1;
|
||
|
|
uint8_t frameSizeIndex = 1;
|
||
|
|
uint32_t frameInterval = 0;
|
||
|
|
FormatTriplet(uint8_t formatIndex, uint8_t frameSizeIndex, uint32_t frameInterval)
|
||
|
|
: formatIndex(formatIndex), frameSizeIndex(frameSizeIndex), frameInterval(frameInterval) {}
|
||
|
|
};
|
||
|
|
|
||
|
|
// This class manages all things related to UVC event handling.
|
||
|
|
class UVCProvider : public std::enable_shared_from_this<UVCProvider> {
|
||
|
|
public:
|
||
|
|
static std::string getVideoNode();
|
||
|
|
|
||
|
|
UVCProvider() = default;
|
||
|
|
~UVCProvider();
|
||
|
|
|
||
|
|
Status init();
|
||
|
|
// Start listening for UVC events
|
||
|
|
Status startService();
|
||
|
|
|
||
|
|
void stopService();
|
||
|
|
|
||
|
|
int encodeImage(AHardwareBuffer* hardwareBuffer, long timestamp);
|
||
|
|
|
||
|
|
void watchStreamEvent();
|
||
|
|
|
||
|
|
private:
|
||
|
|
// Created after a UVC_SETUP event has been received and processed by UVCProvider
|
||
|
|
// This class manages stream related events UVC_STREAMON / STREAMOFF and queries by the host
|
||
|
|
// for probing and committing controls.
|
||
|
|
class UVCDevice : public BufferCreatorAndDestroyer {
|
||
|
|
public:
|
||
|
|
explicit UVCDevice(std::weak_ptr<UVCProvider> parent);
|
||
|
|
~UVCDevice() override = default;
|
||
|
|
void closeUVCFd();
|
||
|
|
[[nodiscard]] bool isInited() const;
|
||
|
|
int getUVCFd() { return mUVCFd.get(); }
|
||
|
|
void processSetupEvent(const struct usb_ctrlrequest* request,
|
||
|
|
struct uvc_request_data* response);
|
||
|
|
void processSetupControlEvent(const struct usb_ctrlrequest* request,
|
||
|
|
struct uvc_request_data* response);
|
||
|
|
void processSetupStreamingEvent(const struct usb_ctrlrequest* request,
|
||
|
|
struct uvc_request_data* response);
|
||
|
|
|
||
|
|
void processSetupClassEvent(const struct usb_ctrlrequest* request,
|
||
|
|
struct uvc_request_data* response);
|
||
|
|
void processDataEvent(const struct uvc_request_data*);
|
||
|
|
void processStreamOnEvent();
|
||
|
|
void processStreamOffEvent();
|
||
|
|
void processStreamEvent();
|
||
|
|
Status encodeImage(AHardwareBuffer* buffer, long timestamp);
|
||
|
|
|
||
|
|
// BufferCreatorAndDestroyer overrides
|
||
|
|
Status allocateAndMapBuffers(
|
||
|
|
std::shared_ptr<Buffer>* consumerBuffer,
|
||
|
|
std::vector<std::shared_ptr<Buffer>>* producerBuffers) override;
|
||
|
|
void destroyBuffers(std::shared_ptr<Buffer>& consumerBuffer,
|
||
|
|
std::vector<std::shared_ptr<Buffer>>& producerBuffers) override;
|
||
|
|
|
||
|
|
private:
|
||
|
|
std::shared_ptr<UVCProperties> parseUvcProperties();
|
||
|
|
std::vector<ConfigFormat> getFormats();
|
||
|
|
|
||
|
|
void getFrameIntervals(ConfigFrame* frame, ConfigFormat* format);
|
||
|
|
void getFormatFrames(ConfigFormat* format);
|
||
|
|
|
||
|
|
Status openV4L2DeviceAndSubscribe(const std::string& videoNode);
|
||
|
|
void setStreamingControl(struct uvc_streaming_control* streamingControl,
|
||
|
|
const FormatTriplet* req);
|
||
|
|
void commitControls();
|
||
|
|
|
||
|
|
std::shared_ptr<Buffer> mapBuffer(uint32_t i);
|
||
|
|
static Status unmapBuffer(std::shared_ptr<Buffer>& buffer);
|
||
|
|
|
||
|
|
Status getFrameAndQueueBufferToGadgetDriver(bool firstBuffer = false);
|
||
|
|
|
||
|
|
struct uvc_streaming_control mProbe {};
|
||
|
|
struct uvc_streaming_control mCommit {};
|
||
|
|
uint8_t mCurrentControlState = UVC_VS_CONTROL_UNDEFINED;
|
||
|
|
std::weak_ptr<UVCProvider> mParent;
|
||
|
|
std::shared_ptr<UVCProperties> mUVCProperties;
|
||
|
|
std::shared_ptr<BufferManager> mBufferManager;
|
||
|
|
std::shared_ptr<FrameProvider> mFrameProvider;
|
||
|
|
unique_fd mUVCFd;
|
||
|
|
// Path to /dev/video*, this is the node we open up and poll the fd for uvc / v4l2 events.
|
||
|
|
std::string mVideoNode;
|
||
|
|
struct v4l2_format mV4l2Format {};
|
||
|
|
uint32_t mFps = 0;
|
||
|
|
bool mInited = false;
|
||
|
|
};
|
||
|
|
|
||
|
|
void stopAndWaitForUVCListenerThread();
|
||
|
|
void startUVCListenerThread();
|
||
|
|
void ListenToUVCFds();
|
||
|
|
|
||
|
|
void processUVCEvent();
|
||
|
|
|
||
|
|
std::shared_ptr<UVCDevice> mUVCDevice;
|
||
|
|
std::thread mUVCListenerThread;
|
||
|
|
volatile bool mListenToUVCFds = true;
|
||
|
|
EpollW mEpollW;
|
||
|
|
};
|
||
|
|
|
||
|
|
} // namespace webcam
|
||
|
|
} // namespace android
|