diff options
Diffstat (limited to 'v4l2-drm-example')
-rw-r--r-- | v4l2-drm-example/dmabuf-sharing.c | 234 |
1 files changed, 138 insertions, 96 deletions
diff --git a/v4l2-drm-example/dmabuf-sharing.c b/v4l2-drm-example/dmabuf-sharing.c index d72b6d9..da83eb7 100644 --- a/v4l2-drm-example/dmabuf-sharing.c +++ b/v4l2-drm-example/dmabuf-sharing.c @@ -86,6 +86,25 @@ struct setup { struct v4l2_rect compose; }; +struct drm_device { + const char *module; + int fd; + + unsigned int crtc_id; + unsigned int con_id; + + drmModeModeInfo mode; + const char *modestr; + unsigned int format; +}; + +struct v4l2_device { + const char *devname; + int fd; + + struct v4l2_pix_format format; +}; + struct buffer { unsigned int bo_handle; unsigned int fb_handle; @@ -93,10 +112,12 @@ struct buffer { }; struct stream { - int v4lfd; + struct drm_device *drm; + struct v4l2_device *v4l2; + + struct buffer *buffers; + unsigned int num_buffers; int current_buffer; - int buffer_count; - struct buffer *buffer; } stream; static void usage(char *name) @@ -192,19 +213,19 @@ static int parse_args(int argc, char *argv[], struct setup *s) return 0; } -static int buffer_create(struct buffer *b, int drmfd, struct setup *s, - uint64_t size, uint32_t pitch) +static int drm_buffer_create(struct drm_device *dev, struct buffer *b, + const struct v4l2_pix_format *fmt) { struct drm_mode_create_dumb gem; struct drm_mode_destroy_dumb gem_destroy; int ret; memset(&gem, 0, sizeof gem); - gem.width = s->w; - gem.height = s->h; - gem.bpp = pitch / s->w * 8; - gem.size = size; - ret = ioctl(drmfd, DRM_IOCTL_MODE_CREATE_DUMB, &gem); + gem.width = fmt->width; + gem.height = fmt->height; + gem.bpp = fmt->bytesperline / fmt->width * 8; + gem.size = fmt->sizeimage; + ret = ioctl(dev->fd, DRM_IOCTL_MODE_CREATE_DUMB, &gem); if (WARN_ON(ret, "CREATE_DUMB failed: %s\n", ERRSTR)) return -1; b->bo_handle = gem.handle; @@ -213,19 +234,19 @@ static int buffer_create(struct buffer *b, int drmfd, struct setup *s, memset(&prime, 0, sizeof prime); prime.handle = b->bo_handle; - ret = ioctl(drmfd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime); + ret = ioctl(dev->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime); if (WARN_ON(ret, "PRIME_HANDLE_TO_FD failed: %s\n", ERRSTR)) goto fail_gem; printf("dbuf_fd = %d\n", prime.fd); b->dbuf_fd = prime.fd; uint32_t offsets[4] = { 0 }; - uint32_t pitches[4] = { pitch }; + uint32_t pitches[4] = { fmt->bytesperline }; uint32_t bo_handles[4] = { b->bo_handle }; - unsigned int fourcc = s->out_fourcc; + unsigned int fourcc = dev->format; if (!fourcc) - fourcc = s->in_fourcc; - ret = drmModeAddFB2(drmfd, s->w, s->h, fourcc, bo_handles, + fourcc = fmt->pixelformat; + ret = drmModeAddFB2(dev->fd, fmt->width, fmt->height, fourcc, bo_handles, pitches, offsets, &b->fb_handle, 0); if (WARN_ON(ret, "drmModeAddFB2 failed: %s\n", ERRSTR)) goto fail_prime; @@ -238,17 +259,16 @@ fail_prime: fail_gem: memset(&gem_destroy, 0, sizeof gem_destroy); gem_destroy.handle = b->bo_handle, - ret = ioctl(drmfd, DRM_IOCTL_MODE_DESTROY_DUMB, &gem_destroy); + ret = ioctl(dev->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &gem_destroy); WARN_ON(ret, "DESTROY_DUMB failed: %s\n", ERRSTR); return -1; } -static int find_mode(drmModeModeInfo *m, int drmfd, struct setup *s, - uint32_t *con) +static int drm_find_mode(struct drm_device *dev, drmModeModeInfo *m) { int ret = -1; - drmModeRes *res = drmModeGetResources(drmfd); + drmModeRes *res = drmModeGetResources(dev->fd); if (WARN_ON(!res, "drmModeGetResources failed: %s\n", ERRSTR)) return -1; @@ -259,7 +279,7 @@ static int find_mode(drmModeModeInfo *m, int drmfd, struct setup *s, goto fail_res; drmModeConnector *c; - c = drmModeGetConnector(drmfd, s->conId); + c = drmModeGetConnector(dev->fd, dev->con_id); if (WARN_ON(!c, "drmModeGetConnector failed: %s\n", ERRSTR)) goto fail_res; @@ -268,13 +288,13 @@ static int find_mode(drmModeModeInfo *m, int drmfd, struct setup *s, drmModeModeInfo *found = NULL; for (int i = 0; i < c->count_modes; ++i) { - if (strcmp(c->modes[i].name, s->modestr) == 0) { + if (strcmp(c->modes[i].name, dev->modestr) == 0) { found = &c->modes[i]; break; } } - if (WARN_ON(!found, "mode %s not supported\n", s->modestr)) { + if (WARN_ON(!found, "mode %s not supported\n", dev->modestr)) { fprintf(stderr, "Valid modes:"); for (int i = 0; i < c->count_modes; ++i) fprintf(stderr, " %s", c->modes[i].name); @@ -283,8 +303,6 @@ static int find_mode(drmModeModeInfo *m, int drmfd, struct setup *s, } memcpy(m, found, sizeof *found); - if (con) - *con = c->connector_id; ret = 0; fail_conn: @@ -296,50 +314,36 @@ fail_res: return ret; } -static void page_flip_handler(int fd __attribute__((__unused__)), - unsigned int frame __attribute__((__unused__)), - unsigned int sec __attribute__((__unused__)), - unsigned int usec __attribute__((__unused__)), - void *data) +static void drm_init(struct drm_device *dev, const struct v4l2_pix_format *fmt, + unsigned int num_buffers, struct buffer *buffers) { - int index = stream.current_buffer; - struct v4l2_buffer buf; int ret; - stream.current_buffer = (unsigned long)data; - if (index < 0) - return; + dev->fd = drmOpen(dev->module, NULL); + BYE_ON(dev->fd < 0, "drmOpen(%s) failed: %s\n", dev->module, ERRSTR); - memset(&buf, 0, sizeof buf); - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_DMABUF; - buf.index = index; - buf.m.fd = stream.buffer[index].dbuf_fd; + /* TODO: add support for multiplanar formats */ + for (unsigned int i = 0; i < num_buffers; ++i) { + ret = drm_buffer_create(dev, &buffers[i], fmt); + BYE_ON(ret, "failed to create buffer%d\n", i); + } + printf("buffers ready\n"); - ret = ioctl(stream.v4lfd, VIDIOC_QBUF, &buf); - BYE_ON(ret, "VIDIOC_QBUF(index = %d) failed: %s\n", index, ERRSTR); + ret = drm_find_mode(dev, &dev->mode); + BYE_ON(ret, "failed to find valid mode\n"); } -int main(int argc, char *argv[]) +static void v4l2_init(struct v4l2_device *dev, unsigned int num_buffers) { int ret; - struct setup s; - - ret = parse_args(argc, argv, &s); - BYE_ON(ret, "failed to parse arguments\n"); - BYE_ON(s.module[0] == 0, "DRM module is missing\n"); - BYE_ON(s.video[0] == 0, "video node is missing\n"); - - int drmfd = drmOpen(s.module, NULL); - BYE_ON(drmfd < 0, "drmOpen(%s) failed: %s\n", s.module, ERRSTR); - int v4lfd = open(s.video, O_RDWR); - BYE_ON(v4lfd < 0, "failed to open %s: %s\n", s.video, ERRSTR); + dev->fd = open(dev->devname, O_RDWR); + BYE_ON(dev->fd < 0, "failed to open %s: %s\n", dev->devname, ERRSTR); struct v4l2_capability caps; memset(&caps, 0, sizeof caps); - ret = ioctl(v4lfd, VIDIOC_QUERYCAP, &caps); + ret = ioctl(dev->fd, VIDIOC_QUERYCAP, &caps); BYE_ON(ret, "VIDIOC_QUERYCAP failed: %s\n", ERRSTR); /* TODO: add single plane support */ @@ -350,23 +354,18 @@ int main(int argc, char *argv[]) memset(&fmt, 0, sizeof fmt); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - ret = ioctl(v4lfd, VIDIOC_G_FMT, &fmt); + ret = ioctl(dev->fd, VIDIOC_G_FMT, &fmt); BYE_ON(ret < 0, "VIDIOC_G_FMT failed: %s\n", ERRSTR); printf("G_FMT(start): width = %u, height = %u, 4cc = %.4s\n", fmt.fmt.pix.width, fmt.fmt.pix.height, (char*)&fmt.fmt.pix.pixelformat); - if (s.use_wh) { - fmt.fmt.pix.width = s.w; - fmt.fmt.pix.height = s.h; - } - if (s.in_fourcc) - fmt.fmt.pix.pixelformat = s.in_fourcc; + fmt.fmt.pix = dev->format; - ret = ioctl(v4lfd, VIDIOC_S_FMT, &fmt); + ret = ioctl(dev->fd, VIDIOC_S_FMT, &fmt); BYE_ON(ret < 0, "VIDIOC_S_FMT failed: %s\n", ERRSTR); - ret = ioctl(v4lfd, VIDIOC_G_FMT, &fmt); + ret = ioctl(dev->fd, VIDIOC_G_FMT, &fmt); BYE_ON(ret < 0, "VIDIOC_G_FMT failed: %s\n", ERRSTR); printf("G_FMT(final): width = %u, height = %u, 4cc = %.4s\n", fmt.fmt.pix.width, fmt.fmt.pix.height, @@ -374,41 +373,83 @@ int main(int argc, char *argv[]) struct v4l2_requestbuffers rqbufs; memset(&rqbufs, 0, sizeof(rqbufs)); - rqbufs.count = s.buffer_count; + rqbufs.count = num_buffers; rqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; rqbufs.memory = V4L2_MEMORY_DMABUF; - ret = ioctl(v4lfd, VIDIOC_REQBUFS, &rqbufs); + ret = ioctl(dev->fd, VIDIOC_REQBUFS, &rqbufs); BYE_ON(ret < 0, "VIDIOC_REQBUFS failed: %s\n", ERRSTR); - BYE_ON(rqbufs.count < s.buffer_count, "video node allocated only " - "%u of %u buffers\n", rqbufs.count, s.buffer_count); + BYE_ON(rqbufs.count < num_buffers, "video node allocated only " + "%u of %u buffers\n", rqbufs.count, num_buffers); - s.in_fourcc = fmt.fmt.pix.pixelformat; - s.w = fmt.fmt.pix.width; - s.h = fmt.fmt.pix.height; + dev->format = fmt.fmt.pix; +} - /* TODO: add support for multiplanar formats */ - struct buffer buffer[s.buffer_count]; - uint64_t size = fmt.fmt.pix.sizeimage; - uint32_t pitch = fmt.fmt.pix.bytesperline; - printf("size = %llu pitch = %u\n", size, pitch); - for (unsigned int i = 0; i < s.buffer_count; ++i) { - ret = buffer_create(&buffer[i], drmfd, &s, size, pitch); - BYE_ON(ret, "failed to create buffer%d\n", i); +static void page_flip_handler(int fd __attribute__((__unused__)), + unsigned int frame __attribute__((__unused__)), + unsigned int sec __attribute__((__unused__)), + unsigned int usec __attribute__((__unused__)), + void *data) +{ + int index = stream.current_buffer; + struct v4l2_buffer buf; + int ret; + + stream.current_buffer = (unsigned long)data; + if (index < 0) + return; + + memset(&buf, 0, sizeof buf); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_DMABUF; + buf.index = index; + buf.m.fd = stream.buffers[index].dbuf_fd; + + ret = ioctl(stream.v4l2->fd, VIDIOC_QBUF, &buf); + BYE_ON(ret, "VIDIOC_QBUF(index = %d) failed: %s\n", index, ERRSTR); +} + +int main(int argc, char *argv[]) +{ + struct v4l2_device v4l2; + struct drm_device drm; + struct setup s; + int ret; + + ret = parse_args(argc, argv, &s); + BYE_ON(ret, "failed to parse arguments\n"); + BYE_ON(s.module[0] == 0, "DRM module is missing\n"); + BYE_ON(s.video[0] == 0, "video node is missing\n"); + + memset(&v4l2, 0, sizeof v4l2); + v4l2.devname = s.video; + + if (s.use_wh) { + v4l2.format.width = s.w; + v4l2.format.height = s.h; } - printf("buffers ready\n"); + if (s.in_fourcc) + v4l2.format.pixelformat = s.in_fourcc; - drmModeModeInfo drmmode; - uint32_t con; - ret = find_mode(&drmmode, drmfd, &s, &con); - BYE_ON(ret, "failed to find valid mode\n"); + v4l2_init(&v4l2, s.buffer_count); + + struct buffer buffers[s.buffer_count]; + + memset(&drm, 0, sizeof drm); + drm.module = s.module; + drm.modestr = s.modestr; + drm.format = s.out_fourcc; + drm.crtc_id = s.crtId; + drm.con_id = s.conId; + + drm_init(&drm, &v4l2.format, s.buffer_count, buffers); - ret = drmModeSetCrtc(drmfd, s.crtId, buffer[0].fb_handle, 0, 0, - &con, 1, &drmmode); + ret = drmModeSetCrtc(drm.fd, drm.crtc_id, buffers[0].fb_handle, 0, 0, + &drm.con_id, 1, &drm.mode); BYE_ON(ret, "drmModeSetCrtc failed: %s\n", ERRSTR); /* enqueueing first buffer to DRM */ - ret = drmModePageFlip(drmfd, s.crtId, buffer[0].fb_handle, + ret = drmModePageFlip(drm.fd, drm.crtc_id, buffers[0].fb_handle, DRM_MODE_PAGE_FLIP_EVENT, 0); BYE_ON(ret, "drmModePageFlip failed: %s\n", ERRSTR); @@ -419,25 +460,26 @@ int main(int argc, char *argv[]) buf.index = i; buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_DMABUF; - buf.m.fd = buffer[i].dbuf_fd; - ret = ioctl(v4lfd, VIDIOC_QBUF, &buf); + buf.m.fd = buffers[i].dbuf_fd; + ret = ioctl(v4l2.fd, VIDIOC_QBUF, &buf); BYE_ON(ret < 0, "VIDIOC_QBUF for buffer %d failed: %s\n", buf.index, ERRSTR); } int type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - ret = ioctl(v4lfd, VIDIOC_STREAMON, &type); + ret = ioctl(v4l2.fd, VIDIOC_STREAMON, &type); BYE_ON(ret < 0, "STREAMON failed: %s\n", ERRSTR); struct pollfd fds[] = { - { .fd = v4lfd, .events = POLLIN }, - { .fd = drmfd, .events = POLLIN }, + { .fd = v4l2.fd, .events = POLLIN }, + { .fd = drm.fd, .events = POLLIN }, }; /* buffer currently used by drm */ - stream.v4lfd = v4lfd; + stream.v4l2 = &v4l2; stream.current_buffer = -1; - stream.buffer = buffer; + stream.buffers = buffers; + stream.num_buffers = s.buffer_count; while ((ret = poll(fds, 2, 5000)) > 0) { if (fds[0].revents & POLLIN) { @@ -446,10 +488,10 @@ int main(int argc, char *argv[]) /* dequeue buffer */ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_DMABUF; - ret = ioctl(v4lfd, VIDIOC_DQBUF, &buf); + ret = ioctl(v4l2.fd, VIDIOC_DQBUF, &buf); BYE_ON(ret, "VIDIOC_DQBUF failed: %s\n", ERRSTR); - ret = drmModePageFlip(drmfd, s.crtId, buffer[buf.index].fb_handle, + ret = drmModePageFlip(drm.fd, drm.crtc_id, buffers[buf.index].fb_handle, DRM_MODE_PAGE_FLIP_EVENT, (void*)(unsigned long)buf.index); BYE_ON(ret, "drmModePageFlip failed: %s\n", ERRSTR); @@ -460,7 +502,7 @@ int main(int argc, char *argv[]) evctx.version = DRM_EVENT_CONTEXT_VERSION; evctx.page_flip_handler = page_flip_handler; - ret = drmHandleEvent(drmfd, &evctx); + ret = drmHandleEvent(drm.fd, &evctx); BYE_ON(ret, "drmHandleEvent failed: %s\n", ERRSTR); } } |