diff --git a/device/libcamera/buffer.cc b/device/libcamera/buffer.cc index 41dbdf6..87522c6 100644 --- a/device/libcamera/buffer.cc +++ b/device/libcamera/buffer.cc @@ -3,7 +3,7 @@ int libcamera_buffer_open(buffer_t *buf) { buf->libcamera = new buffer_libcamera_t{}; - buf->libcamera->request = buf->buf_list->dev->libcamera->camera->createRequest(); + buf->libcamera->request = buf->buf_list->dev->libcamera->camera->createRequest(buf->index); if (!buf->libcamera->request) { E_LOG_ERROR(buf, "Can't create request"); } @@ -53,15 +53,72 @@ void libcamera_buffer_close(buffer_t *buf) int libcamera_buffer_enqueue(buffer_t *buf, const char *who) { + auto &request = buf->libcamera->request; + auto const &camera = buf->buf_list->dev->libcamera->camera; + + request->reuse(libcamera::Request::ReuseBuffers); + + // TODO: assign timestamps + // for (auto const &pair : request->buffers()) { + // v4l2_buf.timestamp.tv_sec = buf->captured_time_us / (1000LL * 1000LL); + // v4l2_buf.timestamp.tv_usec = buf->captured_time_us % (1000LL * 1000LL); + // } + + if (buf->buf_list->dev->libcamera->camera->queueRequest(buf->libcamera->request.get()) < 0) { + E_LOG_ERROR(buf, "Can't queue buffer."); + } + return 0; + +error: return -1; } +void buffer_list_libcamera_t::libcamera_buffer_list_dequeued(libcamera::Request *request) +{ + E_LOG_INFO(buf_list, "Dequeued: index=%d, status=%d", request->cookie(), request->status()); + + if (request->status() == libcamera::Request::RequestComplete) { + unsigned index = request->cookie(); + if (write(buf_list->libcamera->fds[1], &index, sizeof(index)) == sizeof(index)) { + return; + } + } + + // put back into queue, as it failed + buf_list->dev->libcamera->camera->queueRequest(request); +} + int libcamera_buffer_list_dequeue(buffer_list_t *buf_list, buffer_t **bufp) { - return -1; + unsigned index = 0; + int n = read(buf_list->libcamera->fds[0], &index, sizeof(index)); + if (n != sizeof(index)) { + E_LOG_INFO(buf_list, "Received invalid result from `read`: %d", n); + return -1; + } + + if (index >= buf_list->nbufs) { + E_LOG_INFO(buf_list, "Received invalid index from `read`: %d >= %d", index, buf_list->nbufs); + return -1; + } + + *bufp = buf_list->bufs[index]; + + // TODO: fix timestamps + // buf->v4l2->flags = v4l2_buf.flags; + // buf->flags.is_keyframe = (v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) != 0; + // buf->captured_time_us = get_time_us(CLOCK_FROM_PARAMS, NULL, &v4l2_buf.timestamp, 0); + return 0; } int libcamera_buffer_list_pollfd(buffer_list_t *buf_list, struct pollfd *pollfd, bool can_dequeue) { - return -1; + int count_enqueued = buffer_list_count_enqueued(buf_list); + pollfd->fd = buf_list->libcamera->fds[0]; // write end + pollfd->events = POLLHUP; + if (can_dequeue && count_enqueued > 0) { + pollfd->events |= POLLIN; + } + pollfd->revents = 0; + return 0; } diff --git a/device/libcamera/buffer_list.cc b/device/libcamera/buffer_list.cc index 8fd5763..826117d 100644 --- a/device/libcamera/buffer_list.cc +++ b/device/libcamera/buffer_list.cc @@ -15,9 +15,18 @@ int libcamera_buffer_list_open(buffer_list_t *buf_list, unsigned width, unsigned } buf_list->libcamera = new buffer_list_libcamera_t{}; + buf_list->libcamera->buf_list = buf_list; + buf_list->libcamera->fds[0] = -1; + buf_list->libcamera->fds[1] = -1; + + if (pipe2(buf_list->libcamera->fds, O_DIRECT|O_CLOEXEC) < 0) { + E_LOG_INFO(buf_list, "Cannot open `pipe2`."); + return -1; + } + buf_list->libcamera->configuration = buf_list->dev->libcamera->camera->generateConfiguration( { libcamera::StreamRole::Viewfinder }); - + auto &configuration = buf_list->libcamera->configuration->at(0); configuration.size = libcamera::Size(width, height); configuration.pixelFormat = libcamera::PixelFormat(format); @@ -64,6 +73,9 @@ error: void libcamera_buffer_list_close(buffer_list_t *buf_list) { if (buf_list->libcamera) { + close(buf_list->libcamera->fds[0]); + close(buf_list->libcamera->fds[1]); + delete buf_list->libcamera; buf_list->libcamera = NULL; } @@ -72,10 +84,16 @@ void libcamera_buffer_list_close(buffer_list_t *buf_list) int libcamera_buffer_list_set_stream(buffer_list_t *buf_list, bool do_on) { if (do_on) { + buf_list->dev->libcamera->camera->requestCompleted.connect( + buf_list->libcamera, &buffer_list_libcamera_t::libcamera_buffer_list_dequeued); + if (buf_list->dev->libcamera->camera->start() < 0) { E_LOG_ERROR(buf_list, "Failed to start camera."); } } else { + buf_list->dev->libcamera->camera->requestCompleted.disconnect( + buf_list->libcamera, &buffer_list_libcamera_t::libcamera_buffer_list_dequeued); + if (buf_list->dev->libcamera->camera->stop() < 0) { E_LOG_ERROR(buf_list, "Failed to stop camera."); } diff --git a/device/libcamera/libcamera.hh b/device/libcamera/libcamera.hh index 7eda839..460dcff 100644 --- a/device/libcamera/libcamera.hh +++ b/device/libcamera/libcamera.hh @@ -42,6 +42,10 @@ typedef struct device_libcamera_s { typedef struct buffer_list_libcamera_s { std::shared_ptr configuration; std::shared_ptr allocator; + buffer_list_t *buf_list; + int fds[2]; + + void libcamera_buffer_list_dequeued(libcamera::Request *request); } buffer_list_libcamera_t; typedef struct buffer_libcamera_s { @@ -58,6 +62,7 @@ int libcamera_device_set_option(device_t *dev, const char *key, const char *valu int libcamera_buffer_open(buffer_t *buf); void libcamera_buffer_close(buffer_t *buf); int libcamera_buffer_enqueue(buffer_t *buf, const char *who); +void libcamera_buffer_list_dequeued(buffer_list_t *buf_list, libcamera::Request *request); int libcamera_buffer_list_dequeue(buffer_list_t *buf_list, buffer_t **bufp); int libcamera_buffer_list_pollfd(buffer_list_t *buf_list, struct pollfd *pollfd, bool can_dequeue);