libcamera/include/libcamera/internal/pipeline_handler.h
Hans de Goede c05e45ac77 pipeline_handler: Add acquireDevice() function to mirror releaseDevice()
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>
2024-08-30 15:15:06 +03:00

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 */