mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	libcamera: implement allocation and dataflow
Keep track of the negotiated parameters and use those to construct the Buffers param. Use the FrameAllocator to allocate buffer memory. Keep a request for each buffer and queue them. In requestComplete, put the request metadata info into the buffer and header and write the finished buffer id to a ringbuffer. Then wake up the data thread to pop the finished buffer_id and push it in the graph. Remove some old files.
This commit is contained in:
		
							parent
							
								
									b2c38a2b3b
								
							
						
					
					
						commit
						0fd5e3fdb2
					
				
					 4 changed files with 262 additions and 1361 deletions
				
			
		| 
						 | 
					@ -30,6 +30,7 @@
 | 
				
			||||||
#include <sys/types.h>
 | 
					#include <sys/types.h>
 | 
				
			||||||
#include <sys/stat.h>
 | 
					#include <sys/stat.h>
 | 
				
			||||||
#include <fcntl.h>
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					#include <deque>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <spa/support/plugin.h>
 | 
					#include <spa/support/plugin.h>
 | 
				
			||||||
#include <spa/support/log.h>
 | 
					#include <spa/support/log.h>
 | 
				
			||||||
| 
						 | 
					@ -39,6 +40,7 @@
 | 
				
			||||||
#include <spa/utils/names.h>
 | 
					#include <spa/utils/names.h>
 | 
				
			||||||
#include <spa/utils/result.h>
 | 
					#include <spa/utils/result.h>
 | 
				
			||||||
#include <spa/utils/string.h>
 | 
					#include <spa/utils/string.h>
 | 
				
			||||||
 | 
					#include <spa/utils/ringbuffer.h>
 | 
				
			||||||
#include <spa/monitor/device.h>
 | 
					#include <spa/monitor/device.h>
 | 
				
			||||||
#include <spa/node/node.h>
 | 
					#include <spa/node/node.h>
 | 
				
			||||||
#include <spa/node/io.h>
 | 
					#include <spa/node/io.h>
 | 
				
			||||||
| 
						 | 
					@ -52,6 +54,8 @@
 | 
				
			||||||
#include <libcamera/camera.h>
 | 
					#include <libcamera/camera.h>
 | 
				
			||||||
#include <libcamera/stream.h>
 | 
					#include <libcamera/stream.h>
 | 
				
			||||||
#include <libcamera/formats.h>
 | 
					#include <libcamera/formats.h>
 | 
				
			||||||
 | 
					#include <libcamera/framebuffer.h>
 | 
				
			||||||
 | 
					#include <libcamera/framebuffer_allocator.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "libcamera.h"
 | 
					#include "libcamera.h"
 | 
				
			||||||
#include "libcamera-manager.hpp"
 | 
					#include "libcamera-manager.hpp"
 | 
				
			||||||
| 
						 | 
					@ -67,6 +71,7 @@ static void reset_props(struct props *props)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MAX_BUFFERS	32
 | 
					#define MAX_BUFFERS	32
 | 
				
			||||||
 | 
					#define MASK_BUFFERS	31
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define BUFFER_FLAG_OUTSTANDING	(1<<0)
 | 
					#define BUFFER_FLAG_OUTSTANDING	(1<<0)
 | 
				
			||||||
#define BUFFER_FLAG_ALLOCATED	(1<<1)
 | 
					#define BUFFER_FLAG_ALLOCATED	(1<<1)
 | 
				
			||||||
| 
						 | 
					@ -95,6 +100,7 @@ struct port {
 | 
				
			||||||
	bool have_format;
 | 
						bool have_format;
 | 
				
			||||||
	struct spa_video_info current_format;
 | 
						struct spa_video_info current_format;
 | 
				
			||||||
	struct spa_fraction rate;
 | 
						struct spa_fraction rate;
 | 
				
			||||||
 | 
						StreamConfiguration streamConfig;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint32_t memtype;
 | 
						uint32_t memtype;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -104,8 +110,8 @@ struct port {
 | 
				
			||||||
	struct buffer buffers[MAX_BUFFERS];
 | 
						struct buffer buffers[MAX_BUFFERS];
 | 
				
			||||||
	uint32_t n_buffers;
 | 
						uint32_t n_buffers;
 | 
				
			||||||
	struct spa_list queue;
 | 
						struct spa_list queue;
 | 
				
			||||||
 | 
						struct spa_ringbuffer ring;
 | 
				
			||||||
	struct spa_source source;
 | 
						uint32_t ring_ids[MAX_BUFFERS];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint64_t info_all;
 | 
						uint64_t info_all;
 | 
				
			||||||
	struct spa_port_info info;
 | 
						struct spa_port_info info;
 | 
				
			||||||
| 
						 | 
					@ -123,7 +129,6 @@ struct port {
 | 
				
			||||||
struct impl {
 | 
					struct impl {
 | 
				
			||||||
	struct spa_handle handle;
 | 
						struct spa_handle handle;
 | 
				
			||||||
	struct spa_node node;
 | 
						struct spa_node node;
 | 
				
			||||||
	bool have_source;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct spa_log *log;
 | 
						struct spa_log *log;
 | 
				
			||||||
	struct spa_loop *data_loop;
 | 
						struct spa_loop *data_loop;
 | 
				
			||||||
| 
						 | 
					@ -145,13 +150,23 @@ struct impl {
 | 
				
			||||||
	CameraManager *manager;
 | 
						CameraManager *manager;
 | 
				
			||||||
	std::shared_ptr<Camera> camera;
 | 
						std::shared_ptr<Camera> camera;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FrameBufferAllocator *allocator;
 | 
				
			||||||
 | 
						std::vector<std::unique_ptr<libcamera::Request>> requestPool;
 | 
				
			||||||
 | 
						std::deque<libcamera::Request *> pendingRequests;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void requestComplete(libcamera::Request *request);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int have_config;
 | 
						unsigned int have_config;
 | 
				
			||||||
	std::unique_ptr<CameraConfiguration> config;
 | 
						std::unique_ptr<CameraConfiguration> config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct spa_source source;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int active:1;
 | 
						unsigned int active:1;
 | 
				
			||||||
	unsigned int acquired:1;
 | 
						unsigned int acquired:1;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct impl Impl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CHECK_PORT(impl,direction,port_id)  ((direction) == SPA_DIRECTION_OUTPUT && (port_id) == 0)
 | 
					#define CHECK_PORT(impl,direction,port_id)  ((direction) == SPA_DIRECTION_OUTPUT && (port_id) == 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define GET_OUT_PORT(impl,p)         (&impl->out_ports[p])
 | 
					#define GET_OUT_PORT(impl,p)         (&impl->out_ports[p])
 | 
				
			||||||
| 
						 | 
					@ -409,15 +424,12 @@ static int impl_node_remove_port(void *object,
 | 
				
			||||||
	return -ENOTSUP;
 | 
						return -ENOTSUP;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int port_get_format(void *object,
 | 
					static int port_get_format(struct impl *impl, struct port *port,
 | 
				
			||||||
			   enum spa_direction direction, uint32_t port_id,
 | 
					 | 
				
			||||||
			   uint32_t index,
 | 
								   uint32_t index,
 | 
				
			||||||
			   const struct spa_pod *filter,
 | 
								   const struct spa_pod *filter,
 | 
				
			||||||
			   struct spa_pod **param,
 | 
								   struct spa_pod **param,
 | 
				
			||||||
			   struct spa_pod_builder *builder)
 | 
								   struct spa_pod_builder *builder)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct impl *impl = (struct impl*)object;
 | 
					 | 
				
			||||||
	struct port *port = GET_PORT(impl, direction, port_id);
 | 
					 | 
				
			||||||
	struct spa_pod_frame f;
 | 
						struct spa_pod_frame f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!port->have_format)
 | 
						if (!port->have_format)
 | 
				
			||||||
| 
						 | 
					@ -492,14 +504,13 @@ next:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (id) {
 | 
						switch (id) {
 | 
				
			||||||
	case SPA_PARAM_PropInfo:
 | 
						case SPA_PARAM_PropInfo:
 | 
				
			||||||
		return spa_libcamera_enum_controls(impl, seq, start, num, filter);
 | 
							return spa_libcamera_enum_controls(impl, port, seq, start, num, filter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case SPA_PARAM_EnumFormat:
 | 
						case SPA_PARAM_EnumFormat:
 | 
				
			||||||
		return spa_libcamera_enum_format(impl, seq, start, num, filter);
 | 
							return spa_libcamera_enum_format(impl, port, seq, start, num, filter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case SPA_PARAM_Format:
 | 
						case SPA_PARAM_Format:
 | 
				
			||||||
		if((res = port_get_format(impl, direction, port_id,
 | 
							if((res = port_get_format(impl, port, result.index, filter, ¶m, &b)) <= 0)
 | 
				
			||||||
						result.index, filter, ¶m, &b)) <= 0)
 | 
					 | 
				
			||||||
			return res;
 | 
								return res;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case SPA_PARAM_Buffers:
 | 
						case SPA_PARAM_Buffers:
 | 
				
			||||||
| 
						 | 
					@ -512,15 +523,14 @@ next:
 | 
				
			||||||
		/* Get the number of buffers to be used from libcamera and send the same to pipewire
 | 
							/* Get the number of buffers to be used from libcamera and send the same to pipewire
 | 
				
			||||||
		 * so that exact number of buffers are allocated
 | 
							 * so that exact number of buffers are allocated
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
//		uint32_t n_buffers = libcamera_get_nbuffers(port->dev.camera);
 | 
							uint32_t n_buffers = port->streamConfig.bufferCount;
 | 
				
			||||||
		uint32_t n_buffers = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		param = (struct spa_pod*)spa_pod_builder_add_object(&b,
 | 
							param = (struct spa_pod*)spa_pod_builder_add_object(&b,
 | 
				
			||||||
			SPA_TYPE_OBJECT_ParamBuffers, id,
 | 
								SPA_TYPE_OBJECT_ParamBuffers, id,
 | 
				
			||||||
			SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(n_buffers, n_buffers, n_buffers),
 | 
								SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(n_buffers, n_buffers, n_buffers),
 | 
				
			||||||
			SPA_PARAM_BUFFERS_blocks,  SPA_POD_Int(1),
 | 
								SPA_PARAM_BUFFERS_blocks,  SPA_POD_Int(1),
 | 
				
			||||||
			SPA_PARAM_BUFFERS_size,    SPA_POD_Int(0),
 | 
								SPA_PARAM_BUFFERS_size,    SPA_POD_Int(port->streamConfig.frameSize),
 | 
				
			||||||
			SPA_PARAM_BUFFERS_stride,  SPA_POD_Int(0),
 | 
								SPA_PARAM_BUFFERS_stride,  SPA_POD_Int(port->streamConfig.stride),
 | 
				
			||||||
			SPA_PARAM_BUFFERS_align,   SPA_POD_Int(16));
 | 
								SPA_PARAM_BUFFERS_align,   SPA_POD_Int(16));
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -575,14 +585,10 @@ next:
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int port_set_format(void *object,
 | 
					static int port_set_format(struct impl *impl, struct port *port,
 | 
				
			||||||
			   enum spa_direction direction, uint32_t port_id,
 | 
								   uint32_t flags, const struct spa_pod *format)
 | 
				
			||||||
			   uint32_t flags,
 | 
					 | 
				
			||||||
			   const struct spa_pod *format)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct impl *impl = (struct impl*)object;
 | 
					 | 
				
			||||||
	struct spa_video_info info;
 | 
						struct spa_video_info info;
 | 
				
			||||||
	struct port *port = GET_PORT(impl, direction, port_id);
 | 
					 | 
				
			||||||
	int res;
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (format == NULL) {
 | 
						if (format == NULL) {
 | 
				
			||||||
| 
						 | 
					@ -590,7 +596,7 @@ static int port_set_format(void *object,
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		spa_libcamera_stream_off(impl);
 | 
							spa_libcamera_stream_off(impl);
 | 
				
			||||||
		spa_libcamera_clear_buffers(impl);
 | 
							spa_libcamera_clear_buffers(impl, port);
 | 
				
			||||||
		port->have_format = false;
 | 
							port->have_format = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		spa_libcamera_close(impl);
 | 
							spa_libcamera_close(impl);
 | 
				
			||||||
| 
						 | 
					@ -644,11 +650,11 @@ static int port_set_format(void *object,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (port->have_format && !(flags & SPA_NODE_PARAM_FLAG_TEST_ONLY)) {
 | 
						if (port->have_format && !(flags & SPA_NODE_PARAM_FLAG_TEST_ONLY)) {
 | 
				
			||||||
		spa_libcamera_use_buffers(impl, NULL, 0);
 | 
							spa_libcamera_use_buffers(impl, port, NULL, 0);
 | 
				
			||||||
		port->have_format = false;
 | 
							port->have_format = false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (spa_libcamera_set_format(impl, &info, flags & SPA_NODE_PARAM_FLAG_TEST_ONLY) < 0)
 | 
						if (spa_libcamera_set_format(impl, port, &info, flags & SPA_NODE_PARAM_FLAG_TEST_ONLY) < 0)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!(flags & SPA_NODE_PARAM_FLAG_TEST_ONLY)) {
 | 
						if (!(flags & SPA_NODE_PARAM_FLAG_TEST_ONLY)) {
 | 
				
			||||||
| 
						 | 
					@ -675,15 +681,23 @@ static int impl_node_port_set_param(void *object,
 | 
				
			||||||
				    uint32_t id, uint32_t flags,
 | 
									    uint32_t id, uint32_t flags,
 | 
				
			||||||
				    const struct spa_pod *param)
 | 
									    const struct spa_pod *param)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct impl *impl = (struct impl*)object;
 | 
				
			||||||
 | 
						struct port *port;
 | 
				
			||||||
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_return_val_if_fail(object != NULL, -EINVAL);
 | 
						spa_return_val_if_fail(object != NULL, -EINVAL);
 | 
				
			||||||
 | 
						spa_return_val_if_fail(CHECK_PORT(impl, direction, port_id), -EINVAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_return_val_if_fail(CHECK_PORT(object, direction, port_id), -EINVAL);
 | 
						port = GET_PORT(impl, direction, port_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (id == SPA_PARAM_Format) {
 | 
						switch (id) {
 | 
				
			||||||
		return port_set_format(object, direction, port_id, flags, param);
 | 
						case SPA_PARAM_Format:
 | 
				
			||||||
 | 
							res = port_set_format(impl, port, flags, param);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							res = -ENOENT;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else
 | 
						return res;
 | 
				
			||||||
		return -ENOENT;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int impl_node_port_use_buffers(void *object,
 | 
					static int impl_node_port_use_buffers(void *object,
 | 
				
			||||||
| 
						 | 
					@ -707,16 +721,16 @@ static int impl_node_port_use_buffers(void *object,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (port->n_buffers) {
 | 
						if (port->n_buffers) {
 | 
				
			||||||
		spa_libcamera_stream_off(impl);
 | 
							spa_libcamera_stream_off(impl);
 | 
				
			||||||
		if ((res = spa_libcamera_clear_buffers(impl)) < 0)
 | 
							if ((res = spa_libcamera_clear_buffers(impl, port)) < 0)
 | 
				
			||||||
			return res;
 | 
								return res;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (buffers == NULL)
 | 
						if (buffers == NULL)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (flags & SPA_NODE_BUFFERS_FLAG_ALLOC) {
 | 
						if (flags & SPA_NODE_BUFFERS_FLAG_ALLOC) {
 | 
				
			||||||
		res = spa_libcamera_alloc_buffers(impl, buffers, n_buffers);
 | 
							res = spa_libcamera_alloc_buffers(impl, port, buffers, n_buffers);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		res = spa_libcamera_use_buffers(impl, buffers, n_buffers);
 | 
							res = spa_libcamera_use_buffers(impl, port, buffers, n_buffers);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return res;
 | 
						return res;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -763,16 +777,14 @@ static int impl_node_port_reuse_buffer(void *object,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_return_val_if_fail(buffer_id < port->n_buffers, -EINVAL);
 | 
						spa_return_val_if_fail(buffer_id < port->n_buffers, -EINVAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	res = spa_libcamera_buffer_recycle(impl, buffer_id);
 | 
						res = spa_libcamera_buffer_recycle(impl, port, buffer_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return res;
 | 
						return res;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void set_control(struct impl *impl, struct port *port, uint32_t control_id, float value)
 | 
					static void set_control(struct impl *impl, struct port *port, uint32_t control_id, float value)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
//	if(libcamera_set_control(port->dev.camera, control_id, value) < 0) {
 | 
					 | 
				
			||||||
	spa_log_error(impl->log, "Failed to set control");
 | 
						spa_log_error(impl->log, "Failed to set control");
 | 
				
			||||||
//	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int process_control(struct impl *impl, struct spa_pod_sequence *control)
 | 
					static int process_control(struct impl *impl, struct spa_pod_sequence *control)
 | 
				
			||||||
| 
						 | 
					@ -825,7 +837,7 @@ static int impl_node_process(void *object)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (io->buffer_id < port->n_buffers) {
 | 
						if (io->buffer_id < port->n_buffers) {
 | 
				
			||||||
		if ((res = spa_libcamera_buffer_recycle(impl, io->buffer_id)) < 0)
 | 
							if ((res = spa_libcamera_buffer_recycle(impl, port, io->buffer_id)) < 0)
 | 
				
			||||||
			return res;
 | 
								return res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		io->buffer_id = SPA_ID_INVALID;
 | 
							io->buffer_id = SPA_ID_INVALID;
 | 
				
			||||||
| 
						 | 
					@ -886,15 +898,9 @@ static int impl_get_interface(struct spa_handle *handle, const char *type, void
 | 
				
			||||||
static int impl_clear(struct spa_handle *handle)
 | 
					static int impl_clear(struct spa_handle *handle)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct impl *impl;
 | 
						struct impl *impl;
 | 
				
			||||||
	struct port *port;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	impl = (struct impl *) handle;
 | 
						impl = (struct impl *) handle;
 | 
				
			||||||
	port = GET_OUT_PORT(impl, 0);
 | 
						impl->~Impl();
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if(impl->have_source) {
 | 
					 | 
				
			||||||
		spa_system_close(impl->system, port->source.fd);
 | 
					 | 
				
			||||||
		impl->have_source = false;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -920,11 +926,11 @@ impl_init(const struct spa_handle_factory *factory,
 | 
				
			||||||
	spa_return_val_if_fail(factory != NULL, -EINVAL);
 | 
						spa_return_val_if_fail(factory != NULL, -EINVAL);
 | 
				
			||||||
	spa_return_val_if_fail(handle != NULL, -EINVAL);
 | 
						spa_return_val_if_fail(handle != NULL, -EINVAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						impl = new(handle) Impl();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	handle->get_interface = impl_get_interface;
 | 
						handle->get_interface = impl_get_interface;
 | 
				
			||||||
	handle->clear = impl_clear;
 | 
						handle->clear = impl_clear;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	impl = (struct impl *) handle;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	impl->log = (struct spa_log*)spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
 | 
						impl->log = (struct spa_log*)spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
 | 
				
			||||||
	libcamera_log_topic_init(impl->log);
 | 
						libcamera_log_topic_init(impl->log);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,6 +40,9 @@ int spa_libcamera_open(struct impl *impl)
 | 
				
			||||||
	if (impl->acquired)
 | 
						if (impl->acquired)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	impl->camera->acquire();
 | 
						impl->camera->acquire();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						impl->allocator = new FrameBufferAllocator(impl->camera);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	impl->acquired = true;
 | 
						impl->acquired = true;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -51,7 +54,12 @@ int spa_libcamera_close(struct impl *impl)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	if (impl->active || port->have_format)
 | 
						if (impl->active || port->have_format)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						delete impl->allocator;
 | 
				
			||||||
 | 
						impl->allocator = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	impl->camera->release();
 | 
						impl->camera->release();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	impl->acquired = false;
 | 
						impl->acquired = false;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -67,21 +75,69 @@ static void spa_libcamera_get_config(struct impl *impl)
 | 
				
			||||||
	impl->have_config = true;
 | 
						impl->have_config = true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int spa_libcamera_buffer_recycle(struct impl *impl, uint32_t buffer_id)
 | 
					static int spa_libcamera_buffer_recycle(struct impl *impl, struct port *port, uint32_t buffer_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct port *port = &impl->out_ports[0];
 | 
					 | 
				
			||||||
	struct buffer *b = &port->buffers[buffer_id];
 | 
						struct buffer *b = &port->buffers[buffer_id];
 | 
				
			||||||
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_OUTSTANDING))
 | 
						if (!SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_OUTSTANDING))
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_OUTSTANDING);
 | 
						SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_OUTSTANDING);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (buffer_id >= impl->requestPool.size()) {
 | 
				
			||||||
 | 
							spa_log_warn(impl->log, "invalid buffer_id %u >= %zu",
 | 
				
			||||||
 | 
									buffer_id, impl->requestPool.size());
 | 
				
			||||||
 | 
					                return -EINVAL;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
						Request *request = impl->requestPool[buffer_id].get();
 | 
				
			||||||
 | 
					        Stream *stream = port->streamConfig.stream();
 | 
				
			||||||
 | 
						FrameBuffer *buffer = impl->allocator->buffers(stream)[buffer_id].get();
 | 
				
			||||||
 | 
						if ((res = request->addBuffer(stream, buffer)) < 0) {
 | 
				
			||||||
 | 
							spa_log_warn(impl->log, "can't add buffer %u for request: %s",
 | 
				
			||||||
 | 
									buffer_id, spa_strerror(res));
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!impl->active) {
 | 
				
			||||||
 | 
							impl->pendingRequests.push_back(request);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
							if ((res = impl->camera->queueRequest(request)) < 0) {
 | 
				
			||||||
 | 
								spa_log_warn(impl->log, "can't queue buffer %u: %s",
 | 
				
			||||||
 | 
									buffer_id, spa_strerror(res));
 | 
				
			||||||
 | 
								return res == -EACCES ? -EBUSY : res;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int spa_libcamera_clear_buffers(struct impl *impl)
 | 
					static int allocBuffers(struct impl *impl, struct port *port, unsigned int count)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((res = impl->allocator->allocate(port->streamConfig.stream())) < 0)
 | 
				
			||||||
 | 
					                return res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (unsigned int i = 0; i < count; i++) {
 | 
				
			||||||
 | 
							std::unique_ptr<Request> request = impl->camera->createRequest(i);
 | 
				
			||||||
 | 
							if (!request) {
 | 
				
			||||||
 | 
								impl->requestPool.clear();
 | 
				
			||||||
 | 
								return -ENOMEM;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							impl->requestPool.push_back(std::move(request));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					        return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void freeBuffers(struct impl *impl, struct port *port)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						impl->pendingRequests.clear();
 | 
				
			||||||
 | 
						impl->requestPool.clear();
 | 
				
			||||||
 | 
						impl->allocator->free(port->streamConfig.stream());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int spa_libcamera_clear_buffers(struct impl *impl, struct port *port)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct port *port = &impl->out_ports[0];
 | 
					 | 
				
			||||||
	uint32_t i;
 | 
						uint32_t i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (port->n_buffers == 0)
 | 
						if (port->n_buffers == 0)
 | 
				
			||||||
| 
						 | 
					@ -96,7 +152,7 @@ static int spa_libcamera_clear_buffers(struct impl *impl)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_OUTSTANDING)) {
 | 
							if (SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_OUTSTANDING)) {
 | 
				
			||||||
			spa_log_debug(impl->log, "queueing outstanding buffer %p", b);
 | 
								spa_log_debug(impl->log, "queueing outstanding buffer %p", b);
 | 
				
			||||||
			spa_libcamera_buffer_recycle(impl, i);
 | 
								spa_libcamera_buffer_recycle(impl, port, i);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_MAPPED)) {
 | 
							if (SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_MAPPED)) {
 | 
				
			||||||
			munmap(SPA_PTROFF(b->ptr, -d[0].mapoffset, void),
 | 
								munmap(SPA_PTROFF(b->ptr, -d[0].mapoffset, void),
 | 
				
			||||||
| 
						 | 
					@ -108,6 +164,7 @@ static int spa_libcamera_clear_buffers(struct impl *impl)
 | 
				
			||||||
		d[0].type = SPA_ID_INVALID;
 | 
							d[0].type = SPA_ID_INVALID;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						freeBuffers(impl, port);
 | 
				
			||||||
	port->n_buffers = 0;
 | 
						port->n_buffers = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					@ -166,9 +223,7 @@ static const struct format_info *video_format_to_info(const PixelFormat &pix) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct format_info *find_format_info_by_media_type(uint32_t type,
 | 
					static const struct format_info *find_format_info_by_media_type(uint32_t type,
 | 
				
			||||||
								uint32_t subtype,
 | 
							uint32_t subtype, uint32_t format, int startidx)
 | 
				
			||||||
								uint32_t format,
 | 
					 | 
				
			||||||
								int startidx)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	size_t i;
 | 
						size_t i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -182,11 +237,9 @@ static const struct format_info *find_format_info_by_media_type(uint32_t type,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
spa_libcamera_enum_format(struct impl *impl, int seq,
 | 
					spa_libcamera_enum_format(struct impl *impl, struct port *port, int seq,
 | 
				
			||||||
		     uint32_t start, uint32_t num,
 | 
							     uint32_t start, uint32_t num, const struct spa_pod *filter)
 | 
				
			||||||
		     const struct spa_pod *filter)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct port *port = &impl->out_ports[0];
 | 
					 | 
				
			||||||
	int res;
 | 
						int res;
 | 
				
			||||||
	const struct format_info *info;
 | 
						const struct format_info *info;
 | 
				
			||||||
	uint8_t buffer[1024];
 | 
						uint8_t buffer[1024];
 | 
				
			||||||
| 
						 | 
					@ -298,13 +351,14 @@ next_fmt:
 | 
				
			||||||
	return res;
 | 
						return res;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int spa_libcamera_set_format(struct impl *impl, struct spa_video_info *format, bool try_only)
 | 
					static int spa_libcamera_set_format(struct impl *impl, struct port *port,
 | 
				
			||||||
 | 
							struct spa_video_info *format, bool try_only)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct port *port = &impl->out_ports[0];
 | 
					 | 
				
			||||||
	const struct format_info *info = NULL;
 | 
						const struct format_info *info = NULL;
 | 
				
			||||||
	uint32_t video_format;
 | 
						uint32_t video_format;
 | 
				
			||||||
	struct spa_rectangle *size = NULL;
 | 
						struct spa_rectangle *size = NULL;
 | 
				
			||||||
	struct spa_fraction *framerate = NULL;
 | 
						struct spa_fraction *framerate = NULL;
 | 
				
			||||||
 | 
						CameraConfiguration::Status validation;
 | 
				
			||||||
	int res;
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (format->media_subtype) {
 | 
						switch (format->media_subtype) {
 | 
				
			||||||
| 
						 | 
					@ -341,10 +395,15 @@ static int spa_libcamera_set_format(struct impl *impl, struct spa_video_info *fo
 | 
				
			||||||
	streamConfig.pixelFormat = info->pix;
 | 
						streamConfig.pixelFormat = info->pix;
 | 
				
			||||||
	streamConfig.size.width = size->width;
 | 
						streamConfig.size.width = size->width;
 | 
				
			||||||
	streamConfig.size.height = size->height;
 | 
						streamConfig.size.height = size->height;
 | 
				
			||||||
 | 
						streamConfig.bufferCount = 8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (impl->config->validate() == CameraConfiguration::Invalid)
 | 
						validation = impl->config->validate();
 | 
				
			||||||
 | 
						if (validation == CameraConfiguration::Invalid)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (try_only)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((res = spa_libcamera_open(impl)) < 0)
 | 
						if ((res = spa_libcamera_open(impl)) < 0)
 | 
				
			||||||
		return res;
 | 
							return res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -352,6 +411,11 @@ static int spa_libcamera_set_format(struct impl *impl, struct spa_video_info *fo
 | 
				
			||||||
	if (res != 0)
 | 
						if (res != 0)
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						port->streamConfig = impl->config->at(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((res = allocBuffers(impl, port, port->streamConfig.bufferCount)) < 0)
 | 
				
			||||||
 | 
							return res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	port->have_format = true;
 | 
						port->have_format = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS | SPA_PORT_CHANGE_MASK_RATE;
 | 
						port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS | SPA_PORT_CHANGE_MASK_RATE;
 | 
				
			||||||
| 
						 | 
					@ -369,127 +433,26 @@ error:
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
spa_libcamera_enum_controls(struct impl *impl, int seq,
 | 
					spa_libcamera_enum_controls(struct impl *impl, struct port *port, int seq,
 | 
				
			||||||
		       uint32_t start, uint32_t num,
 | 
							       uint32_t start, uint32_t num,
 | 
				
			||||||
		       const struct spa_pod *filter)
 | 
							       const struct spa_pod *filter)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return -ENOTSUP;
 | 
						return -ENOTSUP;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int mmap_read(struct impl *impl)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
#if 0
 | 
					 | 
				
			||||||
	struct port *port = &impl->out_ports[0];
 | 
					 | 
				
			||||||
	struct buffer *b = NULL;
 | 
					 | 
				
			||||||
	struct spa_data *d = NULL;
 | 
					 | 
				
			||||||
	unsigned int sequence = 0;
 | 
					 | 
				
			||||||
	struct timeval timestamp;
 | 
					 | 
				
			||||||
	int64_t pts;
 | 
					 | 
				
			||||||
	struct OutBuf *pOut = NULL;
 | 
					 | 
				
			||||||
	struct CamData *pDatas = NULL;
 | 
					 | 
				
			||||||
	uint32_t bytesused = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	timestamp.tv_sec = 0;
 | 
					 | 
				
			||||||
	timestamp.tv_usec = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (impl->camera) {
 | 
					 | 
				
			||||||
//		pOut = (struct OutBuf *)libcamera_get_ring_buffer_data(dev->camera);
 | 
					 | 
				
			||||||
		if(!pOut) {
 | 
					 | 
				
			||||||
			spa_log_debug(impl->log, "Exiting %s as pOut is NULL", __FUNCTION__);
 | 
					 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		/* update the read index of the ring buffer */
 | 
					 | 
				
			||||||
//		libcamera_ringbuffer_read_update(dev->camera);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		pDatas = pOut->datas;
 | 
					 | 
				
			||||||
		if(NULL == pDatas) {
 | 
					 | 
				
			||||||
			spa_log_debug(impl->log, "Exiting %s on NULL pointer", __FUNCTION__);
 | 
					 | 
				
			||||||
			goto end;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		b = &port->buffers[pOut->bufIdx];
 | 
					 | 
				
			||||||
		b->outbuf->n_datas = pOut->n_datas;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if(NULL == b->outbuf->datas) {
 | 
					 | 
				
			||||||
			spa_log_debug(impl->log, "Exiting %s as b->outbuf->datas is NULL", __FUNCTION__);
 | 
					 | 
				
			||||||
			goto end;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for(unsigned int i = 0;  i < pOut->n_datas; ++i) {
 | 
					 | 
				
			||||||
			struct CamData *pData = &pDatas[i];
 | 
					 | 
				
			||||||
			if(NULL == pData) {
 | 
					 | 
				
			||||||
				spa_log_debug(impl->log, "Exiting %s on NULL pointer", __FUNCTION__);
 | 
					 | 
				
			||||||
				goto end;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			b->outbuf->datas[i].flags = SPA_DATA_FLAG_READABLE;
 | 
					 | 
				
			||||||
			if(port->memtype == SPA_DATA_DmaBuf) {
 | 
					 | 
				
			||||||
				b->outbuf->datas[i].fd = pData->fd;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			bytesused = b->outbuf->datas[i].chunk->size = pData->size;
 | 
					 | 
				
			||||||
			timestamp = pData->timestamp;
 | 
					 | 
				
			||||||
			sequence = pData->sequence;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			b->outbuf->datas[i].mapoffset = 0;
 | 
					 | 
				
			||||||
			b->outbuf->datas[i].chunk->offset = 0;
 | 
					 | 
				
			||||||
			b->outbuf->datas[i].chunk->flags = 0;
 | 
					 | 
				
			||||||
			//b->outbuf->datas[i].chunk->stride = pData->sstride; /* FIXME:: This needs to be appropriately filled */
 | 
					 | 
				
			||||||
			b->outbuf->datas[i].maxsize = pData->maxsize;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			spa_log_trace(impl->log,"Spa libcamera Source::%s:: got bufIdx = %d and ndatas = %d",
 | 
					 | 
				
			||||||
				__FUNCTION__, pOut->bufIdx, pOut->n_datas);
 | 
					 | 
				
			||||||
			spa_log_trace(impl->log," data[%d] --> fd = %ld bytesused = %d sequence = %d",
 | 
					 | 
				
			||||||
				i, b->outbuf->datas[i].fd, bytesused, sequence);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pts = SPA_TIMEVAL_TO_NSEC(×tamp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (impl->clock) {
 | 
					 | 
				
			||||||
		impl->clock->nsec = pts;
 | 
					 | 
				
			||||||
		impl->clock->rate = port->rate;
 | 
					 | 
				
			||||||
		impl->clock->position = sequence;
 | 
					 | 
				
			||||||
		impl->clock->duration = 1;
 | 
					 | 
				
			||||||
		impl->clock->delay = 0;
 | 
					 | 
				
			||||||
		impl->clock->rate_diff = 1.0;
 | 
					 | 
				
			||||||
		impl->clock->next_nsec = pts + 1000000000LL / port->rate.denom;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (b->h) {
 | 
					 | 
				
			||||||
		b->h->flags = 0;
 | 
					 | 
				
			||||||
		b->h->offset = 0;
 | 
					 | 
				
			||||||
		b->h->seq = sequence;
 | 
					 | 
				
			||||||
		b->h->pts = pts;
 | 
					 | 
				
			||||||
		b->h->dts_offset = 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	d = b->outbuf->datas;
 | 
					 | 
				
			||||||
	d[0].chunk->offset = 0;
 | 
					 | 
				
			||||||
	d[0].chunk->size = bytesused;
 | 
					 | 
				
			||||||
	d[0].chunk->flags = 0;
 | 
					 | 
				
			||||||
	d[0].data = b->ptr;
 | 
					 | 
				
			||||||
	spa_log_trace(impl->log,"%s:: b->ptr = %p d[0].data = %p",
 | 
					 | 
				
			||||||
				__FUNCTION__, b->ptr, d[0].data);
 | 
					 | 
				
			||||||
	spa_list_append(&port->queue, &b->link);
 | 
					 | 
				
			||||||
end:
 | 
					 | 
				
			||||||
//	libcamera_free_CamData(dev->camera, pDatas);
 | 
					 | 
				
			||||||
//	libcamera_free_OutBuf(dev->camera, pOut);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void libcamera_on_fd_events(struct spa_source *source)
 | 
					static void libcamera_on_fd_events(struct spa_source *source)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct impl *impl = (struct impl*) source->data;
 | 
						struct impl *impl = (struct impl*) source->data;
 | 
				
			||||||
	struct spa_io_buffers *io;
 | 
						struct spa_io_buffers *io;
 | 
				
			||||||
	struct port *port = &impl->out_ports[0];
 | 
						struct port *port = &impl->out_ports[0];
 | 
				
			||||||
 | 
						uint32_t index, buffer_id;
 | 
				
			||||||
	struct buffer *b;
 | 
						struct buffer *b;
 | 
				
			||||||
	uint64_t cnt;
 | 
						uint64_t cnt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (source->rmask & SPA_IO_ERR) {
 | 
						if (source->rmask & SPA_IO_ERR) {
 | 
				
			||||||
		struct port *port = &impl->out_ports[0];
 | 
					 | 
				
			||||||
		spa_log_error(impl->log, "libcamera %p: error %08x", impl, source->rmask);
 | 
							spa_log_error(impl->log, "libcamera %p: error %08x", impl, source->rmask);
 | 
				
			||||||
		if (port->source.loop)
 | 
							if (impl->source.loop)
 | 
				
			||||||
			spa_loop_remove_source(impl->data_loop, &port->source);
 | 
								spa_loop_remove_source(impl->data_loop, &impl->source);
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -498,25 +461,25 @@ static void libcamera_on_fd_events(struct spa_source *source)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (spa_system_eventfd_read(impl->system, port->source.fd, &cnt) < 0) {
 | 
						if (spa_system_eventfd_read(impl->system, impl->source.fd, &cnt) < 0) {
 | 
				
			||||||
		spa_log_error(impl->log, "Failed to read on event fd");
 | 
							spa_log_error(impl->log, "Failed to read on event fd");
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mmap_read(impl) < 0) {
 | 
						if (spa_ringbuffer_get_read_index(&port->ring, &index) < 1) {
 | 
				
			||||||
		spa_log_debug(impl->log, "%s:: mmap_read failure", __FUNCTION__);
 | 
							spa_log_error(impl->log, "nothing is queued");
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						buffer_id = port->ring_ids[index & MASK_BUFFERS];
 | 
				
			||||||
 | 
						spa_ringbuffer_read_update(&port->ring, index + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (spa_list_is_empty(&port->queue)) {
 | 
						b = &port->buffers[buffer_id];
 | 
				
			||||||
		spa_log_debug(impl->log, "Exiting %s as spa list is empty", __FUNCTION__);
 | 
						spa_list_append(&port->queue, &b->link);
 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	io = port->io;
 | 
						io = port->io;
 | 
				
			||||||
	if (io != NULL && io->status != SPA_STATUS_HAVE_DATA) {
 | 
						if (io != NULL && io->status != SPA_STATUS_HAVE_DATA) {
 | 
				
			||||||
		if (io->buffer_id < port->n_buffers)
 | 
							if (io->buffer_id < port->n_buffers)
 | 
				
			||||||
			spa_libcamera_buffer_recycle(impl, io->buffer_id);
 | 
								spa_libcamera_buffer_recycle(impl, port, io->buffer_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		b = spa_list_first(&port->queue, struct buffer, link);
 | 
							b = spa_list_first(&port->queue, struct buffer, link);
 | 
				
			||||||
		spa_list_remove(&b->link);
 | 
							spa_list_remove(&b->link);
 | 
				
			||||||
| 
						 | 
					@ -529,103 +492,28 @@ static void libcamera_on_fd_events(struct spa_source *source)
 | 
				
			||||||
	spa_node_call_ready(&impl->callbacks, SPA_STATUS_HAVE_DATA);
 | 
						spa_node_call_ready(&impl->callbacks, SPA_STATUS_HAVE_DATA);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int spa_libcamera_use_buffers(struct impl *impl, struct spa_buffer **buffers, uint32_t n_buffers)
 | 
					static int spa_libcamera_use_buffers(struct impl *impl, struct port *port,
 | 
				
			||||||
 | 
							struct spa_buffer **buffers, uint32_t n_buffers)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#if 0
 | 
						return -ENOTSUP;
 | 
				
			||||||
	struct port *port = &impl->out_ports[0];
 | 
					 | 
				
			||||||
	unsigned int i, j;
 | 
					 | 
				
			||||||
	struct spa_data *d;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	n_buffers = libcamera_get_nbuffers(port->dev.camera);
 | 
					 | 
				
			||||||
	if (n_buffers > 0) {
 | 
					 | 
				
			||||||
		d = buffers[0]->datas;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (d[0].type == SPA_DATA_MemFd ||
 | 
					 | 
				
			||||||
		    (d[0].type == SPA_DATA_MemPtr && d[0].data != NULL)) {
 | 
					 | 
				
			||||||
			port->memtype = SPA_DATA_MemPtr;
 | 
					 | 
				
			||||||
		} else if (d[0].type == SPA_DATA_DmaBuf) {
 | 
					 | 
				
			||||||
			port->memtype = SPA_DATA_DmaBuf;
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			spa_log_error(impl->log, "v4l2: can't use buffers of type %d", d[0].type);
 | 
					 | 
				
			||||||
			return -EINVAL;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (i = 0; i < n_buffers; i++) {
 | 
					 | 
				
			||||||
		struct buffer *b;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		b = &port->buffers[i];
 | 
					 | 
				
			||||||
		b->id = i;
 | 
					 | 
				
			||||||
		b->outbuf = buffers[i];
 | 
					 | 
				
			||||||
		b->flags = BUFFER_FLAG_OUTSTANDING;
 | 
					 | 
				
			||||||
		b->h = spa_buffer_find_meta_data(buffers[i], SPA_META_Header, sizeof(*b->h));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		spa_log_debug(impl->log, "import buffer %p", buffers[i]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (buffers[i]->n_datas < 1) {
 | 
					 | 
				
			||||||
			spa_log_error(impl->log, "invalid memory on buffer %p", buffers[i]);
 | 
					 | 
				
			||||||
			return -EINVAL;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		d = buffers[i]->datas;
 | 
					 | 
				
			||||||
		for(j = 0; j < buffers[i]->n_datas; ++j) {
 | 
					 | 
				
			||||||
			d[j].mapoffset = 0;
 | 
					 | 
				
			||||||
			d[j].maxsize = libcamera_get_max_size(port->dev.camera);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (port->memtype == SPA_DATA_MemPtr) {
 | 
					 | 
				
			||||||
				if (d[j].data == NULL) {
 | 
					 | 
				
			||||||
					d[j].fd = -1;
 | 
					 | 
				
			||||||
					d[j].data = mmap(NULL,
 | 
					 | 
				
			||||||
						    d[j].maxsize + d[j].mapoffset,
 | 
					 | 
				
			||||||
						    PROT_READ, MAP_SHARED,
 | 
					 | 
				
			||||||
						    libcamera_get_fd(port->dev.camera, i, j),
 | 
					 | 
				
			||||||
						    0);
 | 
					 | 
				
			||||||
					if (d[j].data == MAP_FAILED) {
 | 
					 | 
				
			||||||
						return -errno;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					b->ptr = d[j].data;
 | 
					 | 
				
			||||||
					spa_log_debug(impl->log, "In spa_libcamera_use_buffers(). mmap ptr:%p for fd = %ld buffer: #%d",
 | 
					 | 
				
			||||||
						d[j].data, d[j].fd, i);
 | 
					 | 
				
			||||||
					SPA_FLAG_SET(b->flags, BUFFER_FLAG_MAPPED);
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					b->ptr = d[j].data;
 | 
					 | 
				
			||||||
					spa_log_debug(impl->log, "In spa_libcamera_use_buffers(). b->ptr = %p d[j].maxsize = %d for buffer: #%d",
 | 
					 | 
				
			||||||
						d[j].data, d[j].maxsize, i);
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				spa_log_debug(impl->log, "In spa_libcamera_use_buffers(). setting b->ptr = %p for buffer: #%d on libcamera",
 | 
					 | 
				
			||||||
						b->ptr, i);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			else if (port->memtype == SPA_DATA_DmaBuf) {
 | 
					 | 
				
			||||||
				d[j].fd = libcamera_get_fd(port->dev.camera, i, j);
 | 
					 | 
				
			||||||
				spa_log_debug(impl->log, "Got fd = %ld for buffer: #%d", d[j].fd, i);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			else {
 | 
					 | 
				
			||||||
				spa_log_error(impl->log, "Exiting spa_libcamera_use_buffers() with -EIO");
 | 
					 | 
				
			||||||
				return -EIO;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		spa_libcamera_buffer_recycle(impl, i);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	port->n_buffers = n_buffers;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
mmap_init(struct impl *impl,
 | 
					mmap_init(struct impl *impl, struct port *port,
 | 
				
			||||||
		struct spa_buffer **buffers, uint32_t n_buffers)
 | 
							struct spa_buffer **buffers, uint32_t n_buffers)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#if 0
 | 
					 | 
				
			||||||
	struct port *port = &impl->out_ports[0];
 | 
					 | 
				
			||||||
	unsigned int i, j;
 | 
						unsigned int i, j;
 | 
				
			||||||
	struct spa_data *d;
 | 
						struct spa_data *d;
 | 
				
			||||||
 | 
						Stream *stream = impl->config->at(0).stream();
 | 
				
			||||||
 | 
						const std::vector<std::unique_ptr<FrameBuffer>> &bufs =
 | 
				
			||||||
 | 
								impl->allocator->buffers(stream);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_log_info(impl->log, "In mmap_init()");
 | 
						spa_log_info(impl->log, "In mmap_init()");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (n_buffers > 0) {
 | 
						if (n_buffers > 0) {
 | 
				
			||||||
 | 
							if (bufs.size() != n_buffers)
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		d = buffers[0]->datas;
 | 
							d = buffers[0]->datas;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (d[0].type != SPA_ID_INVALID &&
 | 
							if (d[0].type != SPA_ID_INVALID &&
 | 
				
			||||||
| 
						 | 
					@ -642,10 +530,7 @@ mmap_init(struct impl *impl,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* get n_buffers from libcamera */
 | 
						for (i = 0; i < n_buffers; i++) {
 | 
				
			||||||
	uint32_t libcamera_nbuffers = libcamera_get_nbuffers(port->dev.camera);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (i = 0; i < libcamera_nbuffers; i++) {
 | 
					 | 
				
			||||||
		struct buffer *b;
 | 
							struct buffer *b;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (buffers[i]->n_datas < 1) {
 | 
							if (buffers[i]->n_datas < 1) {
 | 
				
			||||||
| 
						 | 
					@ -657,22 +542,22 @@ mmap_init(struct impl *impl,
 | 
				
			||||||
		b->id = i;
 | 
							b->id = i;
 | 
				
			||||||
		b->outbuf = buffers[i];
 | 
							b->outbuf = buffers[i];
 | 
				
			||||||
		b->flags = BUFFER_FLAG_OUTSTANDING;
 | 
							b->flags = BUFFER_FLAG_OUTSTANDING;
 | 
				
			||||||
		b->h = spa_buffer_find_meta_data(buffers[i], SPA_META_Header, sizeof(*b->h));
 | 
							b->h = (struct spa_meta_header*)spa_buffer_find_meta_data(buffers[i], SPA_META_Header, sizeof(*b->h));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		d = buffers[i]->datas;
 | 
							d = buffers[i]->datas;
 | 
				
			||||||
		for(j = 0; j < buffers[i]->n_datas; ++j) {
 | 
							for(j = 0; j < buffers[i]->n_datas; ++j) {
 | 
				
			||||||
			d[j].type = port->memtype;
 | 
								d[j].type = port->memtype;
 | 
				
			||||||
			d[j].flags = SPA_DATA_FLAG_READABLE;
 | 
								d[j].flags = SPA_DATA_FLAG_READABLE;
 | 
				
			||||||
			d[j].mapoffset = 0;
 | 
								d[j].mapoffset = 0;
 | 
				
			||||||
			d[j].maxsize = libcamera_get_max_size(port->dev.camera);
 | 
								d[j].maxsize = port->streamConfig.frameSize;
 | 
				
			||||||
			d[j].chunk->offset = 0;
 | 
								d[j].chunk->offset = 0;
 | 
				
			||||||
			d[j].chunk->size = 0;
 | 
								d[j].chunk->size = port->streamConfig.frameSize;
 | 
				
			||||||
			d[j].chunk->stride = port->fmt.bytesperline; /* FIXME:: This needs to be appropriately filled */
 | 
								d[j].chunk->stride = port->streamConfig.stride;
 | 
				
			||||||
			d[j].chunk->flags = 0;
 | 
								d[j].chunk->flags = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (port->memtype == SPA_DATA_DmaBuf ||
 | 
								if (port->memtype == SPA_DATA_DmaBuf ||
 | 
				
			||||||
			    port->memtype == SPA_DATA_MemFd) {
 | 
								    port->memtype == SPA_DATA_MemFd) {
 | 
				
			||||||
				d[j].fd = libcamera_get_fd(port->dev.camera, i, j);
 | 
									d[j].fd = bufs[i]->planes()[j].fd.fd();
 | 
				
			||||||
				spa_log_info(impl->log, "Got fd = %ld for buffer: #%d", d[j].fd, i);
 | 
									spa_log_info(impl->log, "Got fd = %ld for buffer: #%d", d[j].fd, i);
 | 
				
			||||||
				d[j].data = NULL;
 | 
									d[j].data = NULL;
 | 
				
			||||||
				SPA_FLAG_SET(b->flags, BUFFER_FLAG_ALLOCATED);
 | 
									SPA_FLAG_SET(b->flags, BUFFER_FLAG_ALLOCATED);
 | 
				
			||||||
| 
						 | 
					@ -682,7 +567,7 @@ mmap_init(struct impl *impl,
 | 
				
			||||||
				d[j].data = mmap(NULL,
 | 
									d[j].data = mmap(NULL,
 | 
				
			||||||
						d[j].maxsize + d[j].mapoffset,
 | 
											d[j].maxsize + d[j].mapoffset,
 | 
				
			||||||
						PROT_READ, MAP_SHARED,
 | 
											PROT_READ, MAP_SHARED,
 | 
				
			||||||
						    libcamera_get_fd(port->dev.camera, i, j),
 | 
											bufs[i]->planes()[j].fd.fd(),
 | 
				
			||||||
						0);
 | 
											0);
 | 
				
			||||||
				if (d[j].data == MAP_FAILED) {
 | 
									if (d[j].data == MAP_FAILED) {
 | 
				
			||||||
					spa_log_error(impl->log, "mmap: %m");
 | 
										spa_log_error(impl->log, "mmap: %m");
 | 
				
			||||||
| 
						 | 
					@ -696,35 +581,89 @@ mmap_init(struct impl *impl,
 | 
				
			||||||
				return -EIO;
 | 
									return -EIO;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							spa_libcamera_buffer_recycle(impl, port, i);
 | 
				
			||||||
		spa_libcamera_buffer_recycle(impl, i);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	port->n_buffers = libcamera_nbuffers;
 | 
						port->n_buffers = n_buffers;
 | 
				
			||||||
#endif
 | 
						spa_log_info(impl->log, "we have %d buffers", n_buffers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
spa_libcamera_alloc_buffers(struct impl *impl,
 | 
					spa_libcamera_alloc_buffers(struct impl *impl, struct port *port,
 | 
				
			||||||
		       struct spa_buffer **buffers,
 | 
							       struct spa_buffer **buffers,
 | 
				
			||||||
		       uint32_t n_buffers)
 | 
							       uint32_t n_buffers)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int res;
 | 
						int res;
 | 
				
			||||||
	struct port *port = &impl->out_ports[0];
 | 
					
 | 
				
			||||||
 | 
						spa_log_info(impl->log, ". %d", port->n_buffers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (port->n_buffers > 0)
 | 
						if (port->n_buffers > 0)
 | 
				
			||||||
		return -EIO;
 | 
							return -EIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((res = mmap_init(impl, buffers, n_buffers)) < 0) {
 | 
						if ((res = mmap_init(impl, port, buffers, n_buffers)) < 0)
 | 
				
			||||||
		return -EIO;
 | 
							return res;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Impl::requestComplete(libcamera::Request *request)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct impl *impl = this;
 | 
				
			||||||
 | 
						struct port *port = &impl->out_ports[0];
 | 
				
			||||||
 | 
						Stream *stream = port->streamConfig.stream();
 | 
				
			||||||
 | 
						uint32_t index, buffer_id;
 | 
				
			||||||
 | 
						struct buffer *b;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_log_info(impl->log, "request complete");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((request->status() == Request::RequestCancelled)) {
 | 
				
			||||||
 | 
					                spa_log_debug(impl->log, "Request was cancelled");
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
						FrameBuffer *buffer = request->findBuffer(stream);
 | 
				
			||||||
 | 
						if (buffer == nullptr) {
 | 
				
			||||||
 | 
					                spa_log_warn(impl->log, "unknown buffer");
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						const FrameMetadata &fmd = buffer->metadata();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buffer_id = request->cookie();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						b = &port->buffers[buffer_id];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (impl->clock) {
 | 
				
			||||||
 | 
							impl->clock->nsec = fmd.timestamp;
 | 
				
			||||||
 | 
							impl->clock->rate = port->rate;
 | 
				
			||||||
 | 
							impl->clock->position = fmd.sequence;
 | 
				
			||||||
 | 
							impl->clock->duration = 1;
 | 
				
			||||||
 | 
							impl->clock->delay = 0;
 | 
				
			||||||
 | 
							impl->clock->rate_diff = 1.0;
 | 
				
			||||||
 | 
							impl->clock->next_nsec = fmd.timestamp;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (b->h) {
 | 
				
			||||||
 | 
							b->h->flags = 0;
 | 
				
			||||||
 | 
							b->h->offset = 0;
 | 
				
			||||||
 | 
							b->h->seq = fmd.sequence;
 | 
				
			||||||
 | 
							b->h->pts = fmd.timestamp;
 | 
				
			||||||
 | 
							b->h->dts_offset = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						request->reuse();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_ringbuffer_get_write_index(&port->ring, &index);
 | 
				
			||||||
 | 
						port->ring_ids[index & MASK_BUFFERS] = buffer_id;
 | 
				
			||||||
 | 
						spa_ringbuffer_write_update(&port->ring, index + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (spa_system_eventfd_write(impl->system, impl->source.fd, 1) < 0)
 | 
				
			||||||
 | 
							spa_log_error(impl->log, "Failed to write on event fd");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int spa_libcamera_stream_on(struct impl *impl)
 | 
					static int spa_libcamera_stream_on(struct impl *impl)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct port *port = &impl->out_ports[0];
 | 
						struct port *port = &impl->out_ports[0];
 | 
				
			||||||
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!port->have_format) {
 | 
						if (!port->have_format) {
 | 
				
			||||||
		spa_log_error(impl->log, "Exting %s with -EIO", __FUNCTION__);
 | 
							spa_log_error(impl->log, "Exting %s with -EIO", __FUNCTION__);
 | 
				
			||||||
| 
						 | 
					@ -736,24 +675,27 @@ static int spa_libcamera_stream_on(struct impl *impl)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_log_info(impl->log, "connecting camera");
 | 
						spa_log_info(impl->log, "connecting camera");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//	libcamera_connect(dev->camera);
 | 
						impl->camera->requestCompleted.connect(impl, &impl::requestComplete);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//	libcamera_start_capture(dev->camera);
 | 
						if ((res = impl->camera->start()) < 0)
 | 
				
			||||||
 | 
							return res == -EACCES ? -EBUSY : res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	port->source.func = libcamera_on_fd_events;
 | 
						for (Request *req : impl->pendingRequests) {
 | 
				
			||||||
	port->source.data = impl;
 | 
					                if ((res = impl->camera->queueRequest(req)) < 0)
 | 
				
			||||||
	port->source.fd = spa_system_eventfd_create(impl->system, SPA_FD_CLOEXEC | SPA_FD_NONBLOCK);
 | 
								return res == -EACCES ? -EBUSY : res;
 | 
				
			||||||
	port->source.mask = SPA_IO_IN | SPA_IO_ERR;
 | 
					 | 
				
			||||||
	port->source.rmask = 0;
 | 
					 | 
				
			||||||
	if (port->source.fd < 0) {
 | 
					 | 
				
			||||||
		spa_log_error(impl->log, "Failed to create eventfd. Exting %s with -EIO", __FUNCTION__);
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		spa_loop_add_source(impl->data_loop, &port->source);
 | 
					 | 
				
			||||||
		impl->have_source = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//		libcamera_set_spa_system(dev->camera, impl->system);
 | 
					 | 
				
			||||||
//		libcamera_set_eventfd(dev->camera, port->source.fd);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        impl->pendingRequests.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						impl->source.func = libcamera_on_fd_events;
 | 
				
			||||||
 | 
						impl->source.data = impl;
 | 
				
			||||||
 | 
						impl->source.fd = spa_system_eventfd_create(impl->system, SPA_FD_CLOEXEC | SPA_FD_NONBLOCK);
 | 
				
			||||||
 | 
						impl->source.mask = SPA_IO_IN | SPA_IO_ERR;
 | 
				
			||||||
 | 
						impl->source.rmask = 0;
 | 
				
			||||||
 | 
						if (impl->source.fd < 0) {
 | 
				
			||||||
 | 
							spa_log_error(impl->log, "Failed to create eventfd: %s", spa_strerror(impl->source.fd));
 | 
				
			||||||
 | 
							return impl->source.fd;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						spa_loop_add_source(impl->data_loop, &impl->source);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	impl->active = true;
 | 
						impl->active = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -767,28 +709,39 @@ static int do_remove_source(struct spa_loop *loop,
 | 
				
			||||||
			    size_t size,
 | 
								    size_t size,
 | 
				
			||||||
			    void *user_data)
 | 
								    void *user_data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct port *port = (struct port *)user_data;
 | 
						struct impl *impl = (struct impl *)user_data;
 | 
				
			||||||
	if (port->source.loop)
 | 
						if (impl->source.loop)
 | 
				
			||||||
		spa_loop_remove_source(loop, &port->source);
 | 
							spa_loop_remove_source(loop, &impl->source);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int spa_libcamera_stream_off(struct impl *impl)
 | 
					static int spa_libcamera_stream_off(struct impl *impl)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct port *port = &impl->out_ports[0];
 | 
						struct port *port = &impl->out_ports[0];
 | 
				
			||||||
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!impl->active)
 | 
						if (!impl->active) {
 | 
				
			||||||
 | 
							for (std::unique_ptr<Request> &req : impl->requestPool)
 | 
				
			||||||
 | 
								req->reuse();
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_log_info(impl->log, "stopping camera");
 | 
						spa_log_info(impl->log, "stopping camera");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//	libcamera_stop_capture(dev->camera);
 | 
						impl->pendingRequests.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((res = impl->camera->stop()) < 0)
 | 
				
			||||||
 | 
							return res == -EACCES ? -EBUSY : res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_log_info(impl->log, "disconnecting camera");
 | 
						spa_log_info(impl->log, "disconnecting camera");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//	libcamera_disconnect(dev->camera);
 | 
						impl->camera->requestCompleted.disconnect(impl, &impl::requestComplete);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_loop_invoke(impl->data_loop, do_remove_source, 0, NULL, 0, true, port);
 | 
						spa_loop_invoke(impl->data_loop, do_remove_source, 0, NULL, 0, true, impl);
 | 
				
			||||||
 | 
						if (impl->source.fd >= 0)  {
 | 
				
			||||||
 | 
							spa_system_close(impl->system, impl->source.fd);
 | 
				
			||||||
 | 
							impl->source.fd = -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_list_init(&port->queue);
 | 
						spa_list_init(&port->queue);
 | 
				
			||||||
	impl->active = false;
 | 
						impl->active = false;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,926 +0,0 @@
 | 
				
			||||||
/* Spa libcamera support
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Copyright (C) 2020, Collabora Ltd.
 | 
					 | 
				
			||||||
 *     Author: Raghavendra Rao Sidlagatta <raghavendra.rao@collabora.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * libcamera_wrapper.cpp
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Permission is hereby granted, free of charge, to any person obtaining a
 | 
					 | 
				
			||||||
 * copy of this software and associated documentation files (the "Software"),
 | 
					 | 
				
			||||||
 * to deal in the Software without restriction, including without limitation
 | 
					 | 
				
			||||||
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 | 
					 | 
				
			||||||
 * and/or sell copies of the Software, and to permit persons to whom the
 | 
					 | 
				
			||||||
 * Software is furnished to do so, subject to the following conditions:
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The above copyright notice and this permission notice (including the next
 | 
					 | 
				
			||||||
 * paragraph) shall be included in all copies or substantial portions of the
 | 
					 | 
				
			||||||
 * Software.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
					 | 
				
			||||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
					 | 
				
			||||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 | 
					 | 
				
			||||||
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
					 | 
				
			||||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
					 | 
				
			||||||
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 | 
					 | 
				
			||||||
 * DEALINGS IN THE SOFTWARE.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
#include <pthread.h>
 | 
					 | 
				
			||||||
#include <stdio.h>
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
#include <errno.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <climits>
 | 
					 | 
				
			||||||
#include <fcntl.h>
 | 
					 | 
				
			||||||
#include <iomanip>
 | 
					 | 
				
			||||||
#include <iostream>
 | 
					 | 
				
			||||||
#include <sstream>
 | 
					 | 
				
			||||||
#include <sys/mman.h>
 | 
					 | 
				
			||||||
#include <unistd.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <drm_fourcc.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <spa/support/log.h>
 | 
					 | 
				
			||||||
#include <spa/support/system.h>
 | 
					 | 
				
			||||||
#include <spa/param/props.h>
 | 
					 | 
				
			||||||
#include <spa/param/video/raw.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <libcamera/camera.h>
 | 
					 | 
				
			||||||
#include <libcamera/camera_manager.h>
 | 
					 | 
				
			||||||
#include <libcamera/request.h>
 | 
					 | 
				
			||||||
#include <libcamera/framebuffer_allocator.h>
 | 
					 | 
				
			||||||
#include <libcamera/framebuffer.h>
 | 
					 | 
				
			||||||
#include <libcamera/property_ids.h>
 | 
					 | 
				
			||||||
#include <libcamera/controls.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <libcamera/control_ids.h>
 | 
					 | 
				
			||||||
#include <linux/videodev2.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using namespace libcamera;
 | 
					 | 
				
			||||||
using namespace controls;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "libcamera_wrapper.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define DEFAULT_WIDTH			640
 | 
					 | 
				
			||||||
#define DEFAULT_HEIGHT			480
 | 
					 | 
				
			||||||
#define DEFAULT_PIXEL_FMT		DRM_FORMAT_YUYV
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Compressed formats
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * TODO: Should be removed when the format gets merged in the
 | 
					 | 
				
			||||||
 * libdrm.*/
 | 
					 | 
				
			||||||
#ifndef DRM_FORMAT_MJPEG
 | 
					 | 
				
			||||||
# define DRM_FORMAT_MJPEG	fourcc_code('M', 'J', 'P', 'G') /* Motion-JPEG */
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
extern "C" {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static const struct {
 | 
					 | 
				
			||||||
		spa_video_format video_format;
 | 
					 | 
				
			||||||
		unsigned int drm_fourcc;
 | 
					 | 
				
			||||||
	} format_map[] = {
 | 
					 | 
				
			||||||
		{ SPA_VIDEO_FORMAT_ENCODED, DRM_FORMAT_MJPEG },
 | 
					 | 
				
			||||||
		{ SPA_VIDEO_FORMAT_RGB, DRM_FORMAT_BGR888 },
 | 
					 | 
				
			||||||
		{ SPA_VIDEO_FORMAT_BGR, DRM_FORMAT_RGB888 },
 | 
					 | 
				
			||||||
		{ SPA_VIDEO_FORMAT_ARGB, DRM_FORMAT_BGRA8888 },
 | 
					 | 
				
			||||||
		{ SPA_VIDEO_FORMAT_NV12, DRM_FORMAT_NV12 },
 | 
					 | 
				
			||||||
		{ SPA_VIDEO_FORMAT_NV21, DRM_FORMAT_NV21 },
 | 
					 | 
				
			||||||
		{ SPA_VIDEO_FORMAT_NV16, DRM_FORMAT_NV16 },
 | 
					 | 
				
			||||||
		{ SPA_VIDEO_FORMAT_NV61, DRM_FORMAT_NV61 },
 | 
					 | 
				
			||||||
		{ SPA_VIDEO_FORMAT_NV24, DRM_FORMAT_NV24 },
 | 
					 | 
				
			||||||
		{ SPA_VIDEO_FORMAT_UYVY, DRM_FORMAT_UYVY },
 | 
					 | 
				
			||||||
		{ SPA_VIDEO_FORMAT_VYUY, DRM_FORMAT_VYUY },
 | 
					 | 
				
			||||||
		{ SPA_VIDEO_FORMAT_YUY2, DRM_FORMAT_YUYV },
 | 
					 | 
				
			||||||
		{ SPA_VIDEO_FORMAT_YVYU, DRM_FORMAT_YVYU },
 | 
					 | 
				
			||||||
		/* \todo NV42 is used in libcamera but is not mapped in here yet. */
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	typedef struct ring_buf {
 | 
					 | 
				
			||||||
		uint32_t read_index;
 | 
					 | 
				
			||||||
		uint32_t write_index;
 | 
					 | 
				
			||||||
	}ring_buf;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	typedef struct LibCamera {
 | 
					 | 
				
			||||||
		std::unique_ptr<CameraManager> cm_;
 | 
					 | 
				
			||||||
		std::shared_ptr<Camera> cam_;
 | 
					 | 
				
			||||||
		std::unique_ptr<CameraConfiguration> config_;
 | 
					 | 
				
			||||||
		FrameBufferAllocator *allocator_;
 | 
					 | 
				
			||||||
		std::map<Stream*, std::string> streamName_;
 | 
					 | 
				
			||||||
		std::vector<std::unique_ptr<Request>> requests_;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		uint32_t nbuffers_;
 | 
					 | 
				
			||||||
		uint32_t nplanes_;
 | 
					 | 
				
			||||||
		uint32_t bufIdx_;
 | 
					 | 
				
			||||||
		int64_t **fd_;
 | 
					 | 
				
			||||||
		uint32_t maxSize_;
 | 
					 | 
				
			||||||
		uint32_t width_;
 | 
					 | 
				
			||||||
		uint32_t height_;
 | 
					 | 
				
			||||||
		uint32_t pixelFormat_;
 | 
					 | 
				
			||||||
		uint32_t stride_;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		struct ring_buf ringbuf_;
 | 
					 | 
				
			||||||
		void *ringbuf_data_[MAX_NUM_BUFFERS] = {};
 | 
					 | 
				
			||||||
		struct spa_log *log_;
 | 
					 | 
				
			||||||
		struct spa_system *system_;
 | 
					 | 
				
			||||||
		int eventfd_ = -1;
 | 
					 | 
				
			||||||
		pthread_mutex_t lock;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Methods */
 | 
					 | 
				
			||||||
		int32_t listProperties();
 | 
					 | 
				
			||||||
		void requestComplete(Request *request);
 | 
					 | 
				
			||||||
		void item_free_fn();
 | 
					 | 
				
			||||||
		void ring_buffer_init();
 | 
					 | 
				
			||||||
		void *ring_buffer_read();
 | 
					 | 
				
			||||||
		void ring_buffer_write(void *p);
 | 
					 | 
				
			||||||
		bool open();
 | 
					 | 
				
			||||||
		void close();
 | 
					 | 
				
			||||||
		int request_capture();
 | 
					 | 
				
			||||||
		int start();
 | 
					 | 
				
			||||||
		void stop();
 | 
					 | 
				
			||||||
		void connect();
 | 
					 | 
				
			||||||
		void disconnect();
 | 
					 | 
				
			||||||
		bool set_config();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		std::shared_ptr<Camera> get_camera();
 | 
					 | 
				
			||||||
		std::string choose_camera();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Mutators */
 | 
					 | 
				
			||||||
		void set_streamcfg_width(uint32_t w);
 | 
					 | 
				
			||||||
		void set_streamcfg_height(uint32_t h);
 | 
					 | 
				
			||||||
		void set_streamcfgpixel_format(uint32_t fmt);
 | 
					 | 
				
			||||||
		void set_max_size(uint32_t s);
 | 
					 | 
				
			||||||
		void set_nbuffers(uint32_t n);
 | 
					 | 
				
			||||||
		void set_nplanes(uint32_t n);
 | 
					 | 
				
			||||||
		void set_stride(uint32_t s);
 | 
					 | 
				
			||||||
		void set_fd(Stream *stream);
 | 
					 | 
				
			||||||
		void ring_buffer_set_read_index(uint32_t idx);
 | 
					 | 
				
			||||||
		void ring_buffer_set_write_index(uint32_t idx);
 | 
					 | 
				
			||||||
		void ring_buffer_update_read_index();
 | 
					 | 
				
			||||||
		void ring_buffer_update_write_index();
 | 
					 | 
				
			||||||
		void reset_ring_buffer_data();
 | 
					 | 
				
			||||||
		int32_t set_control(ControlList &controls, uint32_t control_id, float value);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Accessors */
 | 
					 | 
				
			||||||
		uint32_t get_streamcfg_width();
 | 
					 | 
				
			||||||
		uint32_t get_streamcfg_height();
 | 
					 | 
				
			||||||
		uint32_t get_streamcfgpixel_format();
 | 
					 | 
				
			||||||
		uint32_t get_max_size();
 | 
					 | 
				
			||||||
		uint32_t get_nbuffers();
 | 
					 | 
				
			||||||
		uint32_t get_nplanes();
 | 
					 | 
				
			||||||
		uint32_t get_stride();
 | 
					 | 
				
			||||||
		uint32_t ring_buffer_get_read_index();
 | 
					 | 
				
			||||||
		uint32_t ring_buffer_get_write_index();
 | 
					 | 
				
			||||||
	}LibCamera;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint32_t LibCamera::get_max_size() {
 | 
					 | 
				
			||||||
		return this->maxSize_;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void LibCamera::set_max_size(uint32_t s) {
 | 
					 | 
				
			||||||
		this->maxSize_ = s;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint32_t LibCamera::get_nbuffers() {
 | 
					 | 
				
			||||||
		return this->nbuffers_;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void LibCamera::set_nbuffers(uint32_t n) {
 | 
					 | 
				
			||||||
		this->nbuffers_ = n;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void LibCamera::set_nplanes(uint32_t n) {
 | 
					 | 
				
			||||||
		this->nplanes_ = n;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void LibCamera::set_stride(uint32_t s) {
 | 
					 | 
				
			||||||
		this->stride_ = s;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint32_t LibCamera::get_stride() {
 | 
					 | 
				
			||||||
		return this->stride_;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void LibCamera::set_fd(Stream *stream) {
 | 
					 | 
				
			||||||
		this->fd_ = new int64_t*[this->nbuffers_];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		uint32_t bufIdx = 0;
 | 
					 | 
				
			||||||
		for (const std::unique_ptr<FrameBuffer> &buffer : this->allocator_->buffers(stream)) {
 | 
					 | 
				
			||||||
			uint32_t nplanes = buffer->planes().size();
 | 
					 | 
				
			||||||
			this->fd_[bufIdx] = new int64_t[this->nplanes_];
 | 
					 | 
				
			||||||
			for(uint32_t planeIdx = 0; planeIdx < nplanes; ++planeIdx) {
 | 
					 | 
				
			||||||
				const FrameBuffer::Plane &plane = buffer->planes().front();
 | 
					 | 
				
			||||||
				this->fd_[bufIdx][planeIdx] = plane.fd.fd();
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			bufIdx++;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint32_t LibCamera::get_nplanes() {
 | 
					 | 
				
			||||||
		return this->nplanes_;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void LibCamera::ring_buffer_init() {
 | 
					 | 
				
			||||||
		this->ringbuf_.read_index = 0;
 | 
					 | 
				
			||||||
		this->ringbuf_.write_index = 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint32_t LibCamera::ring_buffer_get_read_index() {
 | 
					 | 
				
			||||||
		uint32_t idx;
 | 
					 | 
				
			||||||
		idx = __atomic_load_n(&this->ringbuf_.read_index, __ATOMIC_RELAXED);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return idx;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint32_t LibCamera::ring_buffer_get_write_index() {
 | 
					 | 
				
			||||||
		uint32_t idx;
 | 
					 | 
				
			||||||
		idx = __atomic_load_n(&this->ringbuf_.write_index, __ATOMIC_RELAXED);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return idx;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void LibCamera::ring_buffer_set_read_index(uint32_t idx) {
 | 
					 | 
				
			||||||
		__atomic_store_n(&this->ringbuf_.read_index, idx, __ATOMIC_RELEASE);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void LibCamera::ring_buffer_set_write_index(uint32_t idx) {
 | 
					 | 
				
			||||||
		__atomic_store_n(&this->ringbuf_.write_index, idx, __ATOMIC_RELEASE);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void LibCamera::ring_buffer_update_read_index() {
 | 
					 | 
				
			||||||
		uint32_t idx;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		idx = this->ring_buffer_get_read_index();
 | 
					 | 
				
			||||||
		this->ringbuf_data_[idx] = nullptr;
 | 
					 | 
				
			||||||
		++idx;
 | 
					 | 
				
			||||||
		if(idx == MAX_NUM_BUFFERS) {
 | 
					 | 
				
			||||||
			idx = 0;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		this->ring_buffer_set_read_index(idx);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void LibCamera::ring_buffer_update_write_index() {
 | 
					 | 
				
			||||||
		uint32_t idx;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		idx = this->ring_buffer_get_write_index();
 | 
					 | 
				
			||||||
		++idx;
 | 
					 | 
				
			||||||
		if(idx == MAX_NUM_BUFFERS) {
 | 
					 | 
				
			||||||
			idx = 0;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		this->ring_buffer_set_write_index(idx);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void LibCamera::ring_buffer_write(void *p)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		uint32_t idx;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		idx = this->ring_buffer_get_write_index();
 | 
					 | 
				
			||||||
		pthread_mutex_lock(&this->lock);
 | 
					 | 
				
			||||||
		ringbuf_data_[idx] = p;
 | 
					 | 
				
			||||||
		pthread_mutex_unlock(&this->lock);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void *LibCamera::ring_buffer_read()
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		uint32_t idx;
 | 
					 | 
				
			||||||
		void *p;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		idx = this->ring_buffer_get_read_index();
 | 
					 | 
				
			||||||
		pthread_mutex_lock(&this->lock);
 | 
					 | 
				
			||||||
		p = (void *)this->ringbuf_data_[idx];
 | 
					 | 
				
			||||||
		pthread_mutex_unlock(&this->lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return p;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void LibCamera::item_free_fn() {
 | 
					 | 
				
			||||||
		uint32_t ringbuf_read_index;
 | 
					 | 
				
			||||||
		struct OutBuf *pOut = NULL;
 | 
					 | 
				
			||||||
		struct CamData *pDatas = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ringbuf_read_index = this->ring_buffer_get_read_index();
 | 
					 | 
				
			||||||
		for(int i = 0; i < MAX_NUM_BUFFERS; i++) {
 | 
					 | 
				
			||||||
			pOut = (struct OutBuf *)ringbuf_data_[ringbuf_read_index];
 | 
					 | 
				
			||||||
			if(pOut) {
 | 
					 | 
				
			||||||
				pDatas = pOut->datas;
 | 
					 | 
				
			||||||
				if(pDatas) {
 | 
					 | 
				
			||||||
					libcamera_free_CamData(this, pDatas);
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				libcamera_free_OutBuf(this, pOut);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			++ringbuf_read_index;
 | 
					 | 
				
			||||||
			if(ringbuf_read_index == MAX_NUM_BUFFERS) {
 | 
					 | 
				
			||||||
				ringbuf_read_index = 0;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::string LibCamera::choose_camera() {
 | 
					 | 
				
			||||||
		if (!this->cm_) {
 | 
					 | 
				
			||||||
			return std::string();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (this->cm_->cameras().empty()) {
 | 
					 | 
				
			||||||
			return std::string();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		/* If only one camera is available, use it automatically. */
 | 
					 | 
				
			||||||
		else if (this->cm_->cameras().size() == 1) {
 | 
					 | 
				
			||||||
			return this->cm_->cameras()[0]->id();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		/* TODO::
 | 
					 | 
				
			||||||
		 * 1. Allow the user to provide a camera name to select.			*
 | 
					 | 
				
			||||||
		 * 2. Select the camera based on the camera name provided by User 	*
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		/* For time being, return the first camera if more than 1 camera devices are available */
 | 
					 | 
				
			||||||
		else {
 | 
					 | 
				
			||||||
			return this->cm_->cameras()[0]->id();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::shared_ptr<Camera> LibCamera::get_camera() {
 | 
					 | 
				
			||||||
		std::string camName = this->choose_camera();
 | 
					 | 
				
			||||||
		std::shared_ptr<Camera> cam;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (camName == "") {
 | 
					 | 
				
			||||||
			return nullptr;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		cam = this->cm_->get(camName);
 | 
					 | 
				
			||||||
		if (!cam) {
 | 
					 | 
				
			||||||
			return nullptr;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Sanity check that the camera has streams. */
 | 
					 | 
				
			||||||
		if (cam->streams().empty()) {
 | 
					 | 
				
			||||||
			return nullptr;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return cam;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint32_t LibCamera::get_streamcfg_width() {
 | 
					 | 
				
			||||||
		return this->width_;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint32_t LibCamera::get_streamcfg_height() {
 | 
					 | 
				
			||||||
		return this->height_;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint32_t LibCamera::get_streamcfgpixel_format() {
 | 
					 | 
				
			||||||
		return this->pixelFormat_;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void LibCamera::set_streamcfg_width(uint32_t w) {
 | 
					 | 
				
			||||||
		this->width_ = w;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void LibCamera::set_streamcfg_height(uint32_t h) {
 | 
					 | 
				
			||||||
		this->height_ = h;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void LibCamera::set_streamcfgpixel_format(uint32_t fmt) {
 | 
					 | 
				
			||||||
		this->pixelFormat_ = fmt;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool LibCamera::set_config() {
 | 
					 | 
				
			||||||
    	if(!this->cam_) {
 | 
					 | 
				
			||||||
    		return false;
 | 
					 | 
				
			||||||
    	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    	this->config_ = this->cam_->generateConfiguration({ StreamRole::VideoRecording });
 | 
					 | 
				
			||||||
    	if (!this->config_ || this->config_->size() != 1) {
 | 
					 | 
				
			||||||
    		return false;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		StreamConfiguration &cfg = this->config_->at(0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		cfg.size.width = this->get_streamcfg_width();
 | 
					 | 
				
			||||||
		cfg.size.height = this->get_streamcfg_height();
 | 
					 | 
				
			||||||
		cfg.pixelFormat = PixelFormat(this->get_streamcfgpixel_format());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Validate the configuration. */
 | 
					 | 
				
			||||||
		if (this->config_->validate() == CameraConfiguration::Invalid) {
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    	if (this->cam_->configure(this->config_.get())) {
 | 
					 | 
				
			||||||
    		return false;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		this->listProperties();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		this->allocator_ = new FrameBufferAllocator(this->cam_);
 | 
					 | 
				
			||||||
		uint32_t nbuffers = UINT_MAX, nplanes = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Stream *stream = cfg.stream();
 | 
					 | 
				
			||||||
		int ret = this->allocator_->allocate(stream);
 | 
					 | 
				
			||||||
		if (ret < 0) {
 | 
					 | 
				
			||||||
			return -ENOMEM;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		uint32_t allocated = this->allocator_->buffers(cfg.stream()).size();
 | 
					 | 
				
			||||||
		nbuffers = std::min(nbuffers, allocated);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		this->set_nbuffers(nbuffers);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		int id = 0;
 | 
					 | 
				
			||||||
		uint32_t max_size = 0;
 | 
					 | 
				
			||||||
		for (const std::unique_ptr<FrameBuffer> &buffer : this->allocator_->buffers(stream)) {
 | 
					 | 
				
			||||||
			nplanes = buffer->planes().size();
 | 
					 | 
				
			||||||
			const FrameBuffer::Plane &plane = buffer->planes().front();
 | 
					 | 
				
			||||||
			max_size = std::max(max_size, plane.length);
 | 
					 | 
				
			||||||
			++id;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		this->set_max_size(max_size);
 | 
					 | 
				
			||||||
		this->set_nplanes(nplanes);
 | 
					 | 
				
			||||||
		this->set_fd(stream);
 | 
					 | 
				
			||||||
		this->set_stride(cfg.stride);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return true;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int LibCamera::request_capture() {
 | 
					 | 
				
			||||||
    	int ret = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    	StreamConfiguration &cfg = this->config_->at(0);
 | 
					 | 
				
			||||||
		Stream *stream = cfg.stream();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (const std::unique_ptr<FrameBuffer> &buffer : this->allocator_->buffers(stream)) {
 | 
					 | 
				
			||||||
			std::unique_ptr<Request> request = this->cam_->createRequest();
 | 
					 | 
				
			||||||
			if (!request) {
 | 
					 | 
				
			||||||
				spa_log_error(this->log_, "Cannot create request");
 | 
					 | 
				
			||||||
				return -ENOMEM;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (request->addBuffer(stream, buffer.get())) {
 | 
					 | 
				
			||||||
				spa_log_error(this->log_, "Failed to associating buffer with request");
 | 
					 | 
				
			||||||
				return -ENOMEM;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			this->requests_.push_back(std::move(request));
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool LibCamera::open() {
 | 
					 | 
				
			||||||
		std::shared_ptr<Camera> cam;
 | 
					 | 
				
			||||||
		int ret = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		cam = this->get_camera();
 | 
					 | 
				
			||||||
		if(!cam) {
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ret = cam->acquire();
 | 
					 | 
				
			||||||
		if (ret) {
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		this->cam_ = cam;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if(!this->set_config()) {
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return true;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int LibCamera::start() {
 | 
					 | 
				
			||||||
		for (unsigned int index = 0; index < this->config_->size(); ++index) {
 | 
					 | 
				
			||||||
			StreamConfiguration &cfg = this->config_->at(index);
 | 
					 | 
				
			||||||
			this->streamName_[cfg.stream()] = "stream" + std::to_string(index);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if(this->request_capture()) {
 | 
					 | 
				
			||||||
			spa_log_error(this->log_, "failed to create request");
 | 
					 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		spa_log_info(this->log_, "Starting camera ...");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* start the camera now */
 | 
					 | 
				
			||||||
		if (this->cam_->start()) {
 | 
					 | 
				
			||||||
			spa_log_error(this->log_, "failed to start camera");
 | 
					 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		this->ring_buffer_init();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (std::unique_ptr<Request> &request : this->requests_) {
 | 
					 | 
				
			||||||
			int ret = this->cam_->queueRequest(request.get());
 | 
					 | 
				
			||||||
			if (ret < 0) {
 | 
					 | 
				
			||||||
				spa_log_error(this->log_, "Cannot enqueue request");
 | 
					 | 
				
			||||||
				return ret;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void LibCamera::stop() {
 | 
					 | 
				
			||||||
		StreamConfiguration &cfg = this->config_->at(0);
 | 
					 | 
				
			||||||
		Stream *stream = cfg.stream();
 | 
					 | 
				
			||||||
		uint32_t nbuffers = this->allocator_->buffers(stream).size();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (uint32_t bufIdx = 0; bufIdx < nbuffers; bufIdx++) {
 | 
					 | 
				
			||||||
			delete [] this->fd_[bufIdx];
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		delete [] this->fd_;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    	spa_log_info(this->log_, "Stopping camera ...");
 | 
					 | 
				
			||||||
    	this->cam_->stop();
 | 
					 | 
				
			||||||
    	if(this->allocator_) {
 | 
					 | 
				
			||||||
		this->allocator_->free(stream);
 | 
					 | 
				
			||||||
	    	delete this->allocator_;
 | 
					 | 
				
			||||||
	    	this->allocator_ = nullptr;
 | 
					 | 
				
			||||||
    	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	    this->item_free_fn();
 | 
					 | 
				
			||||||
	    this->requests_.clear();
 | 
					 | 
				
			||||||
	    this->streamName_.clear();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void LibCamera::close() {
 | 
					 | 
				
			||||||
		if (this->cam_)
 | 
					 | 
				
			||||||
			this->cam_->release();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void LibCamera::connect()
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		this->cam_->requestCompleted.connect(this, &LibCamera::requestComplete);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void LibCamera::disconnect()
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		this->cam_->requestCompleted.disconnect(this, &LibCamera::requestComplete);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint32_t libcamera_get_streamcfg_width(LibCamera *camera) {
 | 
					 | 
				
			||||||
		return camera->get_streamcfg_width();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint32_t libcamera_get_streamcfg_height(LibCamera *camera) {
 | 
					 | 
				
			||||||
		return camera->get_streamcfg_height();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint32_t libcamera_get_streamcfgpixel_format(LibCamera *camera) {
 | 
					 | 
				
			||||||
		return camera->get_streamcfgpixel_format();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void libcamera_set_streamcfg_width(LibCamera *camera, uint32_t w) {
 | 
					 | 
				
			||||||
		camera->set_streamcfg_width(w);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void libcamera_set_streamcfg_height(LibCamera *camera, uint32_t h) {
 | 
					 | 
				
			||||||
		camera->set_streamcfg_height(h);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void libcamera_set_streamcfgpixel_format(LibCamera *camera, uint32_t fmt) {
 | 
					 | 
				
			||||||
		camera->set_streamcfgpixel_format(fmt);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool libcamera_set_config(LibCamera *camera) {
 | 
					 | 
				
			||||||
		return camera->set_config();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void libcamera_ringbuffer_read_update(LibCamera *camera) {
 | 
					 | 
				
			||||||
		camera->ring_buffer_update_read_index();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void *libcamera_get_ring_buffer_data(LibCamera *camera) {
 | 
					 | 
				
			||||||
		return camera->ring_buffer_read();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void libcamera_free_OutBuf(LibCamera *camera, OutBuf *p) {
 | 
					 | 
				
			||||||
		pthread_mutex_lock(&camera->lock);
 | 
					 | 
				
			||||||
    	if(p != nullptr) {
 | 
					 | 
				
			||||||
    		delete p;
 | 
					 | 
				
			||||||
    		p = nullptr;
 | 
					 | 
				
			||||||
    	}
 | 
					 | 
				
			||||||
    	pthread_mutex_unlock(&camera->lock);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void libcamera_free_CamData(LibCamera *camera, CamData *p) {
 | 
					 | 
				
			||||||
    	pthread_mutex_lock(&camera->lock);
 | 
					 | 
				
			||||||
    	if(p != nullptr) {
 | 
					 | 
				
			||||||
    		delete p;
 | 
					 | 
				
			||||||
    		p = nullptr;
 | 
					 | 
				
			||||||
    	}
 | 
					 | 
				
			||||||
    	pthread_mutex_unlock(&camera->lock);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void libcamera_set_log(LibCamera *camera, struct spa_log *log) {
 | 
					 | 
				
			||||||
		camera->log_ = log;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void libcamera_set_spa_system(LibCamera *camera, struct spa_system *system) {
 | 
					 | 
				
			||||||
		camera->system_ = system;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void libcamera_set_eventfd(LibCamera *camera, int fd) {
 | 
					 | 
				
			||||||
		camera->eventfd_ = fd;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	spa_video_format libcamera_map_drm_fourcc_format(unsigned int fourcc) {
 | 
					 | 
				
			||||||
		for (const auto &item : format_map) {
 | 
					 | 
				
			||||||
			if (item.drm_fourcc == fourcc) {
 | 
					 | 
				
			||||||
				return item.video_format;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return (spa_video_format)UINT32_MAX;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint32_t libcamera_drm_to_video_format(unsigned int drm) {
 | 
					 | 
				
			||||||
		return libcamera_map_drm_fourcc_format(drm);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint32_t libcamera_video_format_to_drm(uint32_t format)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		if (format == SPA_VIDEO_FORMAT_ENCODED) {
 | 
					 | 
				
			||||||
			return DRM_FORMAT_INVALID;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (const auto &item : format_map) {
 | 
					 | 
				
			||||||
			if (item.video_format == format) {
 | 
					 | 
				
			||||||
				return item.drm_fourcc;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return DRM_FORMAT_INVALID;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint32_t libcamera_enum_streamcfgpixel_format(LibCamera *camera, uint32_t idx) {
 | 
					 | 
				
			||||||
		if(!camera) {
 | 
					 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (!camera->config_) {
 | 
					 | 
				
			||||||
			spa_log_error(camera->log_, "Cannot get stream information without a camera");
 | 
					 | 
				
			||||||
			return -EINVAL;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (const StreamConfiguration &cfg : *camera->config_) {
 | 
					 | 
				
			||||||
			uint32_t index = 0;
 | 
					 | 
				
			||||||
			const StreamFormats &formats = cfg.formats();
 | 
					 | 
				
			||||||
			for (PixelFormat pixelformat : formats.pixelformats()) {
 | 
					 | 
				
			||||||
				if(index == idx) {
 | 
					 | 
				
			||||||
					return pixelformat.fourcc();
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				++index;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		/* We shouldn't be here */
 | 
					 | 
				
			||||||
		return UINT32_MAX;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void libcamera_get_streamcfg_size(LibCamera *camera, uint32_t idx, uint32_t *width, uint32_t *height) {
 | 
					 | 
				
			||||||
		if(!camera) {
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (!camera->config_) {
 | 
					 | 
				
			||||||
			spa_log_error(camera->log_, "Cannot get stream information without a camera");;
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (const StreamConfiguration &cfg : *camera->config_) {
 | 
					 | 
				
			||||||
			const StreamFormats &formats = cfg.formats();
 | 
					 | 
				
			||||||
			for (PixelFormat pixelformat : formats.pixelformats()) {
 | 
					 | 
				
			||||||
				uint32_t index = 0;
 | 
					 | 
				
			||||||
				for (const Size &size : formats.sizes(pixelformat)) {
 | 
					 | 
				
			||||||
					if(index == idx) {
 | 
					 | 
				
			||||||
						*width = size.width;
 | 
					 | 
				
			||||||
						*height = size.height;
 | 
					 | 
				
			||||||
						return;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					++index;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		/* We shouldn't be here */
 | 
					 | 
				
			||||||
		*width = *height = UINT32_MAX;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int LibCamera::listProperties()
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		if (!cam_) {
 | 
					 | 
				
			||||||
			spa_log_error(log_, "Cannot list properties without a camera");;
 | 
					 | 
				
			||||||
			return -EINVAL;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		spa_log_info(log_, "listing properties");
 | 
					 | 
				
			||||||
		for (const auto &prop : cam_->properties()) {
 | 
					 | 
				
			||||||
			const ControlId *id = properties::properties.at(prop.first);
 | 
					 | 
				
			||||||
			const ControlValue &value = prop.second;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			spa_log_info(log_, "Property: %s = %s",id->name().c_str(), value.toString().c_str());
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int64_t libcamera_get_fd(LibCamera *camera, int bufIdx, int planeIdx) {
 | 
					 | 
				
			||||||
		if((bufIdx >= (int)camera->nbuffers_) || (planeIdx >= (int)camera->nplanes_)){
 | 
					 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			return camera->fd_[bufIdx][planeIdx];
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int libcamera_get_max_size(LibCamera *camera) {
 | 
					 | 
				
			||||||
		return camera->get_max_size();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void libcamera_connect(LibCamera *camera) {
 | 
					 | 
				
			||||||
    	if(!camera || !camera->cam_) {
 | 
					 | 
				
			||||||
    		return;
 | 
					 | 
				
			||||||
    	}
 | 
					 | 
				
			||||||
    	camera->connect();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    uint32_t libcamera_get_nbuffers(LibCamera *camera) {
 | 
					 | 
				
			||||||
		return camera->get_nbuffers();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    uint32_t libcamera_get_nplanes(LibCamera *camera) {
 | 
					 | 
				
			||||||
    	return camera->get_nplanes();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    uint32_t libcamera_get_stride(LibCamera *camera) {
 | 
					 | 
				
			||||||
    	return camera->get_stride();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int libcamera_start_capture(LibCamera *camera) {
 | 
					 | 
				
			||||||
		if (!camera || !camera->cm_ || !camera->cam_) {
 | 
					 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return camera->start();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void libcamera_disconnect(LibCamera *camera) {
 | 
					 | 
				
			||||||
    	if(!camera || !camera->cam_) {
 | 
					 | 
				
			||||||
    		return;
 | 
					 | 
				
			||||||
    	}
 | 
					 | 
				
			||||||
    	camera->disconnect();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void libcamera_stop_capture(LibCamera *camera) {
 | 
					 | 
				
			||||||
    	if(!camera || !camera->cm_ || !camera->cam_) {
 | 
					 | 
				
			||||||
    		return;
 | 
					 | 
				
			||||||
    	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    	camera->stop();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	LibCamera* newLibCamera() {
 | 
					 | 
				
			||||||
		int ret = 0;
 | 
					 | 
				
			||||||
		pthread_mutexattr_t attr;
 | 
					 | 
				
			||||||
		std::unique_ptr<CameraManager> cm = std::make_unique<CameraManager>();
 | 
					 | 
				
			||||||
		LibCamera* camera = new LibCamera();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		pthread_mutexattr_init(&attr);
 | 
					 | 
				
			||||||
		pthread_mutex_init(&camera->lock, &attr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ret = cm->start();
 | 
					 | 
				
			||||||
		if (ret) {
 | 
					 | 
				
			||||||
			deleteLibCamera(camera);
 | 
					 | 
				
			||||||
			return nullptr;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		camera->cm_ = std::move(cm);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		camera->bufIdx_ = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		camera->set_streamcfg_width(DEFAULT_WIDTH);
 | 
					 | 
				
			||||||
		camera->set_streamcfg_height(DEFAULT_HEIGHT);
 | 
					 | 
				
			||||||
		camera->set_streamcfgpixel_format(DEFAULT_PIXEL_FMT);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if(!camera->open()) {
 | 
					 | 
				
			||||||
			deleteLibCamera(camera);
 | 
					 | 
				
			||||||
			return nullptr;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		camera->ring_buffer_init();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return camera;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void deleteLibCamera(LibCamera *camera) {
 | 
					 | 
				
			||||||
    	if(camera == nullptr) {
 | 
					 | 
				
			||||||
    		return;
 | 
					 | 
				
			||||||
    	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    	pthread_mutex_destroy(&camera->lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    	camera->close();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    	if(camera->cm_)
 | 
					 | 
				
			||||||
    		camera->cm_->stop();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    	delete camera;
 | 
					 | 
				
			||||||
    	camera = nullptr;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void LibCamera::requestComplete(Request *request) {
 | 
					 | 
				
			||||||
    	if (request->status() == Request::RequestCancelled) {
 | 
					 | 
				
			||||||
    		return;
 | 
					 | 
				
			||||||
    	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    	++bufIdx_;
 | 
					 | 
				
			||||||
		if(bufIdx_ >= nbuffers_) {
 | 
					 | 
				
			||||||
			bufIdx_ = 0;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		const Request::BufferMap &buffers = request->buffers();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (auto it = buffers.begin(); it != buffers.end(); ++it) {
 | 
					 | 
				
			||||||
			FrameBuffer *buffer = it->second;
 | 
					 | 
				
			||||||
			unsigned int nplanes = buffer->planes().size();
 | 
					 | 
				
			||||||
			OutBuf *pBuf = new OutBuf();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			pBuf->bufIdx = bufIdx_;
 | 
					 | 
				
			||||||
			pBuf->n_datas = nplanes;
 | 
					 | 
				
			||||||
			pBuf->datas = new CamData[pBuf->n_datas];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			unsigned int planeIdx = 0;
 | 
					 | 
				
			||||||
			const std::vector<FrameBuffer::Plane> &planes = buffer->planes();
 | 
					 | 
				
			||||||
			const FrameMetadata &metadata = buffer->metadata();
 | 
					 | 
				
			||||||
			for (const FrameMetadata::Plane &plane : metadata.planes()) {
 | 
					 | 
				
			||||||
				pBuf->datas[planeIdx].idx = planeIdx;
 | 
					 | 
				
			||||||
				pBuf->datas[planeIdx].type = 3; /*SPA_DATA_DmaBuf;*/
 | 
					 | 
				
			||||||
				pBuf->datas[planeIdx].fd = planes[planeIdx].fd.fd();
 | 
					 | 
				
			||||||
				pBuf->datas[planeIdx].size = plane.bytesused;
 | 
					 | 
				
			||||||
				pBuf->datas[planeIdx].maxsize = buffer->planes()[planeIdx].length;
 | 
					 | 
				
			||||||
				pBuf->datas[planeIdx].sequence = metadata.sequence;
 | 
					 | 
				
			||||||
				pBuf->datas[planeIdx].timestamp.tv_sec = metadata.timestamp / 1000000000;
 | 
					 | 
				
			||||||
				pBuf->datas[planeIdx].timestamp.tv_usec = (metadata.timestamp / 1000) % 1000000;
 | 
					 | 
				
			||||||
				++planeIdx;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			/* Push the buffer to ring buffer */
 | 
					 | 
				
			||||||
			if(pBuf && pBuf->datas) {
 | 
					 | 
				
			||||||
				this->ring_buffer_write(pBuf);
 | 
					 | 
				
			||||||
				/* Now update the write index of the ring buffer */
 | 
					 | 
				
			||||||
				this->ring_buffer_update_write_index();
 | 
					 | 
				
			||||||
				if(this->system_ && (this->eventfd_ > 0)) {
 | 
					 | 
				
			||||||
					if (spa_system_eventfd_write(this->system_, this->eventfd_, 1) < 0) {
 | 
					 | 
				
			||||||
						spa_log_error(log_, "Failed to write on event fd");
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/*
 | 
					 | 
				
			||||||
		 * Create a new request and populate it with one buffer for each
 | 
					 | 
				
			||||||
		 * stream.
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		for (auto it = buffers.begin(); it != buffers.end(); ++it) {
 | 
					 | 
				
			||||||
			const Stream *stream = it->first;
 | 
					 | 
				
			||||||
			FrameBuffer *buffer = it->second;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			request->reuse();
 | 
					 | 
				
			||||||
			request->addBuffer(stream, buffer);
 | 
					 | 
				
			||||||
			cam_->queueRequest(request);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int32_t LibCamera::set_control(ControlList &controls, uint32_t control_id, float value) {
 | 
					 | 
				
			||||||
    	switch(control_id) {
 | 
					 | 
				
			||||||
    		case SPA_PROP_brightness:
 | 
					 | 
				
			||||||
    			controls.set(controls::Brightness, value);
 | 
					 | 
				
			||||||
    		break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    		case SPA_PROP_contrast:
 | 
					 | 
				
			||||||
    			controls.set(controls::Contrast, value);
 | 
					 | 
				
			||||||
    		break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    		case SPA_PROP_saturation:
 | 
					 | 
				
			||||||
    			controls.set(controls::Saturation, value);
 | 
					 | 
				
			||||||
    		break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    		case SPA_PROP_exposure:
 | 
					 | 
				
			||||||
    			controls.set(controls::ExposureValue, value);
 | 
					 | 
				
			||||||
    		break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    		case SPA_PROP_gain:
 | 
					 | 
				
			||||||
    			controls.set(controls::AnalogueGain, value);
 | 
					 | 
				
			||||||
    		break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    		default:
 | 
					 | 
				
			||||||
    		return -1;
 | 
					 | 
				
			||||||
    	}
 | 
					 | 
				
			||||||
    	return 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int32_t libcamera_set_control(LibCamera *camera, uint32_t control_id, float value) {
 | 
					 | 
				
			||||||
    	int32_t res;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    	if(!camera || !camera->cm_ || !camera->cam_)
 | 
					 | 
				
			||||||
    		return -1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::unique_ptr<Request> request = camera->cam_->createRequest();
 | 
					 | 
				
			||||||
    	ControlList &controls = request->controls();
 | 
					 | 
				
			||||||
    	res = camera->set_control(controls, control_id, value);
 | 
					 | 
				
			||||||
        camera->cam_->queueRequest(request.get());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    	return res;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,132 +0,0 @@
 | 
				
			||||||
/* Spa libcamera support
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Copyright (C) 2020, Collabora Ltd.
 | 
					 | 
				
			||||||
 *     Author: Raghavendra Rao Sidlagatta <raghavendra.rao@collabora.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * libcamera_wrapper.h
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Permission is hereby granted, free of charge, to any person obtaining a
 | 
					 | 
				
			||||||
 * copy of this software and associated documentation files (the "Software"),
 | 
					 | 
				
			||||||
 * to deal in the Software without restriction, including without limitation
 | 
					 | 
				
			||||||
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 | 
					 | 
				
			||||||
 * and/or sell copies of the Software, and to permit persons to whom the
 | 
					 | 
				
			||||||
 * Software is furnished to do so, subject to the following conditions:
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The above copyright notice and this permission notice (including the next
 | 
					 | 
				
			||||||
 * paragraph) shall be included in all copies or substantial portions of the
 | 
					 | 
				
			||||||
 * Software.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
					 | 
				
			||||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
					 | 
				
			||||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 | 
					 | 
				
			||||||
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
					 | 
				
			||||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
					 | 
				
			||||||
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 | 
					 | 
				
			||||||
 * DEALINGS IN THE SOFTWARE.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef __LIBCAMERA_WRAPPER_H
 | 
					 | 
				
			||||||
#define __LIBCAMERA_WRAPPER_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef __cplusplus
 | 
					 | 
				
			||||||
extern "C" {
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define MAX_NUM_BUFFERS				16
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct CamData {
 | 
					 | 
				
			||||||
	uint32_t idx;
 | 
					 | 
				
			||||||
	uint32_t type;
 | 
					 | 
				
			||||||
	int64_t fd;
 | 
					 | 
				
			||||||
	uint32_t maxsize; /**< max size of data */
 | 
					 | 
				
			||||||
	uint32_t size; /**< size of valid data. Should be clamped to
 | 
					 | 
				
			||||||
					  *  maxsize. */
 | 
					 | 
				
			||||||
	struct timeval timestamp;
 | 
					 | 
				
			||||||
	uint32_t sequence;
 | 
					 | 
				
			||||||
	void *data;
 | 
					 | 
				
			||||||
}CamData;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct OutBuf {
 | 
					 | 
				
			||||||
	uint32_t bufIdx;
 | 
					 | 
				
			||||||
	uint32_t n_datas;		/**< number of data members */
 | 
					 | 
				
			||||||
	struct CamData *datas;	/**< array of data members */
 | 
					 | 
				
			||||||
}OutBuf;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct LibCamera LibCamera;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
LibCamera *newLibCamera();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void deleteLibCamera(LibCamera *camera);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void libcamera_set_log(LibCamera *camera, struct spa_log *log);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool libcamera_open(LibCamera *camera);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void libcamera_close(LibCamera *camera);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void libcamera_connect(LibCamera *camera);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void libcamera_disconnect(LibCamera *camera);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int libcamera_isCapturing(LibCamera *camera);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int libcamera_start_capture(LibCamera *camera);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void libcamera_stop_capture(LibCamera *camera);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int libcamera_get_refcnt(LibCamera *camera);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uint32_t libcamera_get_streamcfg_width(LibCamera *camera);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uint32_t libcamera_get_streamcfg_height(LibCamera *camera);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uint32_t libcamera_get_streamcfgpixel_format(LibCamera *camera);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uint32_t libcamera_enum_streamcfgpixel_format(LibCamera *camera, uint32_t idx);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uint32_t libcamera_video_format_to_drm(uint32_t fmt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uint32_t libcamera_drm_to_video_format(unsigned int drm);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uint32_t libcamera_get_nbuffers(LibCamera *camera);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uint32_t libcamera_get_nplanes(LibCamera *camera);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int64_t libcamera_get_fd(LibCamera *camera, int bufIdx, int planeIdx);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int32_t libcamera_get_max_size(LibCamera *camera);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int32_t libcamera_set_control(LibCamera *camera, uint32_t control_id, float value);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void libcamera_set_streamcfg_width(LibCamera *camera, uint32_t w);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void libcamera_set_streamcfg_height(LibCamera *camera, uint32_t w);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void libcamera_set_streamcfgpixel_format(LibCamera *camera, uint32_t fmt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool libcamera_set_config(LibCamera *camera);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void libcamera_get_streamcfg_size(LibCamera *camera, uint32_t idx, uint32_t *width, uint32_t *height);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uint32_t libcamera_get_stride(LibCamera *camera);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void *libcamera_get_ring_buffer_data(LibCamera *camera);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void libcamera_reset_ring_buffer_data(LibCamera *camera);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void libcamera_ringbuffer_read_update(LibCamera *camera);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void libcamera_consume_data(LibCamera *camera);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void libcamera_free_CamData(LibCamera *camera, CamData *p);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void libcamera_free_OutBuf(LibCamera *camera, OutBuf *p);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void libcamera_set_spa_system(LibCamera *camera, struct spa_system *system);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void libcamera_set_eventfd(LibCamera *camera, int fd);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef __cplusplus
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif /* extern "C" */
 | 
					 | 
				
			||||||
#endif /* __LIBCAMERA_WRAPPER_H */
 | 
					 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue