On 8/8/19 10:02 PM, André Almeida wrote: > v4l2-compliance tests deals with memory-to-memory devices (m2m) like > they are a single device, through the struct node. This is indeed the > most usual case. However, there are m2m devices that have two > separated devices for the capture queue and for the output queue, and > the current design does not support they. > > Split the node on testNode and related functions in two arguments: > struct node node and struct node node_m2m_cap. For now, use the same node in > both arguments. > > Signed-off-by: André Almeida <andrealmeid@xxxxxxxxxxxxx> > --- > Hello, > > This is an effort to support topologies with video loopback (i.e. an > output device and a capture in the same media path). A future patch will > add a new option (--output) to specify the output device to be used with > the --device to form the loopback. With that option, the arguments node > and node_m2m_cap would not be the same device, as in this patch. > I may forgot to replace in some function, please notify my if you find > something missing. > I believe it also worth saying that I tested the modification with vivid and vim2m and the tool behave as expected (all tests succeed). > Thanks, > André > > utils/v4l2-compliance/v4l2-compliance.cpp | 20 ++--- > utils/v4l2-compliance/v4l2-compliance.h | 22 +++++- > utils/v4l2-compliance/v4l2-test-buffers.cpp | 88 +++++++++++---------- > utils/v4l2-compliance/v4l2-test-media.cpp | 2 +- > 4 files changed, 74 insertions(+), 58 deletions(-) > > diff --git a/utils/v4l2-compliance/v4l2-compliance.cpp b/utils/v4l2-compliance/v4l2-compliance.cpp > index fbeb96be..d9509064 100644 > --- a/utils/v4l2-compliance/v4l2-compliance.cpp > +++ b/utils/v4l2-compliance/v4l2-compliance.cpp > @@ -908,7 +908,7 @@ err: > return result; > } > > -void testNode(struct node &node, struct node &expbuf_node, media_type type, > +void testNode(struct node &node, struct node &node_m2m_cap, struct node &expbuf_node, media_type type, > unsigned frame_count, unsigned all_fmt_frame_count) > { > struct node node2; > @@ -1333,33 +1333,33 @@ void testNode(struct node &node, struct node &expbuf_node, media_type type, > node.reopen(); > if (!(node.codec_mask & (STATEFUL_ENCODER | STATEFUL_DECODER))) { > printf("\ttest MMAP (no poll): %s\n", > - ok(testMmap(&node, frame_count, POLL_MODE_NONE))); > + ok(testMmap(&node, &node_m2m_cap, frame_count, POLL_MODE_NONE))); > node.reopen(); > } > printf("\ttest MMAP (select): %s\n", > - ok(testMmap(&node, frame_count, POLL_MODE_SELECT))); > + ok(testMmap(&node, &node_m2m_cap, frame_count, POLL_MODE_SELECT))); > node.reopen(); > printf("\ttest MMAP (epoll): %s\n", > - ok(testMmap(&node, frame_count, POLL_MODE_EPOLL))); > + ok(testMmap(&node, &node_m2m_cap, frame_count, POLL_MODE_EPOLL))); > node.reopen(); > if (!(node.codec_mask & (STATEFUL_ENCODER | STATEFUL_DECODER))) { > printf("\ttest USERPTR (no poll): %s\n", > - ok(testUserPtr(&node, frame_count, POLL_MODE_NONE))); > + ok(testUserPtr(&node, &node_m2m_cap, frame_count, POLL_MODE_NONE))); > node.reopen(); > } > printf("\ttest USERPTR (select): %s\n", > - ok(testUserPtr(&node, frame_count, POLL_MODE_SELECT))); > + ok(testUserPtr(&node, &node_m2m_cap, frame_count, POLL_MODE_SELECT))); > node.reopen(); > if (options[OptSetExpBufDevice] || > !(node.valid_memorytype & (1 << V4L2_MEMORY_DMABUF))) { > if (!(node.codec_mask & (STATEFUL_ENCODER | STATEFUL_DECODER))) { > printf("\ttest DMABUF (no poll): %s\n", > - ok(testDmaBuf(&expbuf_node, &node, frame_count, > - POLL_MODE_NONE))); > + ok(testDmaBuf(&expbuf_node, &node, &node_m2m_cap, > + frame_count, POLL_MODE_NONE))); > node.reopen(); > } > printf("\ttest DMABUF (select): %s\n", > - ok(testDmaBuf(&expbuf_node, &node, frame_count, POLL_MODE_SELECT))); > + ok(testDmaBuf(&expbuf_node, &node, &node_m2m_cap, frame_count, POLL_MODE_SELECT))); > node.reopen(); > } else if (!options[OptSetExpBufDevice]) { > printf("\ttest DMABUF: Cannot test, specify --expbuf-device\n"); > @@ -1707,7 +1707,7 @@ int main(int argc, char **argv) > } > } > > - testNode(node, expbuf_node, type, frame_count, all_fmt_frame_count); > + testNode(node, node, expbuf_node, type, frame_count, all_fmt_frame_count); > > if (!expbuf_device.empty()) > expbuf_node.close(); > diff --git a/utils/v4l2-compliance/v4l2-compliance.h b/utils/v4l2-compliance/v4l2-compliance.h > index 152a6c6d..6aba3828 100644 > --- a/utils/v4l2-compliance/v4l2-compliance.h > +++ b/utils/v4l2-compliance/v4l2-compliance.h > @@ -258,7 +258,7 @@ int check_string(const char *s, size_t len); > int check_ustring(const __u8 *s, int len); > int check_0(const void *p, int len); > int restoreFormat(struct node *node); > -void testNode(struct node &node, struct node &expbuf_node, media_type type, > +void testNode(struct node &node, struct node &node_m2m_cap, struct node &expbuf_node, media_type type, > unsigned frame_count, unsigned all_fmt_frame_count); > std::string stream_from(std::string pixelformat, bool &use_hdr); > > @@ -331,9 +331,23 @@ int testReqBufs(struct node *node); > int testReadWrite(struct node *node); > int testExpBuf(struct node *node); > int testBlockingWait(struct node *node); > -int testMmap(struct node *node, unsigned frame_count, enum poll_mode pollmode); > -int testUserPtr(struct node *node, unsigned frame_count, enum poll_mode pollmode); > -int testDmaBuf(struct node *expbuf_node, struct node *node, unsigned frame_count, > +/* > + * struct node node: > + * the current media node being tested > + * > + * struct node node_m2m_cap: > + * the capture device to be used when testing loopback or m2m, for > + * instance, if the node we are testing is m2m, then node == node_m2m_cap, > + * but if we have a topology like output->capture, node will be the output > + * and node_m2m_cap will be the capture device that v4l2-compliance will > + * use to test the loop > + */ > +int testMmap(struct node *node, struct node *node_m2m_cap, unsigned frame_count, > + enum poll_mode pollmode); > +int testUserPtr(struct node *node, struct node *node_m2m_cap, > + unsigned frame_count, enum poll_mode pollmode); > +int testDmaBuf(struct node *expbuf_node, struct node *node, > + struct node *node_m2m_cap, unsigned frame_count, > enum poll_mode pollmode); > int testRequests(struct node *node, bool test_streaming); > void streamAllFormats(struct node *node, unsigned frame_count); > diff --git a/utils/v4l2-compliance/v4l2-test-buffers.cpp b/utils/v4l2-compliance/v4l2-test-buffers.cpp > index fefe3e7b..029d0ed0 100644 > --- a/utils/v4l2-compliance/v4l2-test-buffers.cpp > +++ b/utils/v4l2-compliance/v4l2-test-buffers.cpp > @@ -836,7 +836,7 @@ static int setupM2M(struct node *node, cv4l_queue &q, bool init = true) > return 0; > } > > -static int captureBufs(struct node *node, const cv4l_queue &q, > +static int captureBufs(struct node *node, struct node *node_m2m_cap, const cv4l_queue &q, > cv4l_queue &m2m_q, unsigned frame_count, int pollmode, > unsigned &capture_count) > { > @@ -885,8 +885,8 @@ static int captureBufs(struct node *node, const cv4l_queue &q, > V4L2_FMT_FLAG_COMPRESSED) > valid_output_flags = V4L2_BUF_FLAG_TIMECODE | V4L2_BUF_FLAG_TSTAMP_SRC_MASK; > if (node->is_m2m) { > - node->g_fmt(fmt_q, m2m_q.g_type()); > - if (node->buftype_pixfmts[m2m_q.g_type()][fmt_q.g_pixelformat()] & > + node_m2m_cap->g_fmt(fmt_q, m2m_q.g_type()); > + if (node_m2m_cap->buftype_pixfmts[m2m_q.g_type()][fmt_q.g_pixelformat()] & > V4L2_FMT_FLAG_COMPRESSED) > valid_output_flags = V4L2_BUF_FLAG_TIMECODE | V4L2_BUF_FLAG_TSTAMP_SRC_MASK; > > @@ -1045,7 +1045,7 @@ static int captureBufs(struct node *node, const cv4l_queue &q, > > buf.init(m2m_q); > do { > - ret = buf.dqbuf(node); > + ret = buf.dqbuf(node_m2m_cap); > } while (ret == EAGAIN); > capture_count++; > > @@ -1072,16 +1072,16 @@ static int captureBufs(struct node *node, const cv4l_queue &q, > } > fail_on_test(buf.g_flags() & V4L2_BUF_FLAG_DONE); > if (!count || stopped) { > - if (!(node->codec_mask & (STATEFUL_ENCODER | STATEFUL_DECODER))) > + if (!(node_m2m_cap->codec_mask & (STATEFUL_ENCODER | STATEFUL_DECODER))) > break; > if (buf.g_flags() & V4L2_BUF_FLAG_LAST) { > - fail_on_test(buf.dqbuf(node) != EPIPE); > + fail_on_test(buf.dqbuf(node_m2m_cap) != EPIPE); > fail_on_test(!got_eos && !got_source_change); > if (!count) > break; > - fail_on_test(node->streamoff(m2m_q.g_type())); > - m2m_q.munmap_bufs(node); > - fail_on_test(setupM2M(node, m2m_q, false)); > + fail_on_test(node_m2m_cap->streamoff(m2m_q.g_type())); > + m2m_q.munmap_bufs(node_m2m_cap); > + fail_on_test(setupM2M(node_m2m_cap, m2m_q, false)); > stopped = false; > got_source_change = false; > > @@ -1089,12 +1089,12 @@ static int captureBufs(struct node *node, const cv4l_queue &q, > > memset(&cmd, 0, sizeof(cmd)); > cmd.cmd = V4L2_DEC_CMD_START; > - fail_on_test(doioctl(node, VIDIOC_DECODER_CMD, &cmd)); > + fail_on_test(doioctl(node_m2m_cap, VIDIOC_DECODER_CMD, &cmd)); > continue; > } > } > buf.s_flags(buf.g_flags() & ~V4L2_BUF_FLAG_REQUEST_FD); > - fail_on_test(buf.qbuf(node, m2m_q)); > + fail_on_test(buf.qbuf(node_m2m_cap, m2m_q)); > // If the queued buffer is immediately returned as a last > // empty buffer, then FLAG_DONE is set here. > // Need to look at this more closely. > @@ -1210,7 +1210,8 @@ static int setupMmap(struct node *node, cv4l_queue &q) > return 0; > } > > -int testMmap(struct node *node, unsigned frame_count, enum poll_mode pollmode) > +int testMmap(struct node *node, struct node *node_m2m_cap, unsigned frame_count, > + enum poll_mode pollmode) > { > bool can_stream = node->g_caps() & V4L2_CAP_STREAMING; > bool have_createbufs = true; > @@ -1338,15 +1339,15 @@ int testMmap(struct node *node, unsigned frame_count, enum poll_mode pollmode) > fail_on_test(ev.type != V4L2_EVENT_SOURCE_CHANGE); > fail_on_test(!(ev.u.src_change.changes & V4L2_EVENT_SRC_CH_RESOLUTION)); > } > - fail_on_test(setupM2M(node, m2m_q)); > + fail_on_test(setupM2M(node_m2m_cap, m2m_q)); > } > > - fail_on_test(captureBufs(node, q, m2m_q, frame_count, > + fail_on_test(captureBufs(node, node_m2m_cap, q, m2m_q, frame_count, > pollmode, capture_count)); > fail_on_test(node->streamoff(q.g_type())); > fail_on_test(node->streamoff(q.g_type())); > if (node->is_m2m) > - fail_on_test(node->streamoff(m2m_q.g_type())); > + fail_on_test(node_m2m_cap->streamoff(m2m_q.g_type())); > > if (node->codec_mask & STATEFUL_ENCODER) { > struct v4l2_encoder_cmd cmd; > @@ -1357,7 +1358,7 @@ int testMmap(struct node *node, unsigned frame_count, enum poll_mode pollmode) > > /* No buffers are queued, call STREAMON, then STOP */ > fail_on_test(node->streamon(q.g_type())); > - fail_on_test(node->streamon(m2m_q.g_type())); > + fail_on_test(node_m2m_cap->streamon(m2m_q.g_type())); > fail_on_test(doioctl(node, VIDIOC_ENCODER_CMD, &cmd)); > > fail_on_test(buf_cap.querybuf(node, 0)); > @@ -1367,11 +1368,11 @@ int testMmap(struct node *node, unsigned frame_count, enum poll_mode pollmode) > for (unsigned p = 0; p < buf_cap.g_num_planes(); p++) > fail_on_test(buf_cap.g_bytesused(p)); > fail_on_test(node->streamoff(q.g_type())); > - fail_on_test(node->streamoff(m2m_q.g_type())); > + fail_on_test(node_m2m_cap->streamoff(m2m_q.g_type())); > > /* Call STREAMON, queue one CAPTURE buffer, then STOP */ > fail_on_test(node->streamon(q.g_type())); > - fail_on_test(node->streamon(m2m_q.g_type())); > + fail_on_test(node_m2m_cap->streamon(m2m_q.g_type())); > fail_on_test(buf_cap.querybuf(node, 0)); > fail_on_test(buf_cap.qbuf(node)); > fail_on_test(doioctl(node, VIDIOC_ENCODER_CMD, &cmd)); > @@ -1381,7 +1382,7 @@ int testMmap(struct node *node, unsigned frame_count, enum poll_mode pollmode) > for (unsigned p = 0; p < buf_cap.g_num_planes(); p++) > fail_on_test(buf_cap.g_bytesused(p)); > fail_on_test(node->streamoff(q.g_type())); > - fail_on_test(node->streamoff(m2m_q.g_type())); > + fail_on_test(node_m2m_cap->streamoff(m2m_q.g_type())); > } > > if (node->codec_mask & STATEFUL_DECODER) { > @@ -1393,7 +1394,7 @@ int testMmap(struct node *node, unsigned frame_count, enum poll_mode pollmode) > > /* No buffers are queued, call STREAMON, then STOP */ > fail_on_test(node->streamon(q.g_type())); > - fail_on_test(node->streamon(m2m_q.g_type())); > + fail_on_test(node_m2m_cap->streamon(m2m_q.g_type())); > fail_on_test(doioctl(node, VIDIOC_DECODER_CMD, &cmd)); > > fail_on_test(buf_cap.querybuf(node, 0)); > @@ -1403,11 +1404,11 @@ int testMmap(struct node *node, unsigned frame_count, enum poll_mode pollmode) > for (unsigned p = 0; p < buf_cap.g_num_planes(); p++) > fail_on_test(buf_cap.g_bytesused(p)); > fail_on_test(node->streamoff(q.g_type())); > - fail_on_test(node->streamoff(m2m_q.g_type())); > + fail_on_test(node_m2m_cap->streamoff(m2m_q.g_type())); > > /* Call STREAMON, queue one CAPTURE buffer, then STOP */ > fail_on_test(node->streamon(q.g_type())); > - fail_on_test(node->streamon(m2m_q.g_type())); > + fail_on_test(node_m2m_cap->streamon(m2m_q.g_type())); > fail_on_test(buf_cap.querybuf(node, 0)); > fail_on_test(buf_cap.qbuf(node)); > fail_on_test(doioctl(node, VIDIOC_DECODER_CMD, &cmd)); > @@ -1417,7 +1418,7 @@ int testMmap(struct node *node, unsigned frame_count, enum poll_mode pollmode) > for (unsigned p = 0; p < buf_cap.g_num_planes(); p++) > fail_on_test(buf_cap.g_bytesused(p)); > fail_on_test(node->streamoff(q.g_type())); > - fail_on_test(node->streamoff(m2m_q.g_type())); > + fail_on_test(node_m2m_cap->streamoff(m2m_q.g_type())); > } > > if (node->supports_orphaned_bufs) { > @@ -1436,15 +1437,15 @@ int testMmap(struct node *node, unsigned frame_count, enum poll_mode pollmode) > if (node->is_m2m) { > if (node->supports_orphaned_bufs) { > fail_on_test(m2m_q.reqbufs(node, 0)); > - m2m_q.munmap_bufs(node); > + m2m_q.munmap_bufs(node_m2m_cap); > } else if (m2m_q.reqbufs(node, 0) != EBUSY) { > // It's either a bug or this driver should set > // V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS > warn("Can free buffers even if still mmap()ed\n"); > q.munmap_bufs(node); > } else { > - m2m_q.munmap_bufs(node); > - fail_on_test(m2m_q.reqbufs(node, 0)); > + m2m_q.munmap_bufs(node_m2m_cap); > + fail_on_test(m2m_q.reqbufs(node_m2m_cap, 0)); > } > fail_on_test(!capture_count); > } > @@ -1528,7 +1529,8 @@ static int setupUserPtr(struct node *node, cv4l_queue &q) > return 0; > } > > -int testUserPtr(struct node *node, unsigned frame_count, enum poll_mode pollmode) > +int testUserPtr(struct node *node, struct node *node_m2m_cap, unsigned frame_count, > + enum poll_mode pollmode) > { > bool can_stream = node->g_caps() & V4L2_CAP_STREAMING; > int type; > @@ -1592,16 +1594,16 @@ int testUserPtr(struct node *node, unsigned frame_count, enum poll_mode pollmode > fail_on_test(ev.type != V4L2_EVENT_SOURCE_CHANGE); > fail_on_test(!(ev.u.src_change.changes & V4L2_EVENT_SRC_CH_RESOLUTION)); > } > - fail_on_test(setupM2M(node, m2m_q)); > + fail_on_test(setupM2M(node_m2m_cap, m2m_q)); > } > - fail_on_test(captureBufs(node, q, m2m_q, frame_count, > + fail_on_test(captureBufs(node, node_m2m_cap, q, m2m_q, frame_count, > pollmode, capture_count)); > fail_on_test(node->streamoff(q.g_type())); > fail_on_test(node->streamoff(q.g_type())); > if (node->is_m2m) { > - fail_on_test(node->streamoff(m2m_q.g_type())); > - m2m_q.munmap_bufs(node); > - fail_on_test(m2m_q.reqbufs(node, 0)); > + fail_on_test(node_m2m_cap->streamoff(m2m_q.g_type())); > + m2m_q.munmap_bufs(node_m2m_cap); > + fail_on_test(m2m_q.reqbufs(node_m2m_cap, 0)); > fail_on_test(!capture_count); > } > stream_close(); > @@ -1670,7 +1672,7 @@ static int setupDmaBuf(struct node *expbuf_node, struct node *node, > return 0; > } > > -int testDmaBuf(struct node *expbuf_node, struct node *node, > +int testDmaBuf(struct node *expbuf_node, struct node *node, struct node *node_m2m_cap, > unsigned frame_count, enum poll_mode pollmode) > { > bool can_stream = node->g_caps() & V4L2_CAP_STREAMING; > @@ -1746,9 +1748,9 @@ int testDmaBuf(struct node *expbuf_node, struct node *node, > fail_on_test(ev.type != V4L2_EVENT_SOURCE_CHANGE); > fail_on_test(!(ev.u.src_change.changes & V4L2_EVENT_SRC_CH_RESOLUTION)); > } > - fail_on_test(setupM2M(node, m2m_q)); > + fail_on_test(setupM2M(node_m2m_cap, m2m_q)); > } > - fail_on_test(captureBufs(node, q, m2m_q, frame_count, > + fail_on_test(captureBufs(node, node_m2m_cap, q, m2m_q, frame_count, > pollmode, capture_count)); > fail_on_test(node->streamoff(q.g_type())); > fail_on_test(node->streamoff(q.g_type())); > @@ -1765,18 +1767,18 @@ int testDmaBuf(struct node *expbuf_node, struct node *node, > fail_on_test(q.reqbufs(node, 0)); > } > if (node->is_m2m) { > - fail_on_test(node->streamoff(m2m_q.g_type())); > - if (node->supports_orphaned_bufs) { > + fail_on_test(node_m2m_cap->streamoff(m2m_q.g_type())); > + if (node_m2m_cap->supports_orphaned_bufs) { > fail_on_test(m2m_q.reqbufs(node, 0)); > - m2m_q.munmap_bufs(node); > - } else if (m2m_q.reqbufs(node, 0) != EBUSY) { > + m2m_q.munmap_bufs(node_m2m_cap); > + } else if (m2m_q.reqbufs(node_m2m_cap, 0) != EBUSY) { > // It's either a bug or this driver should set > // V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS > warn("Can free buffers even if still mmap()ed\n"); > q.munmap_bufs(node); > } else { > - m2m_q.munmap_bufs(node); > - fail_on_test(m2m_q.reqbufs(node, 0)); > + m2m_q.munmap_bufs(node_m2m_cap); > + fail_on_test(m2m_q.reqbufs(node_m2m_cap, 0)); > } > fail_on_test(!capture_count); > } > @@ -2086,7 +2088,7 @@ int testRequests(struct node *node, bool test_streaming) > if (test_streaming) { > unsigned capture_count; > > - fail_on_test(captureBufs(node, q, m2m_q, num_bufs, > + fail_on_test(captureBufs(node, node, q, m2m_q, num_bufs, > POLL_MODE_SELECT, capture_count)); > } > fail_on_test(node->streamoff(q.g_type())); > @@ -2824,7 +2826,7 @@ static void streamM2MRun(struct node *node, unsigned frame_count) > fcc2s(cap_fmt.g_pixelformat()).c_str(), > pixfmt2s(cap_fmt.g_pixelformat()).c_str(), > cap_fmt.g_width(), cap_fmt.g_height(), > - ok(testMmap(node, frame_count, POLL_MODE_SELECT))); > + ok(testMmap(node, node, frame_count, POLL_MODE_SELECT))); > } > > static int streamM2MOutFormat(struct node *node, __u32 pixelformat, __u32 w, __u32 h, > diff --git a/utils/v4l2-compliance/v4l2-test-media.cpp b/utils/v4l2-compliance/v4l2-test-media.cpp > index 03314b9d..a8b84b9a 100644 > --- a/utils/v4l2-compliance/v4l2-test-media.cpp > +++ b/utils/v4l2-compliance/v4l2-test-media.cpp > @@ -601,7 +601,7 @@ void walkTopology(struct node &node, struct node &expbuf_node, > continue; > } > > - testNode(test_node, expbuf_node, type, > + testNode(test_node, test_node, expbuf_node, type, > frame_count, all_fmt_frame_count); > test_node.close(); > } >