diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/camera/veyeimx287m.cpp | 438 | ||||
| -rw-r--r-- | src/camera/veyeimx287m.h | 17 | ||||
| -rw-r--r-- | src/constants.h | 4 | ||||
| -rw-r--r-- | src/image.cpp | 8 | ||||
| -rw-r--r-- | src/image.h | 7 | ||||
| -rw-r--r-- | src/imagealgos.cpp | 6 | ||||
| -rw-r--r-- | src/main.cpp | 189 |
7 files changed, 566 insertions, 103 deletions
diff --git a/src/camera/veyeimx287m.cpp b/src/camera/veyeimx287m.cpp index e89442c..1f9bc20 100644 --- a/src/camera/veyeimx287m.cpp +++ b/src/camera/veyeimx287m.cpp @@ -20,6 +20,159 @@ #include "pixels.h" // #include "rotaryencoder.h" +static const struct v4l2_format_info +{ + const char *name; + unsigned int fourcc; + unsigned char n_planes; +} pixel_formats[] = { + {"RGB332", V4L2_PIX_FMT_RGB332, 1}, + {"RGB444", V4L2_PIX_FMT_RGB444, 1}, + {"ARGB444", V4L2_PIX_FMT_ARGB444, 1}, + {"XRGB444", V4L2_PIX_FMT_XRGB444, 1}, + {"RGB555", V4L2_PIX_FMT_RGB555, 1}, + {"ARGB555", V4L2_PIX_FMT_ARGB555, 1}, + {"XRGB555", V4L2_PIX_FMT_XRGB555, 1}, + {"RGB565", V4L2_PIX_FMT_RGB565, 1}, + {"RGB555X", V4L2_PIX_FMT_RGB555X, 1}, + {"RGB565X", V4L2_PIX_FMT_RGB565X, 1}, + {"BGR666", V4L2_PIX_FMT_BGR666, 1}, + {"BGR24", V4L2_PIX_FMT_BGR24, 1}, + {"RGB24", V4L2_PIX_FMT_RGB24, 1}, + {"BGR32", V4L2_PIX_FMT_BGR32, 1}, + {"ABGR32", V4L2_PIX_FMT_ABGR32, 1}, + {"XBGR32", V4L2_PIX_FMT_XBGR32, 1}, + {"RGB32", V4L2_PIX_FMT_RGB32, 1}, + {"ARGB32", V4L2_PIX_FMT_ARGB32, 1}, + {"XRGB32", V4L2_PIX_FMT_XRGB32, 1}, + {"HSV24", V4L2_PIX_FMT_HSV24, 1}, + {"HSV32", V4L2_PIX_FMT_HSV32, 1}, + {"Y8", V4L2_PIX_FMT_GREY, 1}, + {"Y10", V4L2_PIX_FMT_Y10, 1}, + {"Y12", V4L2_PIX_FMT_Y12, 1}, + {"Y16", V4L2_PIX_FMT_Y16, 1}, + {"UYVY", V4L2_PIX_FMT_UYVY, 1}, + {"VYUY", V4L2_PIX_FMT_VYUY, 1}, + {"YUYV", V4L2_PIX_FMT_YUYV, 1}, + {"YVYU", V4L2_PIX_FMT_YVYU, 1}, + {"YUV32", V4L2_PIX_FMT_YUV32, 1}, + {"AYUV32", V4L2_PIX_FMT_AYUV32, 1}, + {"XYUV32", V4L2_PIX_FMT_XYUV32, 1}, + {"VUYA32", V4L2_PIX_FMT_VUYA32, 1}, + {"VUYX32", V4L2_PIX_FMT_VUYX32, 1}, + {"YUVA32", V4L2_PIX_FMT_YUVA32, 1}, + {"YUVX32", V4L2_PIX_FMT_YUVX32, 1}, + {"NV12", V4L2_PIX_FMT_NV12, 1}, + {"NV12M", V4L2_PIX_FMT_NV12M, 2}, + {"NV21", V4L2_PIX_FMT_NV21, 1}, + {"NV21M", V4L2_PIX_FMT_NV21M, 2}, + {"NV16", V4L2_PIX_FMT_NV16, 1}, + {"NV16M", V4L2_PIX_FMT_NV16M, 2}, + {"NV61", V4L2_PIX_FMT_NV61, 1}, + {"NV61M", V4L2_PIX_FMT_NV61M, 2}, + {"NV24", V4L2_PIX_FMT_NV24, 1}, + {"NV42", V4L2_PIX_FMT_NV42, 1}, + {"YUV420M", V4L2_PIX_FMT_YUV420M, 3}, + {"YUV422M", V4L2_PIX_FMT_YUV422M, 3}, + {"YUV444M", V4L2_PIX_FMT_YUV444M, 3}, + {"YVU420M", V4L2_PIX_FMT_YVU420M, 3}, + {"YVU422M", V4L2_PIX_FMT_YVU422M, 3}, + {"YVU444M", V4L2_PIX_FMT_YVU444M, 3}, + {"SBGGR8", V4L2_PIX_FMT_SBGGR8, 1}, + {"SGBRG8", V4L2_PIX_FMT_SGBRG8, 1}, + {"SGRBG8", V4L2_PIX_FMT_SGRBG8, 1}, + {"SRGGB8", V4L2_PIX_FMT_SRGGB8, 1}, + {"SBGGR10_DPCM8", V4L2_PIX_FMT_SBGGR10DPCM8, 1}, + {"SGBRG10_DPCM8", V4L2_PIX_FMT_SGBRG10DPCM8, 1}, + {"SGRBG10_DPCM8", V4L2_PIX_FMT_SGRBG10DPCM8, 1}, + {"SRGGB10_DPCM8", V4L2_PIX_FMT_SRGGB10DPCM8, 1}, + {"SBGGR10", V4L2_PIX_FMT_SBGGR10, 1}, + {"SGBRG10", V4L2_PIX_FMT_SGBRG10, 1}, + {"SGRBG10", V4L2_PIX_FMT_SGRBG10, 1}, + {"SRGGB10", V4L2_PIX_FMT_SRGGB10, 1}, + {"SBGGR10P", V4L2_PIX_FMT_SBGGR10P, 1}, + {"SGBRG10P", V4L2_PIX_FMT_SGBRG10P, 1}, + {"SGRBG10P", V4L2_PIX_FMT_SGRBG10P, 1}, + {"SRGGB10P", V4L2_PIX_FMT_SRGGB10P, 1}, + {"SBGGR12", V4L2_PIX_FMT_SBGGR12, 1}, + {"SGBRG12", V4L2_PIX_FMT_SGBRG12, 1}, + {"SGRBG12", V4L2_PIX_FMT_SGRBG12, 1}, + {"SRGGB12", V4L2_PIX_FMT_SRGGB12, 1}, + {"SBGGR16", V4L2_PIX_FMT_SBGGR16, 1}, + {"SGBRG16", V4L2_PIX_FMT_SGBRG16, 1}, + {"SGRBG16", V4L2_PIX_FMT_SGRBG16, 1}, + {"SRGGB16", V4L2_PIX_FMT_SRGGB16, 1}, + {"IPU3_SBGGR10", V4L2_PIX_FMT_IPU3_SBGGR10, 1}, + {"IPU3_SGBRG10", V4L2_PIX_FMT_IPU3_SGBRG10, 1}, + {"IPU3_SGRBG10", V4L2_PIX_FMT_IPU3_SGRBG10, 1}, + {"IPU3_SRGGB10", V4L2_PIX_FMT_IPU3_SRGGB10, 1}, + {"IPU3_Y10", V4L2_PIX_FMT_IPU3_Y10, 1}, + {"DV", V4L2_PIX_FMT_DV, 1}, + {"MJPEG", V4L2_PIX_FMT_MJPEG, 1}, + {"MPEG", V4L2_PIX_FMT_MPEG, 1}, +}; + +static const struct +{ + const char *name; + enum v4l2_field field; +} fields[] = { + {"any", V4L2_FIELD_ANY}, + {"none", V4L2_FIELD_NONE}, + {"top", V4L2_FIELD_TOP}, + {"bottom", V4L2_FIELD_BOTTOM}, + {"interlaced", V4L2_FIELD_INTERLACED}, + {"seq-tb", V4L2_FIELD_SEQ_TB}, + {"seq-bt", V4L2_FIELD_SEQ_BT}, + {"alternate", V4L2_FIELD_ALTERNATE}, + {"interlaced-tb", V4L2_FIELD_INTERLACED_TB}, + {"interlaced-bt", V4L2_FIELD_INTERLACED_BT}, +}; + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +static const char *v4l2_field_name(enum v4l2_field field) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(fields); ++i) { + if (fields[i].field == field) + return fields[i].name; + } + + return "unknown"; +} + +static const struct v4l2_format_info *v4l2_format_by_fourcc(unsigned int fourcc) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(pixel_formats); ++i) { + if (pixel_formats[i].fourcc == fourcc) + return &pixel_formats[i]; + } + + return NULL; +} +static const char *v4l2_format_name(unsigned int fourcc) +{ + const struct v4l2_format_info *info; + static char name[5]; + unsigned int i; + + info = v4l2_format_by_fourcc(fourcc); + if (info) + return info->name; + + for (i = 0; i < 4; ++i) { + name[i] = fourcc & 0xff; + fourcc >>= 8; + } + + name[4] = '\0'; + return name; +} + #define LOGD(...) \ do { \ printf(__VA_ARGS__); \ @@ -52,16 +205,26 @@ VeyeIMX287m::~VeyeIMX287m() m_streamThread.request_stop(); m_streamThread.join(); - int buffer_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (ioctl(m_cam_fd, VIDIOC_STREAMOFF, &buffer_type) == -1) { + // int buffer_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + const auto radxa_buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + // if (ioctl(m_cam_fd, VIDIOC_STREAMOFF, &buffer_type) == -1) { + if (ioctl(m_cam_fd, VIDIOC_STREAMOFF, &radxa_buf_type) == -1) { std::cout << "cannot stop stream" << std::endl; } +#ifdef RADXA_ZERO_3E + for (const auto buffer : buffers) { + if (munmap(buffer.mem[0], radxa_raw_img_size) < 0) { + DBG("Munmap failed!!."); + } + } +#else for (const auto buffer : m_videoBuffers) { if (munmap(buffer, img_size) < 0) { DBG("Munmap failed!!."); } } +#endif // RADXA_ZERO_3E if (m_cam_fd >= 0) { if (close(m_cam_fd) == -1) { @@ -110,14 +273,19 @@ std::vector<std::shared_ptr<ICamera> > VeyeIMX287m::search() bool VeyeIMX287m::startStream() { - int buffer_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - auto ret = ioctl(m_cam_fd, VIDIOC_STREAMON, &buffer_type); + // int buffer_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + const auto radxa_buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + // auto ret = ioctl(m_cam_fd, VIDIOC_STREAMON, &buffer_type); + auto ret = ioctl(m_cam_fd, VIDIOC_STREAMON, &radxa_buf_type); if (ret != 0) { - DBG("ioctl(VIDIOC_STREAMON) failed %d(%s)", errno, strerror(errno)); + std::cerr << "ioctl(VIDIOC_STREAMON) failed: " << errno << " (" << strerror(errno) << ")" + << std::endl; return false; } + std::cout << "stream started" << std::endl; + // m_streamThread = std::jthread{&VeyeIMX287m::dequeueFrameLoop, this}; for (auto &t : m_calcThreads) { @@ -132,8 +300,8 @@ bool VeyeIMX287m::init() if (!openCam()) return false; - if (!selectCam()) - return false; + // if (!selectCam()) + // return false; if (!initCam()) return false; @@ -198,6 +366,10 @@ bool VeyeIMX287m::setSomething(int value) bool VeyeIMX287m::setCamParam(unsigned int v4l2controlId, int value) { + std::cout << "radxa: skip setCamParam" << std::endl; + + return true; + v4l2_control ctl{v4l2controlId, value}; if (ioctl(m_cam_fd, VIDIOC_S_CTRL, &ctl) < 0) { @@ -254,37 +426,87 @@ bool VeyeIMX287m::selectCam(int camIdx) bool VeyeIMX287m::initCam() { - v4l2_format format; - memset(&format, 0, sizeof(v4l2_format)); - format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - format.fmt.pix.pixelformat = V4L2_PIX_FMT_GREY; - format.fmt.pix.width = img_width; - format.fmt.pix.height = img_height; + int ret{-1}; + constexpr bool radxa_zero_3et{true}; - int ret = ioctl(m_cam_fd, VIDIOC_TRY_FMT, &format); + const auto radxa_buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - if (ret < 0) { - fprintf(stderr, "cannot try cam format: error - '%s'\n", strerror(errno)); + if constexpr (!radxa_zero_3et) { + v4l2_format format; + memset(&format, 0, sizeof(v4l2_format)); + format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + format.fmt.pix.pixelformat = V4L2_PIX_FMT_GREY; + format.fmt.pix.width = img_width; + format.fmt.pix.height = img_height; + + ret = ioctl(m_cam_fd, VIDIOC_TRY_FMT, &format); + + if (ret < 0) { + fprintf(stderr, "cannot try cam format: error - '%s'\n", strerror(errno)); + + return false; + } + + // TODO: remove this? + format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + ret = ioctl(m_cam_fd, VIDIOC_S_FMT, &format); + + if (ret < 0) { + fprintf(stderr, "cannot set cam format: error - '%s'\n", strerror(errno)); + + return false; + } + } + + v4l2_format fmt; + memset(&fmt, 0, sizeof fmt); + fmt.type = radxa_buf_type; + + if (ioctl(m_cam_fd, VIDIOC_G_FMT, &fmt) < 0) { + printf("Unable to get format: %s (%d).\n", strerror(errno), errno); return false; } - // TODO: remove this? - format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + const auto width = fmt.fmt.pix_mp.width; + const auto height = fmt.fmt.pix_mp.height; + const int num_planes = fmt.fmt.pix_mp.num_planes; - ret = ioctl(m_cam_fd, VIDIOC_S_FMT, &format); + std::cout << "num_planes: " << num_planes << std::endl; - if (ret < 0) { - fprintf(stderr, "cannot set cam format: error - '%s'\n", strerror(errno)); + if (num_planes != 1) { + std::cerr << "multiple planes are not supported" << std::endl; return false; } - struct v4l2_requestbuffers request; - request.count = BUFFER_COUNT; - request.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - request.memory = V4L2_MEMORY_MMAP; - ret = ioctl(m_cam_fd, VIDIOC_REQBUFS, &request); + printf("Video format: %s (%08x) %ux%u field %s, %u planes: \n", + v4l2_format_name(fmt.fmt.pix_mp.pixelformat), + fmt.fmt.pix_mp.pixelformat, + fmt.fmt.pix_mp.width, + fmt.fmt.pix_mp.height, + v4l2_field_name((enum v4l2_field) fmt.fmt.pix_mp.field), + fmt.fmt.pix_mp.num_planes); + + for (int i = 0; i < fmt.fmt.pix_mp.num_planes; i++) { + printf(" * Stride %u, buffer size %u\n", + fmt.fmt.pix_mp.plane_fmt[i].bytesperline, + fmt.fmt.pix_mp.plane_fmt[i].sizeimage); + fflush(stdout); + } + + struct v4l2_requestbuffers rb; + memset(&rb, 0, sizeof rb); + rb.count = BUFFER_COUNT; + if constexpr (radxa_zero_3et) { + rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + } else { + rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + } + rb.memory = V4L2_MEMORY_MMAP; + + ret = ioctl(m_cam_fd, VIDIOC_REQBUFS, &rb); if (ret < 0) { fprintf(stderr, "cannot set cam request buffers: ioctl error - '%s'\n", strerror(errno)); @@ -292,45 +514,97 @@ bool VeyeIMX287m::initCam() return false; } - if (request.count < BUFFER_COUNT) { + std::cout << "buffers requested" << std::endl; + + if (rb.count < BUFFER_COUNT) { fprintf(stderr, "cannot set cam request buffers\n"); return false; } - struct v4l2_buffer buffer; - memset(&buffer, 0, sizeof(buffer)); - buffer.type = request.type; - buffer.memory = V4L2_MEMORY_MMAP; + std::cout << "buffers count is ok: " << rb.count << std::endl; - for (uint32_t i = 0; i < request.count; i++) { - buffer.index = i; - ret = ioctl(m_cam_fd, VIDIOC_QUERYBUF, &buffer); + buffers.resize(rb.count); + + // memset(&buffer, 0, sizeof(buffer)); + // buffer.type = request.type; + // buffer.memory = V4L2_MEMORY_MMAP; + + std::cout << "query buffers" << std::endl; + + for (uint32_t i = 0; i < rb.count; i++) { + std::cout << "-----------------------------------------------------" << std::endl; + struct v4l2_buffer buf; + struct v4l2_plane planes[VIDEO_MAX_PLANES]; + + memset(&buf, 0, sizeof buf); + memset(planes, 0, sizeof planes); + + buf.index = i; + buf.type = rb.type; + buf.memory = V4L2_MEMORY_MMAP; + buf.length = VIDEO_MAX_PLANES; + buf.m.planes = planes; + + std::cout << "run ioctl(VIDIOC_QUERYBUF) for buf #" << i << std::endl; + ret = ioctl(m_cam_fd, VIDIOC_QUERYBUF, &buf); if (ret < 0) { - DBG("ioctl(VIDIOC_QUERYBUF) failed %d(%s)", errno, strerror(errno)); + // std::cout << "ioctl(VIDIOC_QUERYBUF) failed: " << errno << " " << std::endl; + std::cerr << "ioctl(VIDIOC_QUERYBUF) failed: " << errno << " (" << strerror(errno) + << ")" << std::endl; return false; } - DBG("buffer.length: %d", buffer.length); - DBG("buffer.m.offset: %d", buffer.m.offset); - m_videoBuffers[i] = (uint8_t *) - mmap(NULL, buffer.length, PROT_READ | PROT_WRITE, MAP_SHARED, m_cam_fd, buffer.m.offset); - if (m_videoBuffers[i] == MAP_FAILED) { - DBG("mmap() failed %d(%s)", errno, strerror(errno)); + std::cout << "ioctl(VIDIOC_QUERYBUF) is ok: " << std::endl; + + std::cout << "buffer.length: " << buf.length << std::endl; + std::cout << "buffer.m.offset: " << buf.m.offset << std::endl; + + buffers[i].idx = i; + + const auto length = buf.m.planes[0].length; + const auto offset = buf.m.planes[0].m.mem_offset; + buffers[i].mem[0] = mmap(0, length, PROT_READ | PROT_WRITE, MAP_SHARED, m_cam_fd, offset); + if (buffers[i].mem[0] == MAP_FAILED) { + std::cerr << "mmap() failed: " << errno << " (" << strerror(errno) << ")" << std::endl; + std::cerr << "length: " << length << std::endl; + std::cerr << "offset: " << offset << std::endl; return false; + + // m_videoBuffers[i] = (uint8_t *) + // mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, m_cam_fd, buf.m.offset); + // if (m_videoBuffers[i] == MAP_FAILED) { + // DBG("mmap() failed %d(%s)", errno, strerror(errno)); + // return false; } - buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buffer.memory = V4L2_MEMORY_MMAP; - buffer.index = i; - ret = ioctl(m_cam_fd, VIDIOC_QBUF, &buffer); + m_videoBuffers[i] = (uint8_t *) buffers[i].mem[0]; + + buffers[i].size[i] = length; + buffers[i].padding[i] = 0; + + printf("Buffer %u/%u mapped at address %p.\n", buffers[i].idx, i, buffers[i].mem[0]); + + // buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + // buf.memory = V4L2_MEMORY_MMAP; + // buf.index = i; + ret = ioctl(m_cam_fd, VIDIOC_QBUF, &buf); if (ret != 0) { - DBG("ioctl(VIDIOC_QBUF) failed %d(%s)", errno, strerror(errno)); + std::cerr << "ioctl(VIDIOC_QBUF) failed: " << errno << " (" << strerror(errno) << ")" + << std::endl; return false; } + + std::cout << "ioctl(VIDIOC_QBUF) is OK" << std::endl; } + fflush(stdout); + fflush(stderr); + + // std::cout << "test return false" << std::endl; + // return false; + // int buffer_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; // ret = ioctl(m_cam_fd, VIDIOC_STREAMON, &buffer_type); // if (ret != 0) @@ -379,6 +653,7 @@ void VeyeIMX287m::calcFrameLoop(std::stop_token stopToken) // std::lock_guard buffer_lock{m_bufferMutexes[bufferIdx]}; // get: 4100-4500 memcpy(&image.data, m_videoBuffers[bufferIdx], img_size); + // memcpy(&image.data, buffers[bufferIdx].mem[0], img_size); // get: 5000-5100 // memcpy_1by1<img_size / sizeof(ARRAY_TYPE)>((ARRAY_TYPE *) &image.data, // (ARRAY_TYPE *) m_videoBuffers[bufferIdx]); @@ -402,11 +677,14 @@ void VeyeIMX287m::calcFrameLoop(std::stop_token stopToken) image.rotate(); // const auto pixels = image.pixels(); - const auto pixels = image.sharedPixels(); + // static const auto pixels = image.sharedPixels(); + + ++processedCounter; + #pragma push_macro("emit") #undef emit // std::cout << "emit pixels" << std::endl; - newPixels.emit(pixels); + // newPixels.emit(pixels); #pragma pop_macro("emit") // const auto lines = pixelsToLines(*pixels); // continue; @@ -435,14 +713,14 @@ bool VeyeIMX287m::dequeueImageBuffer(size_t &imageIndex) counter, dropped_count, curr.tv_sec % 1000, - dq_elapsed_ns / 1000 / counter, - get_elapsed_ns / 1000 / counter, - rot_elapsed_ns / 1000 / counter, - pix_elapsed_ns / 1000 / counter, - sum_elapsed_ns / 1000 / counter, - corr_elapsed_ns / 1000 / counter, - // max_elapsed_ns / 1000 / counter, - value_elapsed_ns / 1000 / counter); + dq_elapsed_ns / 1000 / processedCounter, + get_elapsed_ns / 1000 / processedCounter, + rot_elapsed_ns / 1000 / processedCounter, + pix_elapsed_ns / 1000 / processedCounter, + sum_elapsed_ns / 1000 / processedCounter, + corr_elapsed_ns / 1000 / processedCounter, + // max_elapsed_ns / 1000 / processedCounter, + value_elapsed_ns / 1000 / processedCounter); dq_elapsed_ns = 0; get_elapsed_ns = 0; @@ -455,18 +733,26 @@ bool VeyeIMX287m::dequeueImageBuffer(size_t &imageIndex) dropped_count = 0; counter = 0; + processedCounter = 0; prev = curr; } int ret; - struct v4l2_buffer buffer; + struct v4l2_buffer buf; + struct v4l2_plane planes[VIDEO_MAX_PLANES]; + + memset(&buf, 0, sizeof(buf)); + memset(planes, 0, sizeof planes); - memset(&buffer, 0, sizeof(buffer)); - buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buffer.memory = V4L2_MEMORY_MMAP; + const auto radxa_buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + // buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.type = radxa_buf_type; + buf.memory = V4L2_MEMORY_MMAP; + buf.length = VIDEO_MAX_PLANES; + buf.m.planes = planes; static uint16_t requestIdx{0}; // buffer.index = BUFFER_COUNT; - buffer.index = requestIdx++ % BUFFER_COUNT; + buf.index = requestIdx++ % BUFFER_COUNT; { QElapsedTimer t; @@ -481,24 +767,25 @@ bool VeyeIMX287m::dequeueImageBuffer(size_t &imageIndex) // } // } - auto oldIdx = buffer.index; + auto oldIdx = buf.index; // m_bufferMutexes[buffer.index].lock(); std::lock_guard<std::mutex> lock(m_camMtx); - ret = ioctl(m_cam_fd, VIDIOC_DQBUF, &buffer); + ret = ioctl(m_cam_fd, VIDIOC_DQBUF, &buf); // m_bufferMutexes[buffer.index].unlock(); - auto newIdx = buffer.index; + auto newIdx = buf.index; if (oldIdx != newIdx) { // std::cout << "AAAAAAAAAAAAAA " << oldIdx << ' ' << newIdx << std::endl; } if (ret != 0) { - DBG("ioctl(VIDIOC_DQBUF) failed %d(%s)", errno, strerror(errno)); + std::cerr << "ioctl(VIDIOC_DQBUF) failed: " << errno << " (" << strerror(errno) << ")" + << std::endl; return false; } - if (buffer.index < 0 || buffer.index >= BUFFER_COUNT) { - DBG("invalid buffer index: %d", buffer.index); + if (buf.index < 0 || buf.index >= BUFFER_COUNT) { + std::cerr << "invalid buffer index: " << buf.index << std::endl; return false; } @@ -509,19 +796,20 @@ bool VeyeIMX287m::dequeueImageBuffer(size_t &imageIndex) } // auto &image = video_buffer_ptr[buffer.index]; - imageIndex = buffer.index; - auto &image = m_images[buffer.index]; + imageIndex = buf.index; + // std::cout << "index: " << imageIndex << std::endl; + auto &image = m_images[buf.index]; image.height = img_height; image.width = img_width; // TODO: fill // image.counters.encoderPosition = RotaryEncoder::instance()->position(); - image.counters.measurementCounter = buffer.sequence; + image.counters.measurementCounter = buf.sequence; - static int64_t prevCounter = buffer.sequence; - dropped_count += buffer.sequence - prevCounter - 1; - prevCounter = buffer.sequence; + static int64_t prevCounter = buf.sequence; + dropped_count += buf.sequence - prevCounter - 1; + prevCounter = buf.sequence; - image.counters.timestampUs = buffer.timestamp.tv_sec * 1000 * 1000 + buffer.timestamp.tv_usec; + image.counters.timestampUs = buf.timestamp.tv_sec * 1000 * 1000 + buf.timestamp.tv_usec; // { // QElapsedTimer t; @@ -533,7 +821,7 @@ bool VeyeIMX287m::dequeueImageBuffer(size_t &imageIndex) { std::lock_guard<std::mutex> lock(m_camMtx); - ret = ioctl(m_cam_fd, VIDIOC_QBUF, &buffer); + ret = ioctl(m_cam_fd, VIDIOC_QBUF, &buf); } if (ret != 0) { diff --git a/src/camera/veyeimx287m.h b/src/camera/veyeimx287m.h index 37da5b0..e1eb76d 100644 --- a/src/camera/veyeimx287m.h +++ b/src/camera/veyeimx287m.h @@ -1,7 +1,7 @@ #pragma once #include <cstdint> - +#include <linux/videodev2.h> #include <queue> #include <thread> @@ -57,17 +57,30 @@ private: private: int m_cam_fd{-1}; - static constexpr uint8_t BUFFER_COUNT{8}; + static constexpr uint8_t BUFFER_COUNT{16}; + struct v4l2_plane planes[VIDEO_MAX_PLANES]; std::array<std::mutex, BUFFER_COUNT> m_imageMutexes; std::array<Image, BUFFER_COUNT> m_images; std::array<std::mutex, BUFFER_COUNT> m_bufferMutexes; std::array<uint8_t *, BUFFER_COUNT> m_videoBuffers; + struct buffer + { + unsigned int idx; + unsigned int padding[VIDEO_MAX_PLANES]; + unsigned int size[VIDEO_MAX_PLANES]; + void *mem[VIDEO_MAX_PLANES]; + }; + std::vector<buffer> buffers; + // std::mutex m_queueMtx; std::mutex m_camMtx; std::queue<size_t> m_buffersQueue; std::jthread m_streamThread; + // std::jthread m_calcThreads[1]; std::jthread m_calcThreads[4]; + + uint32_t processedCounter{0}; }; diff --git a/src/constants.h b/src/constants.h index 303e728..83c81c8 100644 --- a/src/constants.h +++ b/src/constants.h @@ -10,11 +10,15 @@ // constexpr size_t img_width = 1280; // constexpr size_t img_height = 800; +#define RADXA_ZERO_3E + // imx287llr constexpr size_t img_width = 704; +constexpr size_t radxa_raw_img_stride = 768; constexpr size_t img_height = 544; constexpr size_t img_size = img_width * img_height; +constexpr size_t radxa_raw_img_size = radxa_raw_img_stride * img_height; constexpr uint32_t patternSize = 16; diff --git a/src/image.cpp b/src/image.cpp index e5265c7..e1f7731 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -176,11 +176,19 @@ void Image::rotate() { t.start(); +#ifdef RADXA_ZERO_3E + for (size_t i = 0; i < img_height; ++i) { + for (size_t j = 0; j < img_width; ++j) { + rotated_cw[j][i] = data[img_height - i - 1][j]; + } + } +#else for (size_t j = 0; j < img_width; ++j) { for (size_t i = 0; i < img_height; ++i) { rotated_cw[j][i] = data[img_height - i - 1][j]; } } +#endif // RADXA_ZERO_3E rot_elapsed_ns += t.nsecsElapsed(); } diff --git a/src/image.h b/src/image.h index e4cf9eb..a59e209 100644 --- a/src/image.h +++ b/src/image.h @@ -19,13 +19,20 @@ struct Image Image &operator=(Image &&other) = default; // uint8_t data[img_height][img_width] = {{0}}; +#ifdef RADXA_ZERO_3E + using row_t = std::array<uint8_t, radxa_raw_img_stride>; + // using row_t = std::array<uint8_t, img_width>; + using data_t = std::array<row_t, img_height>; +#else using row_t = std::array<uint8_t, img_width>; using data_t = std::array<row_t, img_height>; +#endif // RADXA_ZERO_3E using rotated_row_t = std::array<uint8_t, img_height>; using column_t = rotated_row_t; using rotated_data_t = std::array<column_t, img_width>; // data_t d; alignas(128) data_t data; + // alignas(128) std::array<uint8_t, 417792> rawData; int width{0}; int height{0}; // data_t *data; diff --git a/src/imagealgos.cpp b/src/imagealgos.cpp index 2257244..9228749 100644 --- a/src/imagealgos.cpp +++ b/src/imagealgos.cpp @@ -35,7 +35,13 @@ size_t pgm_save(Image *img, FILE *outfile, bool really_save) n += sprintf((char*)pgm_image, "P5\n%d %d\n%d\n", img->width, img->height, 0xFF); +#ifdef RADXA_ZERO_3E + for (size_t row{0}; row < img_height; ++row) { + memcpy(pgm_image + n + row * img_width, img->data[row].data(), img_width); + } +#else memcpy(pgm_image + n, img->data.data(), sizeof(img->data)); +#endif // RADXA_ZERO_3E // memcpy(pgm_image + n, img->data->data(), sizeof(img->data)); n += sizeof(img->data); pgm_image_size = n; diff --git a/src/main.cpp b/src/main.cpp index bc0c00b..2ec6c0c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,10 +1,13 @@ #include <chrono> #include <csignal> #include <errno.h> +#include <fcntl.h> #include <fstream> #include <iostream> #include <iterator> +#include <linux/videodev2.h> #include <string.h> +#include <sys/ioctl.h> #include <sys/mman.h> #include <thread> @@ -63,7 +66,7 @@ requested_params_t requested_params; namespace { // std::shared_ptr<Image> img; -Image *img = nullptr; +// Image *img = nullptr; Pixels pixels; std::vector<Pixels> calibrationPixels; QMutex calibrationPixelsMutex; @@ -100,18 +103,18 @@ auto printPixels = [](const auto& pixels) { }; // void onNewImage(std::shared_ptr<Image> image) -void onNewImage(Image &image) -{ - // std::cout << __func__ << std::endl << std::flush; +// void onNewImage(Image &image) +// { +// // std::cout << __func__ << std::endl << std::flush; - // if (!image) - // { - // qDebug() << __func__ << "no image"; - // return; - // } +// // if (!image) +// // { +// // qDebug() << __func__ << "no image"; +// // return; +// // } - ::img = ℑ -} +// ::img = ℑ +// } void onNewPixels(std::shared_ptr<Pixels> pixels) { @@ -139,6 +142,8 @@ void onNewPixels(std::shared_ptr<Pixels> pixels) bool initLaser(); +bool initCam(); + int main(int argc, char* argv[]) { auto sigHandler = [](int s) { @@ -148,6 +153,12 @@ int main(int argc, char* argv[]) // qApp->quit(); }; + // if (!initCam()) { + // return EXIT_FAILURE; + // } + + // return EXIT_SUCCESS; + // for (int i = 2000; i >= 0; i -= 50) { // for (int i = 0; i < 2000; i += 50) { // if (!veye::imx287m::test(i)) { @@ -415,7 +426,7 @@ int main(int argc, char* argv[]) std::cout << "connect everything" << std::endl; camera->newPixels.connect(&onNewPixels); // camera->newImage.connect(&onNewImage); - camera->newImageCallback = &onNewImage; + // camera->newImageCallback = &onNewImage; camera->newPixelsCallback = &onNewPixels; for (auto& i : initializers) @@ -444,16 +455,18 @@ int main(int argc, char* argv[]) return QHttpServerResponse::StatusCode::ServiceUnavailable; } - Image img; + static Image img; // yeaah - ::img = &img; + // ::img = &img; if (!cam->getImage(img)) { qDebug() << "cannot get image"; return QHttpServerResponse::StatusCode::ServiceUnavailable; } - pgm_save(::img); - // save = false; + // std::cout << "http: got image" << std::endl << std::flush; + // pgm_save(::img); + pgm_save(&img); std::lock_guard<std::mutex> lg(pgm_image_mtx); + // save = false; // qDebug() << "mutex locked"; // qDebug() << "image saved to array"; return QHttpServerResponse{QByteArray((const char *) pgm_image, pgm_image_size), @@ -478,7 +491,7 @@ int main(int argc, char* argv[]) Image img; // yeaah - ::img = &img; + // ::img = &img; if (!cam->getImage(img)) { qDebug() << "cannot get image"; return QHttpServerResponse::StatusCode::ServiceUnavailable; @@ -486,7 +499,7 @@ int main(int argc, char* argv[]) ::pixels = std::move(img.pixels()); - std::lock_guard<std::mutex> lg(pgm_image_mtx); + // std::lock_guard<std::mutex> lg(pgm_image_mtx); // qt json does not allow to limit double precision @@ -525,11 +538,11 @@ int main(int argc, char* argv[]) const auto result = QJsonDocument(json).toJson(); // qDebug() << "pixels answer size is" << result.size(); - static bool done{false}; - if (!done) { - qDebug().noquote() << result; - done = true; - } + // static bool done{false}; + // if (!done) { + // qDebug().noquote() << result; + // done = true; + // } { rapidjson::Document jd; @@ -551,8 +564,9 @@ int main(int argc, char* argv[]) writer.SetMaxDecimalPlaces(2); jd.Accept(writer); QString res{(const char *) buffer.GetString()}; - qDebug() << "size:" << res.size(); - // qDebug().noquote() << res; + // qDebug() << "size:" << res.size(); + // qDebug().noquote() << "ret pix"; + return QHttpServerResponse{res}; } @@ -575,7 +589,7 @@ int main(int argc, char* argv[]) // std::cout << buffer.GetString() << "\n"; // } - qDebug() << "size:" << result.size(); + // qDebug() << "size:" << result.size(); return QHttpServerResponse(result); }); @@ -912,3 +926,126 @@ bool initLaser() return true; } + +bool initCam() +{ + const v4l2_memory memtype = V4L2_MEMORY_MMAP; + v4l2_buf_type type = (enum v4l2_buf_type) - 1; + const char *devname{"/dev/video0"}; + int fd{open(devname, O_RDWR)}; + + if (fd < 0) { + printf("Error opening device %s: %s (%d).\n", devname, strerror(errno), errno); + fflush(stdout); + return false; + } + + std::cout << devname << ": opened" << std::endl; + + v4l2_capability cap; + memset(&cap, 0, sizeof cap); + const auto ret = ioctl(fd, VIDIOC_QUERYCAP, &cap); + if (ret < 0) { + printf("cannot query cap for %s: %s (%d).\n", devname, strerror(errno), errno); + fflush(stdout); + return false; + } + + std::cout << devname << ": got caps" << std::endl; + + const auto caps = cap.capabilities & V4L2_CAP_DEVICE_CAPS ? cap.device_caps : cap.capabilities; + const bool has_video = caps + & (V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_CAPTURE + | V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_VIDEO_OUTPUT); + const bool has_meta = caps & (V4L2_CAP_META_CAPTURE | V4L2_CAP_META_OUTPUT); + const bool has_capture = caps + & (V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_CAPTURE + | V4L2_CAP_META_CAPTURE); + const bool has_output = caps + & (V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_VIDEO_OUTPUT + | V4L2_CAP_META_OUTPUT); + const bool has_mplane = caps & (V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE); + + printf("Device `%s' on `%s' (driver '%s') supports%s%s%s%s %s mplanes.\n", + cap.card, + cap.bus_info, + cap.driver, + has_video ? " video," : "", + has_meta ? " meta-data," : "", + has_capture ? " capture," : "", + has_output ? " output," : "", + has_mplane ? "with" : "without"); + + const auto buf_type = [caps, devname]() -> int { + if (caps & V4L2_CAP_VIDEO_CAPTURE_MPLANE) { + std::cout << devname << ": buf_type: V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE" << std::endl; + return V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + } else if (caps & V4L2_CAP_VIDEO_OUTPUT_MPLANE) { + std::cout << devname << ": buf_type: V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE" << std::endl; + return V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + } else if (caps & V4L2_CAP_VIDEO_CAPTURE) { + std::cout << devname << ": buf_type: V4L2_BUF_TYPE_VIDEO_CAPTURE" << std::endl; + return V4L2_BUF_TYPE_VIDEO_CAPTURE; + } else if (caps & V4L2_CAP_VIDEO_OUTPUT) { + std::cout << devname << ": buf_type: V4L2_BUF_TYPE_VIDEO_OUTPUT" << std::endl; + return V4L2_BUF_TYPE_VIDEO_OUTPUT; + } else if (caps & V4L2_CAP_META_CAPTURE) { + std::cout << devname << ": buf_type: V4L2_BUF_TYPE_META_CAPTURE" << std::endl; + return V4L2_BUF_TYPE_META_CAPTURE; + } else if (caps & V4L2_CAP_META_OUTPUT) { + std::cout << devname << ": buf_type: V4L2_BUF_TYPE_META_OUTPUT" << std::endl; + return V4L2_BUF_TYPE_META_OUTPUT; + } else { + printf("Device supports neither capture nor output.\n"); + return -EINVAL; + } + }(); + + if (buf_type < 0) { + return false; + } + + if (false) { + v4l2_format fmt; + memset(&fmt, 0, sizeof fmt); + fmt.type = buf_type; + + if (ioctl(fd, VIDIOC_G_FMT, &fmt) < 0) { + printf("Unable to get format: %s (%d).\n", strerror(errno), errno); + + return false; + } + + const auto width = fmt.fmt.pix_mp.width; + const auto height = fmt.fmt.pix_mp.height; + const auto num_planes = fmt.fmt.pix_mp.num_planes; + struct v4l2_plane_pix_format plane_fmt[VIDEO_MAX_PLANES] = {0}; + + printf("Video format: (%08x) %ux%u field %d, %u planes: \n", + fmt.fmt.pix_mp.pixelformat, + fmt.fmt.pix_mp.width, + fmt.fmt.pix_mp.height, + fmt.fmt.pix_mp.field, + fmt.fmt.pix_mp.num_planes); + + for (int i = 0; i < fmt.fmt.pix_mp.num_planes; i++) { + plane_fmt[i].bytesperline = fmt.fmt.pix_mp.plane_fmt[i].bytesperline; + plane_fmt[i].sizeimage = fmt.fmt.pix_mp.plane_fmt[i].bytesperline + ? fmt.fmt.pix_mp.plane_fmt[i].sizeimage + : 0; + + printf(" * Stride %u, buffer size %u\n", + fmt.fmt.pix_mp.plane_fmt[i].bytesperline, + fmt.fmt.pix_mp.plane_fmt[i].sizeimage); + } + } + + unsigned int padding = 0; + unsigned int nbufs = 8; + + // if () + + close(fd); + + return true; +} |
