Request API simple test program
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* This program is a very simple demonstration of the proposed V4L2 request API. | |
* It must be invoked with the path to the vim2m device as parameter, e.g. | |
* | |
* $ ./m2mtest /dev/videoX | |
* | |
* It performs the following: | |
* * open the vim2m and /dev/media0 devices, allocate buffers and requests | |
* * submit a first request with a processing time of 600 ms | |
* * submit a second request with a processing time of 2000 ms | |
* * wait for requests to complete | |
* * queries the requests' controls to verify that the value are as expected | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
#include <unistd.h> | |
#include <fcntl.h> | |
#include <string.h> | |
#include <errno.h> | |
#include <sys/ioctl.h> | |
#include <sys/mman.h> | |
#include <signal.h> | |
#include <poll.h> | |
#include <linux/videodev2.h> | |
#include <linux/v4l2-controls.h> | |
#include <linux/media.h> | |
static void open_devices(const char *vim2m, int *fd, int *media_fd) | |
{ | |
printf("Opening /dev/media0\n"); | |
*media_fd = open("/dev/media0", O_RDWR, 0); | |
if (*media_fd < 0) { | |
perror("cannot open media file"); | |
exit(EXIT_FAILURE); | |
} | |
printf("Opening %s\n", vim2m); | |
*fd = open(vim2m, O_RDWR, 0); | |
if (*fd < 0) { | |
perror("cannot open media file"); | |
exit(EXIT_FAILURE); | |
} | |
} | |
static void set_format(int fd, int buf_type) | |
{ | |
struct v4l2_format format; | |
int ret; | |
memset(&format, 0, sizeof(format)); | |
format.type = buf_type; | |
format.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24; | |
format.fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; | |
format.fmt.pix.width = 1280; | |
format.fmt.pix.height = 720; | |
ret = ioctl(fd, VIDIOC_S_FMT, &format); | |
if (ret < 0) { | |
perror("error while setting format"); | |
exit(EXIT_FAILURE); | |
} | |
} | |
static void request_buffers(int fd, int buf_type, unsigned int count) | |
{ | |
struct v4l2_requestbuffers requestbuffers; | |
int ret; | |
memset(&requestbuffers, 0, sizeof(requestbuffers)); | |
requestbuffers.type = buf_type; | |
requestbuffers.memory = V4L2_MEMORY_MMAP; | |
requestbuffers.count = count; | |
ret = ioctl(fd, VIDIOC_REQBUFS, &requestbuffers); | |
if (ret < 0) { | |
perror("error while requesting buffers"); | |
exit(EXIT_FAILURE); | |
} | |
if (count > 0) | |
printf("%d %s buffers allocated\n", requestbuffers.count, | |
buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? | |
"capture" : "output"); | |
else | |
printf("All %s buffers freed\n", | |
buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? | |
"capture" : "output"); | |
} | |
static void query_buf(int fd, int buf_type, int index, struct v4l2_buffer *buf) | |
{ | |
int ret; | |
memset(buf, 0, sizeof(*buf)); | |
buf->memory = V4L2_MEMORY_MMAP; | |
buf->type = buf_type; | |
buf->index = index; | |
ret = ioctl(fd, VIDIOC_QUERYBUF, buf); | |
if (ret < 0) { | |
perror("error while querying buffer"); | |
exit(EXIT_FAILURE); | |
} | |
} | |
static void alloc_request(int fd, int *req) | |
{ | |
struct media_request_cmd cmd; | |
int ret; | |
memset(&cmd, 0, sizeof(cmd)); | |
cmd.cmd = MEDIA_REQ_CMD_ALLOC; | |
ret = ioctl(fd, MEDIA_IOC_REQUEST_CMD, &cmd); | |
if (ret < 0) { | |
perror("error while allocating request"); | |
exit(EXIT_FAILURE); | |
} | |
*req = cmd.fd; | |
} | |
static void queue_request(int fd, int req) | |
{ | |
struct media_request_cmd cmd; | |
int ret; | |
memset(&cmd, 0, sizeof(cmd)); | |
cmd.cmd = MEDIA_REQ_CMD_SUBMIT; | |
cmd.fd = req; | |
ret = ioctl(fd, MEDIA_IOC_REQUEST_CMD, &cmd); | |
if (ret < 0) { | |
perror("error while queueing request"); | |
exit(EXIT_FAILURE); | |
} | |
} | |
static void set_stream(int fd, int buf_type, int on) | |
{ | |
int ret; | |
ret = ioctl(fd, on ? VIDIOC_STREAMON : VIDIOC_STREAMOFF, &buf_type); | |
if (ret < 0) { | |
perror("error while setting streaming"); | |
exit(EXIT_FAILURE); | |
} | |
printf("%s stream %s\n", buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? | |
"Capture" : "Output", on ? "activated" : "deactivated"); | |
} | |
static void set_vim2m_ctrls(int fd, int req, unsigned int trans_time, | |
int hflip, int vflip) | |
{ | |
struct v4l2_ext_control ctrl[3]; | |
struct v4l2_ext_controls ctrls; | |
int ret; | |
memset(&ctrl, 0, sizeof(ctrl)); | |
ctrl[0].id = (V4L2_CID_USER_BASE + 0x1000); // Transaction time | |
ctrl[0].value = trans_time; | |
ctrl[1].id = V4L2_CID_HFLIP; | |
ctrl[1].value = hflip; | |
ctrl[2].id = V4L2_CID_VFLIP; | |
ctrl[2].value = vflip; | |
memset(&ctrls, 0, sizeof(ctrls)); | |
ctrls.request_fd = req; | |
ctrls.which = V4L2_CTRL_WHICH_CUR_VAL; | |
ctrls.count = 3; | |
ctrls.controls = ctrl; | |
ret = ioctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls); | |
if (ret < 0) { | |
perror("error while setting control value"); | |
exit(EXIT_FAILURE); | |
} | |
} | |
static void get_vim2m_ctrls(int fd, int req, int *trans_time, | |
int *hflip, int *vflip) | |
{ | |
struct v4l2_ext_control ctrl[3]; | |
struct v4l2_ext_controls ctrls; | |
int ret; | |
memset(&ctrl, 0, sizeof(ctrl)); | |
ctrl[0].id = (V4L2_CID_USER_BASE + 0x1000); // Transaction time | |
ctrl[1].id = V4L2_CID_HFLIP; | |
ctrl[2].id = V4L2_CID_VFLIP; | |
memset(&ctrls, 0, sizeof(ctrls)); | |
ctrls.request_fd = req; | |
ctrls.which = V4L2_CTRL_WHICH_CUR_VAL; | |
ctrls.count = 3; | |
ctrls.controls = ctrl; | |
ret = ioctl(fd, VIDIOC_G_EXT_CTRLS, &ctrls); | |
if (ret < 0) { | |
perror("error while getting control value"); | |
exit(EXIT_FAILURE); | |
} | |
if (trans_time) | |
*trans_time = ctrl[0].value; | |
if (hflip) | |
*hflip = ctrl[1].value; | |
if (vflip) | |
*vflip = ctrl[2].value; | |
} | |
static void qbuf(int fd, struct v4l2_buffer *buf) | |
{ | |
int ret; | |
ret = ioctl(fd, VIDIOC_QBUF, buf); | |
if (ret < 0) { | |
perror("error while queuing buffer"); | |
exit(EXIT_FAILURE); | |
} | |
printf("%s buffer %d queued, request FD %d\n", | |
buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? "Capture" : "Output", | |
buf->index, buf->request_fd); | |
} | |
static int dqbuf(int fd, int buf_type) | |
{ | |
struct v4l2_buffer bufferinfo; | |
int ret; | |
memset(&bufferinfo, 0, sizeof bufferinfo); | |
bufferinfo.memory = V4L2_MEMORY_MMAP; | |
bufferinfo.type = buf_type; | |
ret = ioctl(fd, VIDIOC_DQBUF, &bufferinfo); | |
if (ret < 0) { | |
perror("error while dequeuing buffer"); | |
exit(EXIT_FAILURE); | |
} | |
printf("%s buffer %d dequeued, request FD %d\n", | |
buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? "Capture" : "Output", | |
bufferinfo.index, bufferinfo.request_fd); | |
return bufferinfo.index; | |
} | |
int main(int argc, char *argv[]) | |
{ | |
static const unsigned int nb_bufs = 2; | |
struct v4l2_buffer output_buf[nb_bufs]; | |
struct v4l2_buffer capture_buf[nb_bufs]; | |
int request[nb_bufs]; | |
int trans_time, hflp, vflp; | |
int fd, m_fd; | |
int i; | |
struct pollfd pfds[2] = { | |
{ | |
.events = POLLIN, | |
}, | |
{ | |
.events = POLLIN, | |
}, | |
}; | |
if (argc != 2) { | |
printf("Usage: %s /dev/video_device\n", argv[0]); | |
return 0; | |
} | |
open_devices(argv[1], &fd, &m_fd); | |
/* Set format on capture and output queues */ | |
set_format(fd, V4L2_BUF_TYPE_VIDEO_CAPTURE); | |
set_format(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT); | |
request_buffers(fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, nb_bufs); | |
request_buffers(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT, nb_bufs); | |
for (i = 0; i < nb_bufs; i++) { | |
query_buf(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT, i, &output_buf[i]); | |
output_buf[i].bytesused = output_buf[i].length; | |
query_buf(fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, i, &capture_buf[i]); | |
} | |
for (i = 0; i < nb_bufs; i++) { | |
alloc_request(m_fd, &request[i]); | |
printf("Allocated request %d\n", request[i]); | |
} | |
set_stream(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT, 1); | |
set_stream(fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, 1); | |
set_vim2m_ctrls(fd, request[0], 600, 1, 0); | |
set_vim2m_ctrls(fd, request[1], 2000, 0, 1); | |
/* Query the controls on the requests and the hardware */ | |
get_vim2m_ctrls(fd, request[0], &trans_time, &hflp, &vflp); | |
printf("Pre-submit first request transaction time: %d, hflip: %d, vflip: %d\n", | |
trans_time, hflp, vflp); | |
get_vim2m_ctrls(fd, request[1], &trans_time, &hflp, &vflp); | |
printf("Pre-submit second request transaction time: %d, hflip: %d, vflip: %d\n", | |
trans_time, hflp, vflp); | |
get_vim2m_ctrls(fd, 0, &trans_time, &hflp, &vflp); | |
printf("Pre-submit HW transaction time: %d, hflip: %d, vflip: %d\n", | |
trans_time, hflp, vflp); | |
/* Queue buffers for our first request. Even though the stream is active | |
* on both queues, streaming will not start until the request is queued */ | |
output_buf[0].request_fd = request[0]; | |
qbuf(fd, &output_buf[0]); | |
qbuf(fd, &capture_buf[0]); | |
/* Queue the request. This will apply the controls previously set and | |
* actually start streaming */ | |
queue_request(m_fd, request[0]); | |
output_buf[1].request_fd = request[1]; | |
qbuf(fd, &output_buf[1]); | |
/* The request is queued before the capture buf - this is valid, the | |
* driver will just wait for the correct number of buffers to start | |
* processing */ | |
queue_request(m_fd, request[1]); | |
qbuf(fd, &capture_buf[1]); | |
/* Poll on the requests */ | |
pfds[0].fd = request[1]; | |
pfds[1].fd = request[0]; | |
printf("Poll on first request\n"); | |
poll(pfds, 2, -1); | |
printf("%08x %08x\n", pfds[0].revents, pfds[1].revents); | |
printf("Poll on second request\n"); | |
poll(pfds, 1, -1); | |
printf("%08x\n", pfds[0].revents); | |
/* Dequeue all buffers. */ | |
for (i = 0; i < nb_bufs; i++) { | |
dqbuf(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT); | |
dqbuf(fd, V4L2_BUF_TYPE_VIDEO_CAPTURE); | |
} | |
set_stream(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT, 0); | |
set_stream(fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0); | |
/* Query the controls on the completed requests and the hardware */ | |
get_vim2m_ctrls(fd, request[0], &trans_time, &hflp, &vflp); | |
printf("Post-dequeue first request transaction time: %d, hflip: %d, vflip: %d\n", | |
trans_time, hflp, vflp); | |
get_vim2m_ctrls(fd, request[1], &trans_time, &hflp, &vflp); | |
printf("Post-dequeue second request transaction time: %d, hflip: %d, vflip: %d\n", | |
trans_time, hflp, vflp); | |
get_vim2m_ctrls(fd, 0, &trans_time, &hflp, &vflp); | |
printf("Post-dequeue HW transaction time: %d, hflip: %d, vflip: %d\n", | |
trans_time, hflp, vflp); | |
/* Close all requests */ | |
for (i = nb_bufs; i > 0; i--) | |
close(request[i - 1]); | |
request_buffers(fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0); | |
request_buffers(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT, 0); | |
close(m_fd); | |
close(fd); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment