libcamera always keeps all /dev/video# and /dev/v4l2_subdev# nodes for a pipeline open after enumerating the camera. This is a problem for the uvcvideo pipeline handler. Keeping /dev/video# open stops the UVC USB device from being able to enter runtime-suspend causing significant unnecessary power-usage. Add a stub acquireDevice() function to the PipelineHandler class which pipeline handlers can override. The uvcvideo pipeline handler will use this to delay opening /dev/video# until the device is acquired. This is a special case because the kernel uvcvideo driver powers on the USB device as soon as /dev/video# is opened. This behavior should *not* be copied by other pipeline handlers. Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Harvey Yang <chenghaoyang@chromium.org> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
150 lines
3.7 KiB
C++
150 lines
3.7 KiB
C++
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
/*
|
|
* Copyright (C) 2018, Google Inc.
|
|
*
|
|
* Pipeline handler infrastructure
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <memory>
|
|
#include <queue>
|
|
#include <set>
|
|
#include <string>
|
|
#include <sys/types.h>
|
|
#include <vector>
|
|
|
|
#include <libcamera/base/mutex.h>
|
|
#include <libcamera/base/object.h>
|
|
|
|
#include <libcamera/controls.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 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 acquire(Camera *camera);
|
|
void release(Camera *camera);
|
|
|
|
virtual std::unique_ptr<CameraConfiguration> generateConfiguration(Camera *camera,
|
|
Span<const StreamRole> 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, const ControlList *controls) = 0;
|
|
void stop(Camera *camera);
|
|
bool hasPendingRequests(const Camera *camera) const;
|
|
|
|
void registerRequest(Request *request);
|
|
void queueRequest(Request *request);
|
|
|
|
bool completeBuffer(Request *request, FrameBuffer *buffer);
|
|
void completeRequest(Request *request);
|
|
|
|
std::string configurationFile(const std::string &subdir,
|
|
const std::string &name) const;
|
|
|
|
const char *name() const { return name_; }
|
|
|
|
CameraManager *cameraManager() const { return manager_; }
|
|
|
|
protected:
|
|
void registerCamera(std::shared_ptr<Camera> camera);
|
|
void hotplugMediaDevice(MediaDevice *media);
|
|
|
|
virtual int queueRequestDevice(Camera *camera, Request *request) = 0;
|
|
virtual void stopDevice(Camera *camera) = 0;
|
|
|
|
virtual bool acquireDevice(Camera *camera);
|
|
virtual void releaseDevice(Camera *camera);
|
|
|
|
CameraManager *manager_;
|
|
|
|
private:
|
|
void unlockMediaDevices();
|
|
|
|
void mediaDeviceDisconnected(MediaDevice *media);
|
|
virtual void disconnect();
|
|
|
|
void doQueueRequest(Request *request);
|
|
void doQueueRequests();
|
|
|
|
std::vector<std::shared_ptr<MediaDevice>> mediaDevices_;
|
|
std::vector<std::weak_ptr<Camera>> cameras_;
|
|
|
|
std::queue<Request *> waitingRequests_;
|
|
|
|
const char *name_;
|
|
|
|
Mutex lock_;
|
|
unsigned int useCount_ LIBCAMERA_TSA_GUARDED_BY(lock_);
|
|
|
|
friend class PipelineHandlerFactoryBase;
|
|
};
|
|
|
|
class PipelineHandlerFactoryBase
|
|
{
|
|
public:
|
|
PipelineHandlerFactoryBase(const char *name);
|
|
virtual ~PipelineHandlerFactoryBase() = default;
|
|
|
|
std::shared_ptr<PipelineHandler> create(CameraManager *manager) const;
|
|
|
|
const std::string &name() const { return name_; }
|
|
|
|
static std::vector<PipelineHandlerFactoryBase *> &factories();
|
|
static const PipelineHandlerFactoryBase *getFactoryByName(const std::string &name);
|
|
|
|
private:
|
|
static void registerType(PipelineHandlerFactoryBase *factory);
|
|
|
|
virtual std::unique_ptr<PipelineHandler>
|
|
createInstance(CameraManager *manager) const = 0;
|
|
|
|
std::string name_;
|
|
};
|
|
|
|
template<typename _PipelineHandler>
|
|
class PipelineHandlerFactory final : public PipelineHandlerFactoryBase
|
|
{
|
|
public:
|
|
PipelineHandlerFactory(const char *name)
|
|
: PipelineHandlerFactoryBase(name)
|
|
{
|
|
}
|
|
|
|
std::unique_ptr<PipelineHandler>
|
|
createInstance(CameraManager *manager) const override
|
|
{
|
|
return std::make_unique<_PipelineHandler>(manager);
|
|
}
|
|
};
|
|
|
|
#define REGISTER_PIPELINE_HANDLER(handler, name) \
|
|
static PipelineHandlerFactory<handler> global_##handler##Factory(name);
|
|
|
|
} /* namespace libcamera */
|