89a4b81654
Probe `/tmp/expbuf_probe.c` (snapshot at probes/expbuf_probe.c) opens /dev/video1, sets OUTPUT format H264_SLICE 1920x1088, REQBUFS 4 capture buffers, EXPBUF on plane 0 of buffer 0, lseek(fd, 0, SEEK_END). On ohm (kernel besser-7.0, hantro-vpu / rk3568-vpu-dec): CAPTURE: NV12 1920x1088 num_planes=1 sizeimage=3655712 EXPBUF fd lseek(SEEK_END) = 3657728 (page-rounded from 3655712) Kernel exports the dma_buf at full sizeimage; offset 2,088,960 (plane 1 base in ffmpeg's drm-frame-descriptor) is well inside. Hantro is innocent. Side observation: sizeimage = 3,655,712 > naive NV12's 3,133,440. The 522,272-byte excess is trailing padding (likely Rockchip per-frame MV / context metadata) past the UV plane. Y and UV layout fit cleanly within [0, 3,133,440), exactly where mpv/ffmpeg expect. Remaining hypothesis space: H1 (panfrost EGL non-zero plane offset), H2 (KWin wl_dmabuf import), H4 (kwin-fourier residual, low conf). Next probe queued: H2 source-read of KWin 6.6.4 wl_dmabuf import path. ~30 min, no hardware needed. If that turns up nothing, write the EGL importer harness for H1. Posted to dmabuf-modifier-triage#1 comment 255.
125 lines
4.7 KiB
C
125 lines
4.7 KiB
C
/*
|
|
* 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 <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/mman.h>
|
|
#include <unistd.h>
|
|
#include <linux/videodev2.h>
|
|
|
|
#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;
|
|
}
|