diff --git a/buffer.c b/buffer.c index 0174013..3250f9d 100644 --- a/buffer.c +++ b/buffer.c @@ -11,30 +11,33 @@ buffer_t *buffer_open(const char *name, buffer_list_t *buf_list, int index) { buf->buf_list = buf_list; buf->dma_fd = -1; - if (buf_list->do_mmap) { - buf->v4l2_buffer.type = buf_list->type; - buf->v4l2_buffer.memory = V4L2_MEMORY_MMAP; - buf->v4l2_buffer.index = index; + if (!buf_list->do_mmap) { + // nothing to do here + return buf; + } - if (buf_list->do_mplanes) { - buf->v4l2_buffer.length = 1; - buf->v4l2_buffer.m.planes = &buf->v4l2_plane; - } + buf->v4l2_buffer.type = buf_list->type; + buf->v4l2_buffer.memory = V4L2_MEMORY_MMAP; + buf->v4l2_buffer.index = index; - E_XIOCTL(buf_list, dev->fd, VIDIOC_QUERYBUF, &buf->v4l2_buffer, "Cannot query buffer %d", index); + if (buf_list->do_mplanes) { + buf->v4l2_buffer.length = 1; + buf->v4l2_buffer.m.planes = &buf->v4l2_plane; + } - if (buf_list->do_mplanes) { - buf->offset = buf->v4l2_plane.m.mem_offset; - buf->length = buf->v4l2_plane.length; - } else { - buf->offset = buf->v4l2_buffer.m.offset; - buf->length = buf->v4l2_buffer.length; - } + E_XIOCTL(buf_list, dev->fd, VIDIOC_QUERYBUF, &buf->v4l2_buffer, "Cannot query buffer %d", index); - buf->start = mmap(NULL, buf->length, PROT_READ | PROT_WRITE, MAP_SHARED, dev->fd, buf->offset); - if (buf->start == MAP_FAILED) { - goto error; - } + if (buf_list->do_mplanes) { + buf->offset = buf->v4l2_plane.m.mem_offset; + buf->length = buf->v4l2_plane.length; + } else { + buf->offset = buf->v4l2_buffer.m.offset; + buf->length = buf->v4l2_buffer.length; + } + + buf->start = mmap(NULL, buf->length, PROT_READ | PROT_WRITE, MAP_SHARED, dev->fd, buf->offset); + if (buf->start == MAP_FAILED) { + goto error; } if (buf_list->do_dma) { @@ -46,7 +49,10 @@ buffer_t *buffer_open(const char *name, buffer_list_t *buf_list, int index) { buf->dma_fd = v4l2_exp.fd; } - buffer_capture_enqueue(buf); + // enqueue buffer + buf->used = 0; + buf->mmap_reflinks = 1; + buffer_consumed(buf); return buf; diff --git a/buffer.h b/buffer.h index 649d1e0..182f9c7 100644 --- a/buffer.h +++ b/buffer.h @@ -8,14 +8,17 @@ typedef struct buffer_s { int index; void *start; size_t offset; + size_t used; size_t length; struct v4l2_buffer v4l2_buffer; struct v4l2_plane v4l2_plane; int dma_fd; - bool enqueued; + + int mmap_reflinks; + struct buffer_s *mmap_source; } buffer_t; buffer_t *buffer_open(const char *name, struct buffer_list_s *buf_list, int buffer); void buffer_close(buffer_t *buf); -bool buffer_output_dequeue(buffer_t *buf); -bool buffer_capture_enqueue(buffer_t *buf); + +bool buffer_consumed(buffer_t *buf); diff --git a/buffer_list.c b/buffer_list.c index 546c20d..8a77e37 100644 --- a/buffer_list.c +++ b/buffer_list.c @@ -2,7 +2,7 @@ #include "buffer_list.h" #include "device.h" -buffer_list_t *buffer_list_open(const char *name, struct device_s *dev, unsigned type) +buffer_list_t *buffer_list_open(const char *name, struct device_s *dev, unsigned type, bool do_mmap) { buffer_list_t *buf_list = calloc(1, sizeof(buffer_list_t)); @@ -12,21 +12,23 @@ buffer_list_t *buffer_list_open(const char *name, struct device_s *dev, unsigned switch(type) { case V4L2_BUF_TYPE_VIDEO_OUTPUT: + buf_list->do_mmap = do_mmap; break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + buf_list->do_mmap = do_mmap; buf_list->do_mplanes = true; break; case V4L2_BUF_TYPE_VIDEO_CAPTURE: - buf_list->do_dma = true; - buf_list->do_mmap = true; + buf_list->do_dma = do_mmap; + buf_list->do_mmap = do_mmap; buf_list->do_capture = true; break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - buf_list->do_dma = true; - buf_list->do_mmap = true; + buf_list->do_dma = do_mmap; + buf_list->do_mmap = do_mmap; buf_list->do_mplanes = true; buf_list->do_capture = true; break; @@ -69,27 +71,27 @@ int buffer_list_set_format(buffer_list_t *buf_list, unsigned width, unsigned hei fmt->type = buf_list->type; if (buf_list->do_mplanes) { - fmt->fmt.pix.colorspace = V4L2_COLORSPACE_RAW; - fmt->fmt.pix.width = width; - fmt->fmt.pix.height = height; - fmt->fmt.pix.pixelformat = format; - fmt->fmt.pix.field = V4L2_FIELD_ANY; - fmt->fmt.pix.bytesperline = fourcc_to_stride(width, format); - } else { fmt->fmt.pix_mp.colorspace = V4L2_COLORSPACE_JPEG; fmt->fmt.pix_mp.width = width; fmt->fmt.pix_mp.height = height; fmt->fmt.pix_mp.pixelformat = format; fmt->fmt.pix_mp.field = V4L2_FIELD_ANY; fmt->fmt.pix_mp.num_planes = 1; - fmt->fmt.pix_mp.plane_fmt[0].bytesperline = fourcc_to_stride(width, format); + //fmt->fmt.pix_mp.plane_fmt[0].bytesperline = fourcc_to_stride(width, format); + } else { + fmt->fmt.pix.colorspace = V4L2_COLORSPACE_RAW; + fmt->fmt.pix.width = width; + fmt->fmt.pix.height = height; + fmt->fmt.pix.pixelformat = format; + fmt->fmt.pix.field = V4L2_FIELD_ANY; + fmt->fmt.pix.bytesperline = fourcc_to_stride(width, format); } E_LOG_DEBUG(buf_list, "Configuring format ..."); E_XIOCTL(buf_list, buf_list->device->fd, VIDIOC_S_FMT, fmt, "Can't set format"); if (fmt->fmt.pix.width != width || fmt->fmt.pix.height != height) { - E_LOG_ERROR(buf_list, "Requested resolution=%ux%u is unavailable. Got %ux%u.", + E_LOG_INFO(buf_list, "Requested resolution=%ux%u is unavailable. Got %ux%u.", width, height, fmt->fmt.pix.width, fmt->fmt.pix.height); } @@ -102,6 +104,11 @@ int buffer_list_set_format(buffer_list_t *buf_list, unsigned width, unsigned hei E_LOG_INFO(buf_list, "Using: %ux%u/%s", fmt->fmt.pix.width, fmt->fmt.pix.height, fourcc_to_string(fmt->fmt.pix.pixelformat).buf); + + buf_list->fmt_width = fmt->fmt.pix.width; + buf_list->fmt_height = fmt->fmt.pix.height; + buf_list->fmt_format = fmt->fmt.pix.pixelformat; + return 0; error: diff --git a/buffer_list.h b/buffer_list.h index 1ee2933..4ff5189 100644 --- a/buffer_list.h +++ b/buffer_list.h @@ -14,9 +14,11 @@ typedef struct buffer_list_s { bool do_mmap; bool do_dma; bool do_capture; + + unsigned fmt_width, fmt_height, fmt_format; } buffer_list_t; -buffer_list_t *buffer_list_open(const char *name, struct device_s *dev, unsigned type); +buffer_list_t *buffer_list_open(const char *name, struct device_s *dev, unsigned type, bool do_mmap); void buffer_list_close(buffer_list_t *buf_list); int buffer_list_set_format(buffer_list_t *buffer_list, unsigned width, unsigned height, unsigned format); @@ -24,7 +26,7 @@ int buffer_list_request(buffer_list_t *buf_list, int nbufs); bool buffer_list_wait_pool(buffer_list_t *buf_list, int timeout); -buffer_t *buffer_list_output_enqueue(buffer_list_t *buf_list, buffer_t *dma_buf); -buffer_t *buffer_list_capture_dequeue(buffer_list_t *buf_list); - int buffer_list_stream(buffer_list_t *buf_list, bool do_on); + +buffer_t *buffer_list_mmap_dequeue(buffer_list_t *buf_list); +buffer_t *buffer_list_mmap_enqueue(buffer_list_t *buf_list, buffer_t *dma_buf); diff --git a/buffer_queue.c b/buffer_queue.c index 94664d8..31267bb 100644 --- a/buffer_queue.c +++ b/buffer_queue.c @@ -11,19 +11,37 @@ bool buffer_output_dequeue(buffer_t *buf) return false; } -bool buffer_capture_enqueue(buffer_t *buf) +bool buffer_consumed(buffer_t *buf) { - if (buf->enqueued || !buf->buf_list->do_mmap || !buf->buf_list->do_capture) { - return false; + if (buf->buf_list->do_mmap) { + if (buf->mmap_reflinks <= 0) { + return true; + } + + buf->mmap_reflinks--; + + // update used bytes + if (buf->buf_list->do_mplanes) { + buf->v4l2_plane.bytesused = buf->used; + } else { + buf->v4l2_buffer.bytesused = buf->used; + } + + if (buf->mmap_reflinks == 0) { + E_LOG_DEBUG(buf, "Queuing buffer..."); + E_XIOCTL(buf, buf->buf_list->device->fd, VIDIOC_QBUF, &buf->v4l2_buffer, "Can't queue buffer."); + } + } else { + if (buf->mmap_source) { + buffer_consumed(buf->mmap_source); + buf->mmap_source = NULL; + } } - E_LOG_DEBUG(buf, "Queuing buffer..."); - E_XIOCTL(buf, buf->buf_list->device->fd, VIDIOC_QBUF, &buf->v4l2_buffer, "Can't queue buffer."); - - buf->enqueued = true; + return true; error: - return true; + return false; } buffer_t *buffer_list_output_enqueue(buffer_list_t *buf_list, buffer_t *dma_buf) @@ -49,9 +67,42 @@ buffer_t *buffer_list_output_enqueue(buffer_list_t *buf_list, buffer_t *dma_buf) return NULL; } -buffer_t *buffer_list_capture_dequeue(buffer_list_t *buf_list) +buffer_t *buffer_list_mmap_enqueue(buffer_list_t *buf_list, buffer_t *dma_buf) { - if (!buf_list->do_mmap || !buf_list->do_capture) { + buffer_t *buf = NULL; + + if (!buf_list->do_mmap && !dma_buf->buf_list->do_mmap) { + E_LOG_PERROR(buf_list, "Cannot enqueue non-mmap to non-mmap: %s.", dma_buf->name); + } + + if (!buf_list->do_mmap) { + E_LOG_PERROR(buf_list, "Not yet supported: %s.", dma_buf->name); + } + + buf = buffer_list_mmap_dequeue(buf_list); + if (!buf) { + return NULL; + } + + if (dma_buf->used > buf->length) { + E_LOG_PERROR(buf_list, "The dma_buf (%s) is too long: %zu vs space=%zu", + dma_buf->name, dma_buf->used, buf->length); + } + + E_LOG_DEBUG(buf, "mmap copy: dest=%p, src=%p (%s), size=%zu, space=%zu", + buf->start, dma_buf->start, dma_buf->name, dma_buf->used, buf->length); + memcpy(buf->start, dma_buf->start, dma_buf->used); + buffer_consumed(buf); + + return NULL; + +error: + return NULL; +} + +buffer_t *buffer_list_mmap_dequeue(buffer_list_t *buf_list) +{ + if (!buf_list->do_mmap) { return NULL; } @@ -67,17 +118,21 @@ buffer_t *buffer_list_capture_dequeue(buffer_list_t *buf_list) } E_XIOCTL(buf_list, buf_list->device->fd, VIDIOC_DQBUF, &v4l2_buf, "Can't grab capture buffer"); - E_LOG_DEBUG(buf_list, "Grabbed INPUT buffer=%u, bytes=%d", - v4l2_buf.index, v4l2_buf.length); buffer_t *buf = buf_list->bufs[v4l2_buf.index]; buf->v4l2_plane = v4l2_plane; buf->v4l2_buffer = v4l2_buf; if (buf_list->do_mplanes) { buf->v4l2_buffer.m.planes = &buf->v4l2_plane; + buf->used = buf->v4l2_plane.bytesused; + } else { + buf->used = buf->v4l2_buffer.bytesused; } - buf->enqueued = false; + E_LOG_DEBUG(buf_list, "Grabbed mmap buffer=%u, bytes=%d, used=%d", + buf->index, buf->length, buf->used); + + buf->mmap_reflinks = 1; return buf; diff --git a/camera_stream b/camera_stream index 1dd7eff..77efafa 100755 Binary files a/camera_stream and b/camera_stream differ diff --git a/device.c b/device.c index b4fc1a4..fb91cb4 100644 --- a/device.c +++ b/device.c @@ -53,34 +53,37 @@ int device_open_buffer_list(device_t *dev, bool do_capture, unsigned width, unsi unsigned type; char name[64]; struct buffer_list_s **buf_list = NULL; + bool do_mmap = false; if (do_capture) { buf_list = &dev->capture_list; + do_mmap = true; if (dev->v4l2_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) { type = V4L2_BUF_TYPE_VIDEO_CAPTURE; sprintf(name, "%s:capture", dev->name); - } else if (dev->v4l2_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) { + } else if (dev->v4l2_cap.capabilities & (V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_M2M_MPLANE)) { type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; sprintf(name, "%s:capture:mplane", dev->name); } else { - E_LOG_ERROR(dev, "Video capture is not supported by device"); + E_LOG_ERROR(dev, "Video capture is not supported by device: %08x", dev->v4l2_cap.capabilities); } } else { - buf_list = &dev->capture_list; + buf_list = &dev->output_list; + do_mmap = true; if (dev->v4l2_cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) { type = V4L2_BUF_TYPE_VIDEO_OUTPUT; sprintf(name, "%s:output", dev->name); - } else if (dev->v4l2_cap.capabilities & V4L2_CAP_VIDEO_OUTPUT_MPLANE) { + } else if (dev->v4l2_cap.capabilities & (V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_VIDEO_M2M_MPLANE)) { type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; sprintf(name, "%s:output:mplane", dev->name); } else { - E_LOG_ERROR(dev, "Video output is not supported by device"); + E_LOG_ERROR(dev, "Video output is not supported by device: %08x", dev->v4l2_cap.capabilities); } } - *buf_list = buffer_list_open(name, dev, type); + *buf_list = buffer_list_open(name, dev, type, do_mmap); if (!*buf_list) { goto error; } diff --git a/main.c b/main.c index b5700a1..4fb49bd 100644 --- a/main.c +++ b/main.c @@ -12,6 +12,7 @@ device_t *camera = NULL; device_t *isp_srgb = NULL; device_t *isp_yuuv = NULL; device_t *isp_yuuv_low = NULL; +device_t *codec_jpeg = NULL; int open_camera(const char *path) { @@ -27,7 +28,7 @@ int open_camera(const char *path) return 0; } -int open_isp(const char *srgb_path, const char *yuuv_path, const char *yuuv_low_path) +int open_isp(buffer_list_t *src, const char *srgb_path, const char *yuuv_path, const char *yuuv_low_path) { isp_srgb = device_open("ISP-SRGB", srgb_path); isp_yuuv = device_open("ISP-YUUV", yuuv_path); @@ -37,9 +38,24 @@ int open_isp(const char *srgb_path, const char *yuuv_path, const char *yuuv_low_ return -1; } - if (device_open_buffer_list(isp_srgb, false, camera_width, camera_height, camera_format, camera_nbufs) < 0 || - device_open_buffer_list(isp_yuuv, true, camera_width, camera_height, V4L2_PIX_FMT_YUYV, camera_nbufs) < 0 || - device_open_buffer_list(isp_yuuv, true, camera_width / 2, camera_height / 2, V4L2_PIX_FMT_YUYV, camera_nbufs) < 0) { + if (device_open_buffer_list(isp_srgb, false, src->fmt_width, src->fmt_height, src->fmt_format, camera_nbufs) < 0 || + device_open_buffer_list(isp_yuuv, true, src->fmt_width, src->fmt_height, V4L2_PIX_FMT_YUYV, camera_nbufs) < 0 || + device_open_buffer_list(isp_yuuv_low, true, src->fmt_width / 2, src->fmt_height / 2, V4L2_PIX_FMT_YUYV, camera_nbufs) < 0) { + return -1; + } + + return 0; +} + +int open_jpeg(buffer_list_t *src, const char *jpeg_codec) +{ + codec_jpeg = device_open("JPEG", jpeg_codec); + if (!codec_jpeg) { + return -1; + } + + if (device_open_buffer_list(codec_jpeg, false, src->fmt_width, src->fmt_height, src->fmt_format, camera_nbufs) < 0 || + device_open_buffer_list(codec_jpeg, true, src->fmt_width, src->fmt_height, V4L2_PIX_FMT_JPEG, camera_nbufs) < 0) { return -1; } @@ -51,26 +67,61 @@ int main(int argc, char *argv[]) if (open_camera("/dev/video0") < 0) { goto error; } - - // if (open_isp("/dev/video13", "/dev/video14", "/dev/video15") < 0) { - // goto error; - // } + if (open_isp(camera->capture_list, "/dev/video13", "/dev/video14", "/dev/video15") < 0) { + goto error; + } + if (open_jpeg(isp_yuuv->capture_list, "/dev/video31") < 0) { + goto error; + } // return; if (device_stream(camera, true) < 0) { goto error; } - //return; + if (device_stream(isp_srgb, true) < 0) { + goto error; + } + if (device_stream(isp_yuuv, true) < 0) { + goto error; + } + if (device_stream(isp_yuuv_low, true) < 0) { + goto error; + } + if (device_stream(codec_jpeg, true) < 0) { + goto error; + } while(true) { - if (buffer_list_wait_pool(camera->capture_list, 1000000)) { - buffer_t *buf; - if (buf = buffer_list_capture_dequeue(camera->capture_list)) { - E_LOG_INFO(camera, "Got camera buffer: %p", buf); - buffer_capture_enqueue(buf); + buffer_t *buf; + + if (buffer_list_wait_pool(camera->capture_list, 100)) { + if (buf = buffer_list_mmap_dequeue(camera->capture_list)) { + buffer_list_mmap_enqueue(isp_srgb->output_list, buf); + buffer_consumed(buf); } } + + if (buffer_list_wait_pool(isp_yuuv->capture_list, 100)) { + if (buf = buffer_list_mmap_dequeue(isp_yuuv->capture_list)) { + buffer_list_mmap_enqueue(codec_jpeg->output_list, buf); + buffer_consumed(buf); + } + } + + if (buffer_list_wait_pool(isp_yuuv_low->capture_list, 100)) { + if (buf = buffer_list_mmap_dequeue(isp_yuuv_low->capture_list)) { + buffer_consumed(buf); + } + } + + if (buffer_list_wait_pool(codec_jpeg->capture_list, 100)) { + if (buf = buffer_list_mmap_dequeue(codec_jpeg->capture_list)) { + buffer_consumed(buf); + } + } + + usleep(100*1000); } error: