" --stream-user=<count>\n"
" capture video using user pointers [VIDIOC_(D)QBUF]\n"
" count: the number of buffers to allocate. The default is 3.\n"
+ " --stream-dmabuf capture video using dmabuf [VIDIOC_(D)QBUF]\n"
+ " Requires a corresponding --stream-out-mmap option.\n"
" --stream-from=<file> stream from this file. The default is to generate a pattern.\n"
" If <file> is '-', then the data is read from stdin.\n"
" --stream-loop loop when the end of the file we are streaming from is reached.\n"
" --stream-out-user=<count>\n"
" output video using user pointers [VIDIOC_(D)QBUF]\n"
" count: the number of buffers to allocate. The default is 3.\n"
+ " --stream-out-dmabuf\n"
+ " output video using dmabuf [VIDIOC_(D)QBUF]\n"
+ " Requires a corresponding --stream-mmap option.\n"
" --list-buffers list all video buffers [VIDIOC_QUERYBUF]\n"
" --list-buffers-out list all video output buffers [VIDIOC_QUERYBUF]\n"
" --list-buffers-vbi list all VBI buffers [VIDIOC_QUERYBUF]\n"
class buffers {
public:
- buffers(bool is_output, bool is_mmap)
+ buffers(bool is_output)
{
type = is_output ? vidout_buftype : vidcap_buftype;
- memory = is_mmap ? V4L2_MEMORY_MMAP : V4L2_MEMORY_USERPTR;
- if (is_output)
- is_mplane = capabilities & (V4L2_CAP_VIDEO_M2M_MPLANE |
- V4L2_CAP_VIDEO_OUTPUT_MPLANE);
- else
+ if (is_output) {
+ if (options[OptStreamOutMmap])
+ memory = V4L2_MEMORY_MMAP;
+ else if (options[OptStreamOutUser])
+ memory = V4L2_MEMORY_USERPTR;
+ else if (options[OptStreamOutDmaBuf])
+ memory = V4L2_MEMORY_DMABUF;
+ is_mplane = out_capabilities & (V4L2_CAP_VIDEO_M2M_MPLANE |
+ V4L2_CAP_VIDEO_OUTPUT_MPLANE);
+ } else {
+ if (options[OptStreamMmap])
+ memory = V4L2_MEMORY_MMAP;
+ else if (options[OptStreamUser])
+ memory = V4L2_MEMORY_USERPTR;
+ else if (options[OptStreamDmaBuf])
+ memory = V4L2_MEMORY_DMABUF;
is_mplane = capabilities & (V4L2_CAP_VIDEO_M2M_MPLANE |
V4L2_CAP_VIDEO_CAPTURE_MPLANE);
+ }
+ for (int i = 0; i < VIDEO_MAX_FRAME; i++)
+ for (int p = 0; p < VIDEO_MAX_PLANES; p++)
+ fds[i][p] = -1;
+ num_planes = is_mplane ? 0 : 1;
+ }
+ ~buffers()
+ {
+ for (int i = 0; i < VIDEO_MAX_FRAME; i++)
+ for (int p = 0; p < VIDEO_MAX_PLANES; p++)
+ if (fds[i][p] != -1)
+ close(fds[i][p]);
}
public:
unsigned num_planes;
struct v4l2_plane planes[VIDEO_MAX_FRAME][VIDEO_MAX_PLANES];
void *bufs[VIDEO_MAX_FRAME][VIDEO_MAX_PLANES];
+ int fds[VIDEO_MAX_FRAME][VIDEO_MAX_PLANES];
int reqbufs(int fd, unsigned buf_count)
{
err = doioctl(fd, VIDIOC_REQBUFS, &reqbufs);
if (err >= 0)
bcount = reqbufs.count;
+ if (is_mplane) {
+ struct v4l2_plane planes[VIDEO_MAX_PLANES];
+ struct v4l2_buffer buf;
+
+ memset(&buf, 0, sizeof(buf));
+ memset(planes, 0, sizeof(planes));
+ buf.type = type;
+ buf.memory = memory;
+ buf.m.planes = planes;
+ buf.length = VIDEO_MAX_PLANES;
+ err = doioctl(fd, VIDIOC_QUERYBUF, &buf);
+ if (err)
+ return err;
+ num_planes = buf.length;
+ }
return err;
}
+
+ int expbufs(int fd, unsigned type)
+ {
+ struct v4l2_exportbuffer expbuf;
+ unsigned i, p;
+ int err;
+
+ memset(&expbuf, 0, sizeof(expbuf));
+ for (i = 0; i < bcount; i++) {
+ for (p = 0; p < num_planes; p++) {
+ expbuf.type = type;
+ expbuf.index = i;
+ expbuf.plane = p;
+ expbuf.flags = O_RDWR;
+ err = doioctl(fd, VIDIOC_EXPBUF, &expbuf);
+ if (err < 0)
+ return err;
+ if (err >= 0)
+ fds[i][p] = expbuf.fd;
+ }
+ }
+ return 0;
+ }
};
static bool fill_buffer_from_file(buffers &b, unsigned idx, FILE *fin)
return -1;
if (b.is_mplane) {
- b.num_planes = buf.length;
for (unsigned j = 0; j < b.num_planes; j++) {
struct v4l2_plane &p = b.planes[i][j];
fd, planes[j].m.mem_offset);
if (b.bufs[i][j] == MAP_FAILED) {
- fprintf(stderr, "mmap failed\n");
+ fprintf(stderr, "mmap plane %u failed\n", j);
return -1;
}
- }
- else {
+ } else if (b.memory == V4L2_MEMORY_DMABUF) {
+ b.bufs[i][j] = test_mmap(NULL, p.length,
+ PROT_READ | PROT_WRITE, MAP_SHARED,
+ b.fds[i][j], 0);
+
+ if (b.bufs[i][j] == MAP_FAILED) {
+ fprintf(stderr, "dmabuf mmap plane %u failed\n", j);
+ return -1;
+ }
+ planes[j].m.fd = b.fds[i][j];
+ } else {
b.bufs[i][j] = calloc(1, p.length);
planes[j].m.userptr = (unsigned long)b.bufs[i][j];
}
else {
struct v4l2_plane &p = b.planes[i][0];
- b.num_planes = 1;
p.length = buf.length;
if (b.memory == V4L2_MEMORY_MMAP) {
b.bufs[i][0] = test_mmap(NULL, p.length,
fprintf(stderr, "mmap failed\n");
return -1;
}
- }
- else {
+ } else if (b.memory == V4L2_MEMORY_DMABUF) {
+ b.bufs[i][0] = test_mmap(NULL, p.length,
+ PROT_READ | PROT_WRITE, MAP_SHARED,
+ b.fds[i][0], 0);
+
+ if (b.bufs[i][0] == MAP_FAILED) {
+ fprintf(stderr, "dmabuf mmap failed\n");
+ return -1;
+ }
+ buf.m.fd = b.fds[i][0];
+ } else {
b.bufs[i][0] = calloc(1, p.length);
buf.m.userptr = (unsigned long)b.bufs[i][0];
}
return 0;
}
-static int do_setup_out_buffers(int fd, buffers &b, FILE *fin)
+static int do_setup_out_buffers(int fd, buffers &b, FILE *fin, bool qbuf)
{
struct v4l2_format fmt;
memset(&fmt, 0, sizeof(fmt));
fmt.type = b.type;
doioctl(fd, VIDIOC_G_FMT, &fmt);
- if (!precalculate_bars(fmt.fmt.pix.pixelformat, stream_pat)) {
- fprintf(stderr, "unsupported pixelformat\n");
- return -1;
- }
+ bool can_fill = precalculate_bars(fmt.fmt.pix.pixelformat, stream_pat);
for (unsigned i = 0; i < b.bcount; i++) {
struct v4l2_plane planes[VIDEO_MAX_PLANES];
return -1;
if (b.is_mplane) {
- b.num_planes = buf.length;
for (unsigned j = 0; j < b.num_planes; j++) {
struct v4l2_plane &p = b.planes[i][j];
fd, planes[j].m.mem_offset);
if (b.bufs[i][j] == MAP_FAILED) {
- fprintf(stderr, "mmap failed\n");
+ fprintf(stderr, "mmap output plane %u failed\n", j);
return -1;
}
- }
- else {
+ } else if (b.memory == V4L2_MEMORY_DMABUF) {
+ b.bufs[i][j] = test_mmap(NULL, p.length,
+ PROT_READ | PROT_WRITE, MAP_SHARED,
+ b.fds[i][j], 0);
+
+ if (b.bufs[i][j] == MAP_FAILED) {
+ fprintf(stderr, "dmabuf mmap output plane %u failed\n", j);
+ return -1;
+ }
+ planes[j].m.fd = b.fds[i][j];
+ } else {
b.bufs[i][j] = calloc(1, p.length);
planes[j].m.userptr = (unsigned long)b.bufs[i][j];
}
fill_buffer_from_file(b, buf.index, fin);
}
else {
- b.num_planes = 1;
b.planes[i][0].length = buf.length;
buf.bytesused = buf.length;
if (b.memory == V4L2_MEMORY_MMAP) {
PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
if (b.bufs[i][0] == MAP_FAILED) {
- fprintf(stderr, "mmap failed\n");
+ fprintf(stderr, "mmap output failed\n");
return -1;
}
- }
- else {
+ } else if (b.memory == V4L2_MEMORY_DMABUF) {
+ b.bufs[i][0] = test_mmap(NULL, buf.length,
+ PROT_READ | PROT_WRITE, MAP_SHARED,
+ b.fds[i][0], 0);
+
+ if (b.bufs[i][0] == MAP_FAILED) {
+ fprintf(stderr, "dmabuf mmap output failed\n");
+ return -1;
+ }
+ buf.m.fd = b.fds[i][0];
+ } else {
b.bufs[i][0] = calloc(1, buf.length);
buf.m.userptr = (unsigned long)b.bufs[i][0];
}
if (!fin || !fill_buffer_from_file(b, buf.index, fin))
- fill_buffer(b.bufs[i][0], &fmt.fmt.pix);
+ if (can_fill)
+ fill_buffer(b.bufs[i][0], &fmt.fmt.pix);
+ }
+ if (qbuf) {
+ if (V4L2_TYPE_IS_OUTPUT(buf.type))
+ setTimeStamp(buf);
+ if (doioctl(fd, VIDIOC_QBUF, &buf))
+ return -1;
}
- if (V4L2_TYPE_IS_OUTPUT(buf.type))
- setTimeStamp(buf);
- if (doioctl(fd, VIDIOC_QBUF, &buf))
- return -1;
}
return 0;
}
{
for (unsigned i = 0; i < b.bcount; i++) {
for (unsigned j = 0; j < b.num_planes; j++) {
- if (b.memory == V4L2_MEMORY_MMAP)
- munmap(b.bufs[i][j], b.planes[i][j].length);
- else
+ if (b.memory == V4L2_MEMORY_USERPTR)
free(b.bufs[i][j]);
+ else
+ munmap(b.bufs[i][j], b.planes[i][j].length);
}
}
}
-static int do_handle_cap(int fd, buffers &b, FILE *fout,
+static int do_handle_cap(int fd, buffers &b, FILE *fout, int *index,
unsigned &count, unsigned &last, struct timeval &tv_last)
{
char ch = '<';
ch = 'B';
if (verbose)
print_buffer(stderr, buf);
- if (test_ioctl(fd, VIDIOC_QBUF, &buf))
+ if (index == NULL && test_ioctl(fd, VIDIOC_QBUF, &buf))
return -1;
+ if (index)
+ *index = buf.index;
if (!verbose) {
fprintf(stderr, "%c", ch);
return 0;
}
-static int do_handle_out(int fd, buffers &b, FILE *fin,
+static int do_handle_out(int fd, buffers &b, FILE *fin, struct v4l2_buffer *cap,
unsigned &count, unsigned &last, struct timeval &tv_last)
{
struct v4l2_plane planes[VIDEO_MAX_PLANES];
buf.length = VIDEO_MAX_PLANES;
}
- ret = test_ioctl(fd, VIDIOC_DQBUF, &buf);
- if (ret < 0 && errno == EAGAIN)
- return 0;
+ if (cap) {
+ buf.index = cap->index;
+ ret = test_ioctl(fd, VIDIOC_QUERYBUF, &buf);
+ if (b.is_mplane) {
+ for (unsigned j = 0; j < b.num_planes; j++) {
+ unsigned bytesused = cap->m.planes[j].bytesused;
+ unsigned data_offset = cap->m.planes[j].data_offset;
+
+ if (b.memory == V4L2_MEMORY_USERPTR) {
+ planes[j].m.userptr = (unsigned long)cap->m.planes[j].m.userptr + data_offset;
+ planes[j].bytesused = cap->m.planes[j].bytesused - data_offset;
+ planes[j].data_offset = 0;
+ } else if (b.memory == V4L2_MEMORY_DMABUF) {
+ planes[j].m.fd = b.fds[cap->index][j];
+ planes[j].bytesused = bytesused;
+ planes[j].data_offset = data_offset;
+ }
+ }
+ }
+ else {
+ buf.bytesused = cap->bytesused;
+ if (b.memory == V4L2_MEMORY_USERPTR)
+ buf.m.userptr = (unsigned long)cap->m.userptr;
+ else if (b.memory == V4L2_MEMORY_DMABUF)
+ buf.m.fd = b.fds[cap->index][0];
+ }
+ } else {
+ ret = test_ioctl(fd, VIDIOC_DQBUF, &buf);
+ if (ret < 0 && errno == EAGAIN)
+ return 0;
+ if (b.is_mplane) {
+ for (unsigned j = 0; j < buf.length; j++)
+ buf.m.planes[j].bytesused = buf.m.planes[j].length;
+ } else {
+ buf.bytesused = buf.length;
+ }
+ }
if (ret < 0) {
fprintf(stderr, "%s: failed: %s\n", "VIDIOC_DQBUF", strerror(errno));
return -1;
}
if (fin && !fill_buffer_from_file(b, buf.index, fin))
return -1;
- if (b.is_mplane) {
- for (unsigned j = 0; j < buf.length; j++)
- buf.m.planes[j].bytesused = buf.m.planes[j].length;
- } else {
- buf.bytesused = buf.length;
- }
if (V4L2_TYPE_IS_OUTPUT(buf.type))
setTimeStamp(buf);
- if (test_ioctl(fd, VIDIOC_QBUF, &buf))
+ if (test_ioctl(fd, VIDIOC_QBUF, &buf)) {
+ fprintf(stderr, "%s: failed: %s\n", "VIDIOC_QBUF", strerror(errno));
return -1;
+ }
fprintf(stderr, ">");
fflush(stderr);
return 0;
}
+static int do_handle_out_to_in(int out_fd, int fd, buffers &out, buffers &in)
+{
+ struct v4l2_plane planes[VIDEO_MAX_PLANES];
+ struct v4l2_buffer buf;
+ int ret;
+
+ memset(&buf, 0, sizeof(buf));
+ memset(planes, 0, sizeof(planes));
+ buf.type = out.type;
+ buf.memory = out.memory;
+ if (out.is_mplane) {
+ buf.m.planes = planes;
+ buf.length = VIDEO_MAX_PLANES;
+ }
+
+ do {
+ ret = test_ioctl(out_fd, VIDIOC_DQBUF, &buf);
+ } while (ret < 0 && errno == EAGAIN);
+ if (ret < 0) {
+ fprintf(stderr, "%s: failed: %s\n", "VIDIOC_DQBUF", strerror(errno));
+ return -1;
+ }
+ memset(planes, 0, sizeof(planes));
+ buf.type = in.type;
+ buf.memory = in.memory;
+ if (in.is_mplane) {
+ buf.m.planes = planes;
+ buf.length = VIDEO_MAX_PLANES;
+ }
+ ret = test_ioctl(fd, VIDIOC_QUERYBUF, &buf);
+ if (ret == 0)
+ ret = test_ioctl(fd, VIDIOC_QBUF, &buf);
+ if (ret < 0) {
+ fprintf(stderr, "%s: failed: %s\n", "VIDIOC_QBUF", strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
static void streaming_set_cap(int fd)
{
struct v4l2_event_subscription sub;
int fd_flags = fcntl(fd, F_GETFL);
- buffers b(false, options[OptStreamMmap]);
+ buffers b(false);
bool use_poll = options[OptStreamPoll];
unsigned count = 0, last = 0;
struct timeval tv_last;
bool eos = false;
FILE *fout = NULL;
- if (!(capabilities & V4L2_CAP_VIDEO_CAPTURE) &&
- !(capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE)) {
+ if (!(capabilities & (V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+ V4L2_CAP_VIDEO_M2M |
+ V4L2_CAP_VIDEO_M2M_MPLANE))) {
fprintf(stderr, "unsupported stream type\n");
return;
}
+ if (options[OptStreamDmaBuf]) {
+ fprintf(stderr, "--stream-dmabuf can only work in combination with --stream-out-mmap\n");
+ return;
+ }
memset(&sub, 0, sizeof(sub));
sub.type = V4L2_EVENT_EOS;
}
if (FD_ISSET(fd, &read_fds)) {
- r = do_handle_cap(fd, b, fout,
+ r = do_handle_cap(fd, b, fout, NULL,
count, last, tv_last);
if (r == -1)
break;
static void streaming_set_out(int fd)
{
- buffers b(true, options[OptStreamOutMmap]);
+ buffers b(true);
int fd_flags = fcntl(fd, F_GETFL);
bool use_poll = options[OptStreamPoll];
unsigned count = 0, last = 0;
struct timeval tv_last;
FILE *fin = NULL;
- if (!(capabilities & V4L2_CAP_VIDEO_OUTPUT) &&
- !(capabilities & V4L2_CAP_VIDEO_OUTPUT_MPLANE)) {
+ if (!(capabilities & (V4L2_CAP_VIDEO_OUTPUT |
+ V4L2_CAP_VIDEO_OUTPUT_MPLANE |
+ V4L2_CAP_VIDEO_M2M |
+ V4L2_CAP_VIDEO_M2M_MPLANE))) {
fprintf(stderr, "unsupported stream type\n");
return;
}
+ if (options[OptStreamOutDmaBuf]) {
+ fprintf(stderr, "--stream-out-dmabuf can only work in combination with --stream-mmap\n");
+ return;
+ }
if (file_out) {
if (!strcmp(file_out, "-"))
if (b.reqbufs(fd, reqbufs_count_out))
goto done;
- if (do_setup_out_buffers(fd, b, fin))
+ if (do_setup_out_buffers(fd, b, fin, true))
goto done;
if (doioctl(fd, VIDIOC_STREAMON, &b.type))
goto done;
}
}
- r = do_handle_out(fd, b, fin,
+ r = do_handle_out(fd, b, fin, NULL,
count, last, tv_last);
if (r == -1)
break;
{
int fd_flags = fcntl(fd, F_GETFL);
bool use_poll = options[OptStreamPoll];
- buffers in(false, options[OptStreamMmap]);
- buffers out(true, options[OptStreamOutMmap]);
+ buffers in(false);
+ buffers out(true);
unsigned count[2] = { 0, 0 };
unsigned last[2] = { 0, 0 };
struct timeval tv_last[2];
fd_set *ex_fds = &fds[1]; /* for capture */
fd_set *wr_fds = &fds[2]; /* for output */
- if (!(capabilities & V4L2_CAP_VIDEO_M2M) &&
- !(capabilities & V4L2_CAP_VIDEO_M2M_MPLANE)) {
- fprintf(stderr, "unsupported stream type\n");
+ if (!(capabilities & (V4L2_CAP_VIDEO_M2M |
+ V4L2_CAP_VIDEO_M2M_MPLANE))) {
+ fprintf(stderr, "unsupported m2m stream type\n");
+ return;
+ }
+ if (options[OptStreamDmaBuf] || options[OptStreamOutDmaBuf]) {
+ fprintf(stderr, "--stream-dmabuf or --stream-out-dmabuf not supported for m2m devices\n");
return;
}
goto done;
if (do_setup_cap_buffers(fd, in) ||
- do_setup_out_buffers(fd, out, file[OUT]))
+ do_setup_out_buffers(fd, out, file[OUT], true))
goto done;
if (doioctl(fd, VIDIOC_STREAMON, &in.type) ||
}
if (rd_fds && FD_ISSET(fd, rd_fds)) {
- r = do_handle_cap(fd, in, file[CAP],
+ r = do_handle_cap(fd, in, file[CAP], NULL,
count[CAP], last[CAP], tv_last[CAP]);
if (r < 0) {
rd_fds = NULL;
}
if (wr_fds && FD_ISSET(fd, wr_fds)) {
- r = do_handle_out(fd, out, file[OUT],
+ r = do_handle_out(fd, out, file[OUT], NULL,
count[OUT], last[OUT], tv_last[OUT]);
if (r < 0) {
wr_fds = NULL;
struct v4l2_event ev;
while (!ioctl(fd, VIDIOC_DQEVENT, &ev)) {
-
if (ev.type != V4L2_EVENT_EOS)
continue;
fclose(file[OUT]);
}
-void streaming_set(int fd)
+static void streaming_set_cap2out(int fd, int out_fd)
{
- bool do_cap = options[OptStreamMmap] || options[OptStreamUser];
- bool do_out = options[OptStreamOutMmap] || options[OptStreamOutUser];
+ int fd_flags = fcntl(fd, F_GETFL);
+ bool use_poll = options[OptStreamPoll];
+ bool use_dmabuf = options[OptStreamDmaBuf] || options[OptStreamOutDmaBuf];
+ bool use_userptr = options[OptStreamUser] && options[OptStreamOutUser];
+ buffers in(false);
+ buffers out(true);
+ unsigned count[2] = { 0, 0 };
+ unsigned last[2] = { 0, 0 };
+ struct timeval tv_last[2];
+ FILE *file[2] = {NULL, NULL};
+ fd_set fds;
+ unsigned cnt = 0;
+
+ if (!(capabilities & (V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+ V4L2_CAP_VIDEO_M2M |
+ V4L2_CAP_VIDEO_M2M_MPLANE))) {
+ fprintf(stderr, "unsupported capture stream type\n");
+ return;
+ } else if (!(out_capabilities & (V4L2_CAP_VIDEO_OUTPUT |
+ V4L2_CAP_VIDEO_OUTPUT_MPLANE |
+ V4L2_CAP_VIDEO_M2M |
+ V4L2_CAP_VIDEO_M2M_MPLANE))) {
+ fprintf(stderr, "unsupported output stream type\n");
+ return;
+ }
+ if (options[OptStreamDmaBuf] && !options[OptStreamOutMmap]) {
+ fprintf(stderr, "--stream-dmabuf can only work in combination with --stream-out-mmap\n");
+ return;
+ }
+ if (options[OptStreamOutDmaBuf] && !options[OptStreamMmap]) {
+ fprintf(stderr, "--stream-out-dmabuf can only work in combination with --stream-mmap\n");
+ return;
+ }
+ if (options[OptStreamDmaBuf])
+ reqbufs_count_cap = reqbufs_count_out;
+ if (options[OptStreamOutDmaBuf])
+ reqbufs_count_out = reqbufs_count_cap;
+ if (!use_dmabuf && !use_userptr) {
+ fprintf(stderr, "Allowed combinations (for now):\n");
+ fprintf(stderr, "\t--stream-mmap and --stream-out-dmabuf\n");
+ fprintf(stderr, "\t--stream-dmabuf and --stream-out-mmap\n");
+ fprintf(stderr, "\t--stream-user and --stream-out-user\n");
+ return;
+ }
+
+ if (file_cap) {
+ if (!strcmp(file_cap, "-"))
+ file[CAP] = stdout;
+ else
+ file[CAP] = fopen(file_cap, "w+");
+ }
+
+ if (file_out) {
+ if (!strcmp(file_out, "-"))
+ file[OUT] = stdin;
+ else
+ file[OUT] = fopen(file_out, "r");
+ }
+
+ if (in.reqbufs(fd, reqbufs_count_cap) ||
+ out.reqbufs(out_fd, reqbufs_count_out))
+ goto done;
+
+ if (options[OptStreamDmaBuf]) {
+ if (in.expbufs(out_fd, out.type))
+ goto done;
+ } else if (options[OptStreamOutDmaBuf]) {
+ if (out.expbufs(fd, in.type))
+ goto done;
+ }
+
+ if (in.num_planes != out.num_planes ||
+ in.is_mplane != out.is_mplane) {
+ fprintf(stderr, "mismatch between number of planes\n");
+ goto done;
+ }
+
+ if (do_setup_cap_buffers(fd, in) ||
+ do_setup_out_buffers(out_fd, out, file[OUT], false))
+ goto done;
+
+ if (doioctl(fd, VIDIOC_STREAMON, &in.type) ||
+ doioctl(out_fd, VIDIOC_STREAMON, &out.type))
+ goto done;
+
+ if (use_poll)
+ fcntl(fd, F_SETFL, fd_flags | O_NONBLOCK);
+
+ while (1) {
+ struct timeval tv = { use_poll ? 2 : 0, 0 };
+ int r = 0;
- if (do_cap && do_out)
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+
+ if (use_poll)
+ r = select(fd + 1, &fds, NULL, NULL, &tv);
+
+ if (r == -1) {
+ if (EINTR == errno)
+ continue;
+ fprintf(stderr, "select error: %s\n",
+ strerror(errno));
+ goto done;
+ }
+ if (use_poll && r == 0) {
+ fprintf(stderr, "select timeout\n");
+ goto done;
+ }
+
+ if (FD_ISSET(fd, &fds)) {
+ int index = -1;
+
+ r = do_handle_cap(fd, in, file[CAP], &index,
+ count[CAP], last[CAP], tv_last[CAP]);
+ if (r)
+ fprintf(stderr, "handle cap %d\n", r);
+ if (!r) {
+ struct v4l2_plane planes[VIDEO_MAX_PLANES];
+ struct v4l2_buffer buf;
+
+ memset(&buf, 0, sizeof(buf));
+ buf.type = in.type;
+ buf.index = index;
+ if (in.is_mplane) {
+ buf.m.planes = planes;
+ buf.length = VIDEO_MAX_PLANES;
+ memset(planes, 0, sizeof(planes));
+ }
+ if (test_ioctl(fd, VIDIOC_QUERYBUF, &buf))
+ break;
+ r = do_handle_out(out_fd, out, file[OUT], &buf,
+ count[OUT], last[OUT], tv_last[OUT]);
+ }
+ if (r)
+ fprintf(stderr, "handle out %d\n", r);
+ if (!r && cnt++ > 1)
+ r = do_handle_out_to_in(out_fd, fd, out, in);
+ if (r)
+ fprintf(stderr, "handle out2in %d\n", r);
+ if (r < 0) {
+ doioctl(fd, VIDIOC_STREAMOFF, &in.type);
+ doioctl(out_fd, VIDIOC_STREAMOFF, &out.type);
+ break;
+ }
+ }
+ }
+
+ fcntl(fd, F_SETFL, fd_flags);
+ fprintf(stderr, "\n");
+
+ do_release_buffers(in);
+ do_release_buffers(out);
+
+done:
+ if (file[CAP] && file[CAP] != stdout)
+ fclose(file[CAP]);
+
+ if (file[OUT] && file[OUT] != stdin)
+ fclose(file[OUT]);
+}
+
+void streaming_set(int fd, int out_fd)
+{
+ int do_cap = options[OptStreamMmap] + options[OptStreamUser] + options[OptStreamDmaBuf];
+ int do_out = options[OptStreamOutMmap] + options[OptStreamOutUser] + options[OptStreamOutDmaBuf];
+
+ if (out_fd < 0) {
+ out_fd = fd;
+ out_capabilities = capabilities;
+ }
+
+ if (do_cap > 1) {
+ fprintf(stderr, "only one of --stream-mmap/user/dmabuf is allowed\n");
+ return;
+ }
+ if (do_out > 1) {
+ fprintf(stderr, "only one of --stream-out-mmap/user/dmabuf is allowed\n");
+ return;
+ }
+
+ if (do_cap && do_out && fd == out_fd)
streaming_set_m2m(fd);
+ else if (do_cap && do_out)
+ streaming_set_cap2out(fd, out_fd);
else if (do_cap)
streaming_set_cap(fd);
else if (do_out)
streaming_set_out(fd);
}
-void streaming_list(int fd)
+void streaming_list(int fd, int out_fd)
{
+ if (out_fd < 0) {
+ out_fd = fd;
+ out_capabilities = capabilities;
+ }
+
if (options[OptListBuffers]) {
list_buffers(fd, vidcap_buftype);
}
if (options[OptListBuffersOut]) {
- list_buffers(fd, vidout_buftype);
+ list_buffers(out_fd, vidout_buftype);
}
if (options[OptListBuffersVbi]) {
}
if (options[OptListBuffersVbiOut]) {
- list_buffers(fd, V4L2_BUF_TYPE_VBI_OUTPUT);
+ list_buffers(out_fd, V4L2_BUF_TYPE_VBI_OUTPUT);
}
if (options[OptListBuffersSlicedVbiOut]) {
- list_buffers(fd, V4L2_BUF_TYPE_SLICED_VBI_OUTPUT);
+ list_buffers(out_fd, V4L2_BUF_TYPE_SLICED_VBI_OUTPUT);
}
}