/* * iter1 hypothesis 3 probe — lseek(SEEK_END) on a hantro CAPTURE EXPBUF fd * * Question: does hantro export the dma_buf with size = full sizeimage * (3,655,712 = 1920*1088*1.5) or capped to Y-plane only (2,088,960 = 1920*1088)? * * Decides hypothesis 3 from ~/src/dmabuf-modifier-triage/phase2_iter1_findings.md. */ #include #include #include #include #include #include #include #include #include #define DEV "/dev/video1" #define WIDTH 1920 #define HEIGHT 1088 static int xioctl(int fd, unsigned long req, void *arg, const char *name) { int r = ioctl(fd, req, arg); if (r < 0) fprintf(stderr, "ioctl %s: %s (errno=%d)\n", name, strerror(errno), errno); return r; } int main(void) { int fd = open(DEV, O_RDWR); if (fd < 0) { perror("open " DEV); return 1; } struct v4l2_capability cap = {0}; if (xioctl(fd, VIDIOC_QUERYCAP, &cap, "QUERYCAP") < 0) return 2; printf("driver: %s\n", cap.driver); printf("card: %s\n", cap.card); printf("bus_info: %s\n", cap.bus_info); printf("caps: 0x%08x (M2M_MPLANE=%d)\n", cap.device_caps, !!(cap.device_caps & V4L2_CAP_VIDEO_M2M_MPLANE)); /* Set OUTPUT (compressed bitstream) format first. * Hantro derives CAPTURE size from OUTPUT pixel format + dimensions. */ struct v4l2_format ofmt = {0}; ofmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; ofmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264_SLICE; ofmt.fmt.pix_mp.width = WIDTH; ofmt.fmt.pix_mp.height = HEIGHT; ofmt.fmt.pix_mp.num_planes = 1; ofmt.fmt.pix_mp.plane_fmt[0].sizeimage = 1024*1024; /* compressed buf size */ if (xioctl(fd, VIDIOC_S_FMT, &ofmt, "S_FMT(OUTPUT)") < 0) return 3; /* Now CAPTURE format. Driver should default to NV12 1920x1088. */ struct v4l2_format cfmt = {0}; cfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; if (xioctl(fd, VIDIOC_G_FMT, &cfmt, "G_FMT(CAPTURE)") < 0) return 4; printf("CAPTURE: pixfmt=0x%08x (%c%c%c%c) %ux%u num_planes=%u\n", cfmt.fmt.pix_mp.pixelformat, cfmt.fmt.pix_mp.pixelformat & 0xff, (cfmt.fmt.pix_mp.pixelformat >> 8) & 0xff, (cfmt.fmt.pix_mp.pixelformat >> 16) & 0xff, (cfmt.fmt.pix_mp.pixelformat >> 24) & 0xff, cfmt.fmt.pix_mp.width, cfmt.fmt.pix_mp.height, cfmt.fmt.pix_mp.num_planes); for (unsigned i = 0; i < cfmt.fmt.pix_mp.num_planes; ++i) { printf(" plane[%u]: sizeimage=%u bytesperline=%u\n", i, cfmt.fmt.pix_mp.plane_fmt[i].sizeimage, cfmt.fmt.pix_mp.plane_fmt[i].bytesperline); } /* Try setting NV12 explicitly in case driver wants confirmation. */ cfmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12; if (xioctl(fd, VIDIOC_S_FMT, &cfmt, "S_FMT(CAPTURE NV12)") < 0) return 5; /* REQBUFS CAPTURE — DMABUF memory so we can EXPBUF later. */ struct v4l2_requestbuffers rb = {0}; rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; rb.memory = V4L2_MEMORY_MMAP; rb.count = 4; if (xioctl(fd, VIDIOC_REQBUFS, &rb, "REQBUFS(CAPTURE)") < 0) return 6; printf("REQBUFS allocated %u buffers\n", rb.count); /* QUERYBUF buffer 0 to learn its plane layout. */ struct v4l2_buffer qb = {0}; struct v4l2_plane planes[VIDEO_MAX_PLANES] = {0}; qb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; qb.memory = V4L2_MEMORY_MMAP; qb.index = 0; qb.length = VIDEO_MAX_PLANES; qb.m.planes = planes; if (xioctl(fd, VIDIOC_QUERYBUF, &qb, "QUERYBUF") < 0) return 7; printf("QUERYBUF buf 0: %u planes\n", qb.length); for (unsigned i = 0; i < qb.length; ++i) { printf(" plane[%u]: length=%u data_offset=%u m.mem_offset=0x%x\n", i, planes[i].length, planes[i].data_offset, planes[i].m.mem_offset); } /* THE PROBE: VIDIOC_EXPBUF + lseek(SEEK_END). */ for (unsigned i = 0; i < qb.length; ++i) { struct v4l2_exportbuffer eb = {0}; eb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; eb.index = 0; eb.plane = i; eb.flags = O_CLOEXEC | O_RDWR; if (xioctl(fd, VIDIOC_EXPBUF, &eb, "EXPBUF") < 0) { fprintf(stderr, " (plane %u EXPBUF failed)\n", i); continue; } off_t end = lseek(eb.fd, 0, SEEK_END); printf("\n *** plane[%u] EXPBUF fd=%d lseek(SEEK_END)=%lld ***\n", i, eb.fd, (long long)end); printf(" Y-plane-only would be: %d\n", WIDTH * HEIGHT); printf(" full sizeimage would be: %d\n", WIDTH * HEIGHT * 3 / 2); printf(" QUERYBUF reported: %u\n", planes[i].length); close(eb.fd); } close(fd); return 0; }