diff --git a/spa/plugins/libcamera/libcamera-source.cpp b/spa/plugins/libcamera/libcamera-source.cpp index b071dd1bd..15446d6fd 100644 --- a/spa/plugins/libcamera/libcamera-source.cpp +++ b/spa/plugins/libcamera/libcamera-source.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -39,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -52,6 +54,8 @@ #include #include #include +#include +#include #include "libcamera.h" #include "libcamera-manager.hpp" @@ -66,7 +70,8 @@ static void reset_props(struct props *props) spa_zero(*props); } -#define MAX_BUFFERS 32 +#define MAX_BUFFERS 32 +#define MASK_BUFFERS 31 #define BUFFER_FLAG_OUTSTANDING (1<<0) #define BUFFER_FLAG_ALLOCATED (1<<1) @@ -95,6 +100,7 @@ struct port { bool have_format; struct spa_video_info current_format; struct spa_fraction rate; + StreamConfiguration streamConfig; uint32_t memtype; @@ -104,8 +110,8 @@ struct port { struct buffer buffers[MAX_BUFFERS]; uint32_t n_buffers; struct spa_list queue; - - struct spa_source source; + struct spa_ringbuffer ring; + uint32_t ring_ids[MAX_BUFFERS]; uint64_t info_all; struct spa_port_info info; @@ -123,7 +129,6 @@ struct port { struct impl { struct spa_handle handle; struct spa_node node; - bool have_source; struct spa_log *log; struct spa_loop *data_loop; @@ -145,13 +150,23 @@ struct impl { CameraManager *manager; std::shared_ptr camera; + FrameBufferAllocator *allocator; + std::vector> requestPool; + std::deque pendingRequests; + + void requestComplete(libcamera::Request *request); + unsigned int have_config; std::unique_ptr config; + struct spa_source source; + unsigned int active:1; unsigned int acquired:1; }; +typedef struct impl Impl; + #define CHECK_PORT(impl,direction,port_id) ((direction) == SPA_DIRECTION_OUTPUT && (port_id) == 0) #define GET_OUT_PORT(impl,p) (&impl->out_ports[p]) @@ -409,15 +424,12 @@ static int impl_node_remove_port(void *object, return -ENOTSUP; } -static int port_get_format(void *object, - enum spa_direction direction, uint32_t port_id, +static int port_get_format(struct impl *impl, struct port *port, uint32_t index, const struct spa_pod *filter, struct spa_pod **param, 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; if (!port->have_format) @@ -492,14 +504,13 @@ next: switch (id) { 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: - 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: - if((res = port_get_format(impl, direction, port_id, - result.index, filter, ¶m, &b)) <= 0) + if((res = port_get_format(impl, port, result.index, filter, ¶m, &b)) <= 0) return res; break; 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 * so that exact number of buffers are allocated */ -// uint32_t n_buffers = libcamera_get_nbuffers(port->dev.camera); - uint32_t n_buffers = 0; + uint32_t n_buffers = port->streamConfig.bufferCount; param = (struct spa_pod*)spa_pod_builder_add_object(&b, SPA_TYPE_OBJECT_ParamBuffers, id, 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_size, SPA_POD_Int(0), - SPA_PARAM_BUFFERS_stride, SPA_POD_Int(0), + SPA_PARAM_BUFFERS_size, SPA_POD_Int(port->streamConfig.frameSize), + SPA_PARAM_BUFFERS_stride, SPA_POD_Int(port->streamConfig.stride), SPA_PARAM_BUFFERS_align, SPA_POD_Int(16)); break; } @@ -575,14 +585,10 @@ next: return 0; } -static int port_set_format(void *object, - enum spa_direction direction, uint32_t port_id, - uint32_t flags, - const struct spa_pod *format) +static int port_set_format(struct impl *impl, struct port *port, + uint32_t flags, const struct spa_pod *format) { - struct impl *impl = (struct impl*)object; struct spa_video_info info; - struct port *port = GET_PORT(impl, direction, port_id); int res; if (format == NULL) { @@ -590,7 +596,7 @@ static int port_set_format(void *object, return 0; spa_libcamera_stream_off(impl); - spa_libcamera_clear_buffers(impl); + spa_libcamera_clear_buffers(impl, port); port->have_format = false; 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)) { - spa_libcamera_use_buffers(impl, NULL, 0); + spa_libcamera_use_buffers(impl, port, NULL, 0); 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; 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, 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(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) { - return port_set_format(object, direction, port_id, flags, param); + switch (id) { + case SPA_PARAM_Format: + res = port_set_format(impl, port, flags, param); + break; + default: + res = -ENOENT; } - else - return -ENOENT; + return res; } 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) { spa_libcamera_stream_off(impl); - if ((res = spa_libcamera_clear_buffers(impl)) < 0) + if ((res = spa_libcamera_clear_buffers(impl, port)) < 0) return res; } if (buffers == NULL) return 0; 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 { - res = spa_libcamera_use_buffers(impl, buffers, n_buffers); + res = spa_libcamera_use_buffers(impl, port, buffers, n_buffers); } 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); - res = spa_libcamera_buffer_recycle(impl, buffer_id); + res = spa_libcamera_buffer_recycle(impl, port, buffer_id); return res; } 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) @@ -825,7 +837,7 @@ static int impl_node_process(void *object) } 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; 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) { struct impl *impl; - struct port *port; impl = (struct impl *) handle; - port = GET_OUT_PORT(impl, 0); - - if(impl->have_source) { - spa_system_close(impl->system, port->source.fd); - impl->have_source = false; - } + impl->~Impl(); 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(handle != NULL, -EINVAL); + impl = new(handle) Impl(); + handle->get_interface = impl_get_interface; handle->clear = impl_clear; - impl = (struct impl *) handle; - impl->log = (struct spa_log*)spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); libcamera_log_topic_init(impl->log); diff --git a/spa/plugins/libcamera/libcamera-utils.cpp b/spa/plugins/libcamera/libcamera-utils.cpp index 74d8c8b54..ce74fab82 100644 --- a/spa/plugins/libcamera/libcamera-utils.cpp +++ b/spa/plugins/libcamera/libcamera-utils.cpp @@ -40,6 +40,9 @@ int spa_libcamera_open(struct impl *impl) if (impl->acquired) return 0; impl->camera->acquire(); + + impl->allocator = new FrameBufferAllocator(impl->camera); + impl->acquired = true; return 0; } @@ -51,7 +54,12 @@ int spa_libcamera_close(struct impl *impl) return 0; if (impl->active || port->have_format) return 0; + + delete impl->allocator; + impl->allocator = nullptr; + impl->camera->release(); + impl->acquired = false; return 0; } @@ -67,21 +75,69 @@ static void spa_libcamera_get_config(struct impl *impl) 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]; + int res; if (!SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_OUTSTANDING)) return 0; 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; } -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 = 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; 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)) { 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)) { 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; } + freeBuffers(impl, port); port->n_buffers = 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, - uint32_t subtype, - uint32_t format, - int startidx) + uint32_t subtype, uint32_t format, int startidx) { size_t i; @@ -182,11 +237,9 @@ static const struct format_info *find_format_info_by_media_type(uint32_t type, } static int -spa_libcamera_enum_format(struct impl *impl, int seq, - uint32_t start, uint32_t num, - const struct spa_pod *filter) +spa_libcamera_enum_format(struct impl *impl, struct port *port, int seq, + uint32_t start, uint32_t num, const struct spa_pod *filter) { - struct port *port = &impl->out_ports[0]; int res; const struct format_info *info; uint8_t buffer[1024]; @@ -298,13 +351,14 @@ next_fmt: 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; uint32_t video_format; struct spa_rectangle *size = NULL; struct spa_fraction *framerate = NULL; + CameraConfiguration::Status validation; int res; 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.size.width = size->width; streamConfig.size.height = size->height; + streamConfig.bufferCount = 8; - if (impl->config->validate() == CameraConfiguration::Invalid) + validation = impl->config->validate(); + if (validation == CameraConfiguration::Invalid) return -EINVAL; + if (try_only) + return 0; + if ((res = spa_libcamera_open(impl)) < 0) return res; @@ -352,6 +411,11 @@ static int spa_libcamera_set_format(struct impl *impl, struct spa_video_info *fo if (res != 0) goto error; + port->streamConfig = impl->config->at(0); + + if ((res = allocBuffers(impl, port, port->streamConfig.bufferCount)) < 0) + return res; + port->have_format = true; port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS | SPA_PORT_CHANGE_MASK_RATE; @@ -369,127 +433,26 @@ error: } 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, const struct spa_pod *filter) { 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) { struct impl *impl = (struct impl*) source->data; struct spa_io_buffers *io; struct port *port = &impl->out_ports[0]; + uint32_t index, buffer_id; struct buffer *b; uint64_t cnt; 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); - if (port->source.loop) - spa_loop_remove_source(impl->data_loop, &port->source); + if (impl->source.loop) + spa_loop_remove_source(impl->data_loop, &impl->source); return; } @@ -498,25 +461,25 @@ static void libcamera_on_fd_events(struct spa_source *source) 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"); return; } - if (mmap_read(impl) < 0) { - spa_log_debug(impl->log, "%s:: mmap_read failure", __FUNCTION__); + if (spa_ringbuffer_get_read_index(&port->ring, &index) < 1) { + spa_log_error(impl->log, "nothing is queued"); return; } + buffer_id = port->ring_ids[index & MASK_BUFFERS]; + spa_ringbuffer_read_update(&port->ring, index + 1); - if (spa_list_is_empty(&port->queue)) { - spa_log_debug(impl->log, "Exiting %s as spa list is empty", __FUNCTION__); - return; - } + b = &port->buffers[buffer_id]; + spa_list_append(&port->queue, &b->link); io = port->io; if (io != NULL && io->status != SPA_STATUS_HAVE_DATA) { 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); 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); } -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 - 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; + return -ENOTSUP; } static int -mmap_init(struct impl *impl, +mmap_init(struct impl *impl, struct port *port, struct spa_buffer **buffers, uint32_t n_buffers) { -#if 0 - struct port *port = &impl->out_ports[0]; unsigned int i, j; struct spa_data *d; + Stream *stream = impl->config->at(0).stream(); + const std::vector> &bufs = + impl->allocator->buffers(stream); spa_log_info(impl->log, "In mmap_init()"); if (n_buffers > 0) { + if (bufs.size() != n_buffers) + return -EINVAL; + d = buffers[0]->datas; if (d[0].type != SPA_ID_INVALID && @@ -642,10 +530,7 @@ mmap_init(struct impl *impl, } } - /* get n_buffers from libcamera */ - uint32_t libcamera_nbuffers = libcamera_get_nbuffers(port->dev.camera); - - for (i = 0; i < libcamera_nbuffers; i++) { + for (i = 0; i < n_buffers; i++) { struct buffer *b; if (buffers[i]->n_datas < 1) { @@ -657,22 +542,22 @@ mmap_init(struct impl *impl, 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)); + b->h = (struct spa_meta_header*)spa_buffer_find_meta_data(buffers[i], SPA_META_Header, sizeof(*b->h)); d = buffers[i]->datas; for(j = 0; j < buffers[i]->n_datas; ++j) { d[j].type = port->memtype; d[j].flags = SPA_DATA_FLAG_READABLE; 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->size = 0; - d[j].chunk->stride = port->fmt.bytesperline; /* FIXME:: This needs to be appropriately filled */ + d[j].chunk->size = port->streamConfig.frameSize; + d[j].chunk->stride = port->streamConfig.stride; d[j].chunk->flags = 0; if (port->memtype == SPA_DATA_DmaBuf || 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); d[j].data = NULL; SPA_FLAG_SET(b->flags, BUFFER_FLAG_ALLOCATED); @@ -680,10 +565,10 @@ mmap_init(struct impl *impl, else if(port->memtype == SPA_DATA_MemPtr) { 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); + d[j].maxsize + d[j].mapoffset, + PROT_READ, MAP_SHARED, + bufs[i]->planes()[j].fd.fd(), + 0); if (d[j].data == MAP_FAILED) { spa_log_error(impl->log, "mmap: %m"); continue; @@ -696,35 +581,89 @@ mmap_init(struct impl *impl, return -EIO; } } - - spa_libcamera_buffer_recycle(impl, i); + spa_libcamera_buffer_recycle(impl, port, i); } - port->n_buffers = libcamera_nbuffers; -#endif + port->n_buffers = n_buffers; + spa_log_info(impl->log, "we have %d buffers", n_buffers); + return 0; } static int -spa_libcamera_alloc_buffers(struct impl *impl, +spa_libcamera_alloc_buffers(struct impl *impl, struct port *port, struct spa_buffer **buffers, uint32_t n_buffers) { int res; - struct port *port = &impl->out_ports[0]; + + spa_log_info(impl->log, ". %d", port->n_buffers); if (port->n_buffers > 0) return -EIO; - if ((res = mmap_init(impl, buffers, n_buffers)) < 0) { - return -EIO; - } + if ((res = mmap_init(impl, port, buffers, n_buffers)) < 0) + return res; 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) { struct port *port = &impl->out_ports[0]; + int res; if (!port->have_format) { 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"); -// 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; - port->source.data = impl; - port->source.fd = spa_system_eventfd_create(impl->system, SPA_FD_CLOEXEC | SPA_FD_NONBLOCK); - 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; + for (Request *req : impl->pendingRequests) { + if ((res = impl->camera->queueRequest(req)) < 0) + return res == -EACCES ? -EBUSY : res; + } + impl->pendingRequests.clear(); -// libcamera_set_spa_system(dev->camera, impl->system); -// libcamera_set_eventfd(dev->camera, port->source.fd); + 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; @@ -767,28 +709,39 @@ static int do_remove_source(struct spa_loop *loop, size_t size, void *user_data) { - struct port *port = (struct port *)user_data; - if (port->source.loop) - spa_loop_remove_source(loop, &port->source); + struct impl *impl = (struct impl *)user_data; + if (impl->source.loop) + spa_loop_remove_source(loop, &impl->source); return 0; } static int spa_libcamera_stream_off(struct impl *impl) { struct port *port = &impl->out_ports[0]; + int res; - if (!impl->active) + if (!impl->active) { + for (std::unique_ptr &req : impl->requestPool) + req->reuse(); return 0; + } 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"); -// 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); impl->active = false; diff --git a/spa/plugins/libcamera/libcamera_wrapper.cpp b/spa/plugins/libcamera/libcamera_wrapper.cpp deleted file mode 100644 index 997fe4c45..000000000 --- a/spa/plugins/libcamera/libcamera_wrapper.cpp +++ /dev/null @@ -1,926 +0,0 @@ -/* Spa libcamera support - * - * Copyright (C) 2020, Collabora Ltd. - * Author: Raghavendra Rao Sidlagatta - * - * 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 -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -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 cm_; - std::shared_ptr cam_; - std::unique_ptr config_; - FrameBufferAllocator *allocator_; - std::map streamName_; - std::vector> 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 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 &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 LibCamera::get_camera() { - std::string camName = this->choose_camera(); - std::shared_ptr 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 &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 &buffer : this->allocator_->buffers(stream)) { - std::unique_ptr 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 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 : 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 cm = std::make_unique(); - 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 &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 = camera->cam_->createRequest(); - ControlList &controls = request->controls(); - res = camera->set_control(controls, control_id, value); - camera->cam_->queueRequest(request.get()); - - return res; - } -} diff --git a/spa/plugins/libcamera/libcamera_wrapper.h b/spa/plugins/libcamera/libcamera_wrapper.h deleted file mode 100644 index 997575c28..000000000 --- a/spa/plugins/libcamera/libcamera_wrapper.h +++ /dev/null @@ -1,132 +0,0 @@ -/* Spa libcamera support - * - * Copyright (C) 2020, Collabora Ltd. - * Author: Raghavendra Rao Sidlagatta - * - * 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 */ \ No newline at end of file