linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Venus video encoder device doesn't produce any frames
@ 2022-10-04  8:16 Martin Dørum
  0 siblings, 0 replies; only message in thread
From: Martin Dørum @ 2022-10-04  8:16 UTC (permalink / raw)
  To: open list:MEDIA INPUT INFRASTRUCTURE (V4L/DVB)

Hi, I'm sorry if this is not the place for this kind of question.
I have a Qualcomm Venus video encoder, on a SnapDragon 410.
I'm trying to make use of the onboard hardware video encoder that's
exposed as a V4L2 device.
However, when I follow the M2M Stateful Video Encoder Interface,
and write raw frames to the encoder, I only get exactly one encoded
frame back.
poll() on the file descriptor only ever emits one POLLIN at the
beginning, despite emitting POLLOUT for every frame I send it.
As far as I can see, my logic for when I dequeue and enqueue buffers
on the OUTPUT and the CAPTURE side is correct according to the
interface.

I have a small(ish) test program which does the minimum necessary to
exercise the encoder (included at the bottom).
Here's what that outputs:

Found Qualcomm Venus video encoder (/dev/video5, fd 8)
Output format 0: NV12: Y/CbCr 4:2:0
Capture format 0: MPG4: MPEG-4 Part 2 ES
Capture format 1: H263: H.263
Capture format 2: H264: H.264
Capture format 3: VP80: VP8
Mapped buffer 0: 0xffffb40d0000, 1048576
Mapped buffer 1: 0xffffb3fd0000, 1048576
Mapped buffer 2: 0xffffb3ed0000, 1048576
Mapped buffer 3: 0xffffb3dd0000, 1048576
Mapped buffer 0: 0xffffb3d5c000, 475136
Mapped buffer 1: 0xffffb3ce8000, 475136
Mapped buffer 2: 0xffffb3c74000, 475136
Mapped buffer 3: 0xffffb3c00000, 475136
Mapped buffer 4: 0xffffb3b8c000, 475136
Output buffer 0 enqueued, marking not ready
Capture buffer 0 dequeued (at: 0xffffb40d0000, length: 1264)
Capture buffer 0 enqueued
Output buffer 0 dequeued, marking ready
Output buffer 0 enqueued, marking not ready
Output buffer 0 dequeued, marking ready
Output buffer 0 enqueued, marking not ready
Output buffer 0 dequeued, marking ready
Output buffer 0 enqueued, marking not ready
Output buffer 0 dequeued, marking ready
Output buffer 0 enqueued, marking not ready
Output buffer 0 dequeued, marking ready
....

As you can see, I'm enqueuing one OUTPUT buffer, then dequeuing one
CAPTURE buffer (because poll() returns POLLIN), I re-enqueue that
CAPTURE buffer, but after that, I only ever dequeue OUTPUT buffers
because poll() never results in POLLIN again, only POLLOUT.

Here's a log which includes debug info from the 'videobuf2_common'
module and the '/dev/video5' device:

Found Qualcomm Venus video encoder (/dev/video5, fd 8)
Output format 0: NV12: Y/CbCr 4:2:0
Capture format 0: MPG4: MPEG-4 Part 2 ES
Capture format 1: H263: H.263
Capture format 2: H264: H.264
Capture format 3: VP80: VP8
[76714.885397] videodev: v4l2_open: video5: open (0)
[76714.885418] video5: VIDIOC_QUERYCAP: driver=qcom-venus,
card=Qualcomm Venus video encoder, bus=platform:qcom-venus,
version=0x00050a8a, capabilities=0x84204000, device_caps=0x04204000
[76714.885732] video5: VIDIOC_S_FMT: type=vid-cap-mplane, width=640,
height=480, format=H264, field=none, colorspace=0, num_planes=1,
flags=0x0, ycbcr_enc=0, quantization=0, xfer_func=0
[76714.885769] plane 0: bytesperline=0 sizeimage=1048576
[76714.885787] video5: VIDIOC_ENUM_FMT: index=0, type=vid-out-mplane,
flags=0x0, pixelformat=NV12, mbus_code=0x0000, description='Y/CbCr
4:2:0'
[76714.885844] video5: VIDIOC_ENUM_FMT: error -22: index=1,
type=vid-out-mplane, flags=0x0, pixelformat=\x00\x00\x00\x00,
mbus_code=0x0000, description=''
[76714.885882] video5: VIDIOC_ENUM_FMT: index=0, type=vid-cap-mplane,
flags=0x1, pixelformat=MPG4, mbus_code=0x0000, description='MPEG-4
Part 2 ES'
[76714.885928] video5: VIDIOC_ENUM_FMT: index=1, type=vid-cap-mplane,
flags=0x1, pixelformat=H263, mbus_code=0x0000, description='H.263'
[76714.885971] video5: VIDIOC_ENUM_FMT: index=2, type=vid-cap-mplane,
flags=0x1, pixelformat=H264, mbus_code=0x0000, description='H.264'
[76714.886029] video5: VIDIOC_ENUM_FMT: index=3, type=vid-cap-mplane,
flags=0x1, pixelformat=VP80, mbus_code=0x0000, description='VP8'
[76714.886081] video5: VIDIOC_ENUM_FMT: error -22: index=4,
type=vid-cap-mplane, flags=0x0, pixelformat=\x00\x00\x00\x00,
mbus_code=0x0000, description=''
[76714.886122] video5: VIDIOC_S_FMT: type=vid-out-mplane, width=640,
height=480, format=NV12, field=none, colorspace=0, num_planes=1,
flags=0x0, ycbcr_enc=0, quantization=0, xfer_func=0
[76714.886149] plane 0: bytesperline=640 sizeimage=475136
[76714.886165] video5: VIDIOC_S_PARM: type=vid-out-mplane,
capability=0x1000, outputmode=0x0, timeperframe=1/30, extendedmode=0,
writebuffers=0
[76714.886207] video5: VIDIOC_S_PARM: type=vid-cap-mplane,
capability=0x1000, capturemode=0x0, timeperframe=1/30, extendedmode=0,
readbuffers=0
Mapped buffer 0: 0xffff84530000, 1048576
Mapped buffer 1: 0xffff84430000, 1048576
Mapped buffer 2: 0xffff84330000, 1048576
[76714.889190] video5: VIDIOC_REQBUFS: count=4, type=vid-cap-mplane, memory=mmap
[76714.889344] video5: VIDIOC_QUERYBUF: 00:00:00.000000000 index=0,
type=vid-cap-mplane, request_fd=0, flags=0x00004000, field=any,
sequence=0, memory=mmap
[76714.889376] plane 0: bytesused=0, data_offset=0x00000000,
offset/userptr=0x40000000, length=1048576
Mapped buffer 3: 0xffff84230000, 1048576
[76714.889384] timecode=00:00:00 type=0, flags=0x00000000, frames=0,
userbits=0x00000000
[76714.889729] videodev: v4l2_mmap: video5: mmap (0)
[76714.889821] video5: VIDIOC_QUERYBUF: 00:00:00.000000000 index=1,
type=vid-cap-mplane, request_fd=0, flags=0x00004000, field=any,
sequence=0, memory=mmap
[76714.889860] plane 0: bytesused=0, data_offset=0x00000000,
offset/userptr=0x40100000, length=1048576
[76714.889868] timecode=00:00:00 type=0, flags=0x00000000, frames=0,
userbits=0x00000000
[76714.890111] videodev: v4l2_mmap: video5: mmap (0)
[76714.890170] video5: VIDIOC_QUERYBUF: 00:00:00.000000000 index=2,
type=vid-cap-mplane, request_fd=0, flags=0x00004000, field=any,
sequence=0, memory=mmap
[76714.890207] plane 0: bytesused=0, data_offset=0x00000000,
offset/userptr=0x40200000, length=1048576
[76714.890215] timecode=00:00:00 type=0, flags=0x00000000, frames=0,
userbits=0x00000000
[76714.890462] videodev: v4l2_mmap: video5: mmap (0)
[76714.890518] video5: VIDIOC_QUERYBUF: 00:00:00.000000000 index=3,
type=vid-cap-mplane, request_fd=0, flags=0x00004000, field=any,
sequence=0, memory=mmap
[76714.890547] plane 0: bytesused=0, data_offset=0x00000000,
offset/userptr=0x40300000, length=1048576
[76714.890555] timecode=00:00:00 type=0, flags=0x00000000, frames=0,
userbits=0x00000000
[76714.890783] videodev: v4l2_mmap: video5: mmap (0)
Mapped buffer 0: 0xffff841bc000, 475136
Mapped buffer 1: 0xffff84148000, 475136
Mapped buffer 2: 0xffff840d4000, 475136
Mapped buffer 3: 0xffff84060000, 475136
Mapped buffer 4: 0xffff83fec000, 475136
[76714.894347] video5: VIDIOC_REQBUFS: count=5, type=vid-out-mplane, memory=mmap
[76714.894402] video5: VIDIOC_QUERYBUF: 00:00:00.000000000 index=0,
type=vid-out-mplane, request_fd=0, flags=0x00004000, field=any,
sequence=0, memory=mmap
[76714.894425] plane 0: bytesused=0, data_offset=0x00000000,
offset/userptr=0x0, length=475136
[76714.894432] timecode=00:00:00 type=0, flags=0x00000000, frames=0,
userbits=0x00000000
[76714.894564] videodev: v4l2_mmap: video5: mmap (0)
[76714.894649] video5: VIDIOC_QUERYBUF: 00:00:00.000000000 index=1,
type=vid-out-mplane, request_fd=0, flags=0x00004000, field=any,
sequence=0, memory=mmap
[76714.894679] plane 0: bytesused=0, data_offset=0x00000000,
offset/userptr=0x74000, length=475136
[76714.894686] timecode=00:00:00 type=0, flags=0x00000000, frames=0,
userbits=0x00000000
[76714.894789] videodev: v4l2_mmap: video5: mmap (0)
[76714.894843] video5: VIDIOC_QUERYBUF: 00:00:00.000000000 index=2,
type=vid-out-mplane, request_fd=0, flags=0x00004000, field=any,
sequence=0, memory=mmap
[76714.894866] plane 0: bytesused=0, data_offset=0x00000000,
offset/userptr=0xe8000, length=475136
[76714.894873] timecode=00:00:00 type=0, flags=0x00000000, frames=0,
userbits=0x00000000
[76714.894972] videodev: v4l2_mmap: video5: mmap (0)
[76714.895024] video5: VIDIOC_QUERYBUF: 00:00:00.000000000 index=3,
type=vid-out-mplane, request_fd=0, flags=0x00004000, field=any,
sequence=0, memory=mmap
[76714.895047] plane 0: bytesused=0, data_offset=0x00000000,
offset/userptr=0x15c000, length=475136
[76714.895054] timecode=00:00:00 type=0, flags=0x00000000, frames=0,
userbits=0x00000000
[76714.895147] videodev: v4l2_mmap: video5: mmap (0)
[76714.895188] video5: VIDIOC_QUERYBUF: 00:00:00.000000000 index=4,
type=vid-out-mplane, request_fd=0, flags=0x00004000, field=any,
sequence=0, memory=mmap
[76714.895211] plane 0: bytesused=0, data_offset=0x00000000,
offset/userptr=0x1d0000, length=475136
[76714.895219] timecode=00:00:00 type=0, flags=0x00000000, frames=0,
userbits=0x00000000
[76714.895329] videodev: v4l2_mmap: video5: mmap (0)
[76714.895371] __v4l2_m2m_try_queue: Trying to schedule a job for
m2m_ctx: 000000009db4c1e9
[76714.895377] __v4l2_m2m_try_queue: Streaming needs to be on for both queues
[76714.895382] v4l2_m2m_try_run: No job pending
[76714.895386] video5: VIDIOC_STREAMON: type=vid-cap-mplane
[76714.895409] __v4l2_m2m_try_queue: Trying to schedule a job for
m2m_ctx: 000000009db4c1e9
[76714.895414] __v4l2_m2m_try_queue: No input buffers available
[76714.895418] v4l2_m2m_try_run: No job pending
[76714.895422] video5: VIDIOC_STREAMON: type=vid-out-mplane
[76714.895550] __v4l2_m2m_try_queue: Trying to schedule a job for
m2m_ctx: 000000009db4c1e9
[76714.895554] __v4l2_m2m_try_queue: No input buffers available
[76714.895558] v4l2_m2m_try_run: No job pending
[76714.895563] video5: VIDIOC_QBUF: 00:00:00.000000000 index=0,
type=vid-cap-mplane, request_fd=0, flags=0x00004003, field=any,
sequence=0, memory=mmap
[76714.895584] plane 0: bytesused=0, data_offset=0x00000000,
offset/userptr=0x40000000, length=1048576
[76714.895591] timecode=00:00:00 type=0, flags=0x00000000, frames=0,
userbits=0x00000000
[76714.895708] __v4l2_m2m_try_queue: Trying to schedule a job for
m2m_ctx: 000000009db4c1e9
[76714.895712] __v4l2_m2m_try_queue: No input buffers available
[76714.895716] v4l2_m2m_try_run: No job pending
[76714.895720] video5: VIDIOC_QBUF: 00:00:00.000000000 index=1,
type=vid-cap-mplane, request_fd=0, flags=0x00004003, field=any,
sequence=0, memory=mmap
[76714.895741] plane 0: bytesused=0, data_offset=0x00000000,
offset/userptr=0x40100000, length=1048576
[76714.895747] timecode=00:00:00 type=0, flags=0x00000000, frames=0,
userbits=0x00000000
[76714.895860] __v4l2_m2m_try_queue: Trying to schedule a job for
m2m_ctx: 000000009db4c1e9
[76714.895864] __v4l2_m2m_try_queue: No input buffers available
[76714.895868] v4l2_m2m_try_run: No job pending
[76714.895872] video5: VIDIOC_QBUF: 00:00:00.000000000 index=2,
type=vid-cap-mplane, request_fd=0, flags=0x00004003, field=any,
sequence=0, memory=mmap
[76714.895893] plane 0: bytesused=0, data_offset=0x00000000,
offset/userptr=0x40200000, length=1048576
[76714.895899] timecode=00:00:00 type=0, flags=0x00000000, frames=0,
userbits=0x00000000
[76714.896009] __v4l2_m2m_try_queue: Trying to schedule a job for
m2m_ctx: 000000009db4c1e9
[76714.896013] __v4l2_m2m_try_queue: No input buffers available
[76714.896017] v4l2_m2m_try_run: No job pending
[76714.896021] video5: VIDIOC_QBUF: 00:00:00.000000000 index=3,
type=vid-cap-mplane, request_fd=0, flags=0x00004003, field=any,
sequence=0, memory=mmap
[76714.896041] plane 0: bytesused=0, data_offset=0x00000000,
offset/userptr=0x40300000, length=1048576
[76714.896048] timecode=00:00:00 type=0, flags=0x00000000, frames=0,
userbits=0x00000000
[76714.896072] videodev: v4l2_poll: video5: poll: 00000000
Output buffer 0 enqueued, marking not ready
[76714.908897] __v4l2_m2m_try_queue: Trying to schedule a job for
m2m_ctx: 000000009db4c1e9
[76714.908911] v4l2_m2m_try_run: Running job on m2m_ctx: 000000009db4c1e9
[76714.908936] video5: VIDIOC_QBUF: 00:00:00.000000000 index=0,
type=vid-out-mplane, request_fd=0, flags=0x00004003, field=none,
sequence=0, memory=mmap
[76714.908965] plane 0: bytesused=460800, data_offset=0x00000000,
offset/userptr=0x0, length=475136
[76714.908971] timecode=00:00:00 type=0, flags=0x00000000, frames=0,
userbits=0x00000000
Capture buffer 0 dequeued (at: 0xffff84530000, length: 1264)
Capture buffer 0 enqueued
Output buffer 0 dequeued, marking ready
Output buffer 0 enqueued, marking not ready
[76714.942341] videodev: v4l2_poll: video5: poll: 00000145
[76714.942377] video5: VIDIOC_DQBUF: 00:00:00.000000000 index=0,
type=vid-cap-mplane, request_fd=0, flags=0x00004009, field=any,
sequence=0, memory=mmap
[76714.942410] plane 0: bytesused=1264, data_offset=0x00000000,
offset/userptr=0x40000000, length=1048576
[76714.942418] timecode=00:00:00 type=0, flags=0x00000000, frames=0,
userbits=0x00000000
[76714.942645] __v4l2_m2m_try_queue: Trying to schedule a job for
m2m_ctx: 000000009db4c1e9
[76714.942654] __v4l2_m2m_try_queue: On job queue already
[76714.942661] v4l2_m2m_try_run: Another instance is running, won't run now
[76714.942667] video5: VIDIOC_QBUF: 00:00:00.000000000 index=0,
type=vid-cap-mplane, request_fd=0, flags=0x00004003, field=any,
sequence=0, memory=mmap
[76714.942697] plane 0: bytesused=0, data_offset=0x00000000,
offset/userptr=0x40000000, length=1048576
[76714.942705] timecode=00:00:00 type=0, flags=0x00000000, frames=0,
userbits=0x00000000
[76714.942759] video5: VIDIOC_DQBUF: 00:00:00.000000000 index=0,
type=vid-out-mplane, request_fd=0, flags=0x00004001, field=none,
sequence=0, memory=mmap
[76714.942789] plane 0: bytesused=460800, data_offset=0x00000000,
offset/userptr=0x0, length=475136
[76714.942797] timecode=00:00:00 type=0, flags=0x00000000, frames=0,
userbits=0x00000000
[76714.942827] videodev: v4l2_poll: video5: poll: 00000000
[76714.943110] __v4l2_m2m_try_queue: Trying to schedule a job for
m2m_ctx: 000000009db4c1e9
[76714.943115] __v4l2_m2m_try_queue: On job queue already
[76714.943121] v4l2_m2m_try_run: Another instance is running, won't run now
[76714.943125] video5: VIDIOC_QBUF: 00:00:00.000000000 index=0,
type=vid-out-mplane, request_fd=0, flags=0x00004003, field=none,
sequence=0, memory=mmap
[76714.943153] plane 0: bytesused=460800, data_offset=0x00000000,
offset/userptr=0x0, length=475136
[76714.943160] timecode=00:00:00 type=0, flags=0x00000000, frames=0,
userbits=0x00000000
Output buffer 0 dequeued, marking ready
Output buffer 0 enqueued, marking not ready
[76714.976561] videodev: v4l2_poll: video5: poll: 00000104
[76714.976595] video5: VIDIOC_DQBUF: 00:00:00.000000000 index=0,
type=vid-out-mplane, request_fd=0, flags=0x00004001, field=none,
sequence=1, memory=mmap
[76714.976627] plane 0: bytesused=460800, data_offset=0x00000000,
offset/userptr=0x0, length=475136
[76714.976635] timecode=00:00:00 type=0, flags=0x00000000, frames=0,
userbits=0x00000000
[76714.976716] videodev: v4l2_poll: video5: poll: 00000000
[76714.976997] __v4l2_m2m_try_queue: Trying to schedule a job for
m2m_ctx: 000000009db4c1e9
[76714.977005] __v4l2_m2m_try_queue: On job queue already
[76714.977012] v4l2_m2m_try_run: Another instance is running, won't run now
[76714.977017] video5: VIDIOC_QBUF: 00:00:00.000000000 index=0,
type=vid-out-mplane, request_fd=0, flags=0x00004003, field=none,
sequence=0, memory=mmap
[76714.977045] plane 0: bytesused=460800, data_offset=0x00000000,
offset/userptr=0x0, length=475136
[76714.977053] timecode=00:00:00 type=0, flags=0x00000000, frames=0,
userbits=0x00000000
Output buffer 0 dequeued, marking ready
Output buffer 0 enqueued, marking not ready

And finally, here's my C code; it's long, but pretty straightforward:

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <linux/videodev2.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/eventfd.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <poll.h>

#define xioctl(a, b, c) do { \
    if (ioctl(a, b, c) < 0) { \
        fprintf(stderr, "%s:%i: IOCTL %s: %s\n", __FILE__, __LINE__,
#b, strerror(errno)); \
        abort(); \
    } \
} while (0)

struct mmbuffer {
    void *start;
    size_t length;
    int ready;
};

int main() {
    int width = 640;
    int height = 480;
    int fd = -1;

    struct v4l2_capability cap;
    for (int id = 0; id < 16; ++id) {
        char pathbuf[64];
        snprintf(pathbuf, sizeof(pathbuf), "/dev/video%d", id);
        int tfd = open(pathbuf, O_RDWR);
        if (tfd < 0) {
            continue;
        }

        memset(&cap, 0, sizeof(cap));
        if (ioctl(tfd, VIDIOC_QUERYCAP, &cap) < 0) {
            close(tfd);
            continue;
        }

        if (strcmp((const char *)cap.card, "Qualcomm Venus video
encoder") == 0) {
            fprintf(stderr, "Found %s (%s, fd %i)\n", cap.card, pathbuf, tfd);
            fd = tfd;
            break;
        }
    }

    if (fd < 0) {
        fprintf(stderr, "Found no encoder\n");
        return 1;
    }

    // 1. Set the coded format on the CAPTURE queue via VIDIOC_S_FMT().
    struct v4l2_format fmt;
    memset(&fmt, 0, sizeof(fmt));
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
    fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264;
    fmt.fmt.pix_mp.num_planes = 1;
    fmt.fmt.pix_mp.width = width;
    fmt.fmt.pix_mp.height = height;
    fmt.fmt.pix_mp.plane_fmt[0].sizeimage = 1024 * 1024;
    xioctl(fd, VIDIOC_S_FMT, &fmt);

    // 2. Optional. Enumerate supported OUTPUT formats (raw formats
for source) for the selected
    // coded format via VIDIOC_ENUM_FMT().
    struct v4l2_fmtdesc fmtdesc;
    memset(&fmtdesc, 0, sizeof(fmtdesc));
    fmtdesc.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
    while (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) == 0) {
        char fcc[4];
        memcpy(fcc, &fmtdesc.pixelformat, 4);
        fprintf(stderr, "Output format %i: %c%c%c%c: %s\n",
fmtdesc.index, fcc[0], fcc[1], fcc[2], fcc[3], fmtdesc.description);
        fmtdesc.index += 1;
    }

    // Let's do the same with CAPTURE
    memset(&fmtdesc, 0, sizeof(fmtdesc));
    fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
    while (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) == 0) {
        char fcc[4];
        memcpy(fcc, &fmtdesc.pixelformat, 4);
        fprintf(stderr, "Capture format %i: %c%c%c%c: %s\n",
fmtdesc.index, fcc[0], fcc[1], fcc[2], fcc[3], fmtdesc.description);
        fmtdesc.index += 1;
    }

    // 3. Set the raw source format on the OUTPUT queue via VIDIOC_S_FMT().
    memset(&fmt, 0, sizeof(fmt));
    fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
    fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12;
    fmt.fmt.pix_mp.width = width;
    fmt.fmt.pix_mp.height = height;
    xioctl(fd, VIDIOC_S_FMT, &fmt);

    // 4. Set the raw frame interval on the OUTPUT queue via
VIDIOC_S_PARM(). This also sets the
    // coded frame interval on the CAPTURE queue to the same value.
    struct v4l2_streamparm parm;
    memset(&parm, 0, sizeof(parm));
    parm.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
    parm.parm.output.timeperframe.numerator = 1;
    parm.parm.output.timeperframe.denominator = 30;
    xioctl(fd, VIDIOC_S_PARM, &parm);

    // 5. Optional. Set the coded frame interval on the CAPTURE queue
via VIDIOC_S_PARM().
    memset(&parm, 0, sizeof(parm));
    parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
    parm.parm.capture.timeperframe.numerator = 1;
    parm.parm.capture.timeperframe.denominator = 30;
    xioctl(fd, VIDIOC_S_PARM, &parm);

    // 6. Optional. Set the visible resolution for the stream metadata
via VIDIOC_S_SELECTION() on
    // the OUTPUT queue if it is desired to be different than the full
OUTPUT resolution.

    // 7. Allocate buffers for both OUTPUT and CAPTURE via VIDIOC_REQBUFS().
    // This may be performed in any order.

    struct mmbuffer *captureBufs = NULL;
    size_t captureBufCount;
    { // CAPTURE
        struct v4l2_requestbuffers reqbufs;
        memset(&reqbufs, 0, sizeof(reqbufs));
        reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
        reqbufs.memory = V4L2_MEMORY_MMAP;
        reqbufs.count = 4;
        xioctl(fd, VIDIOC_REQBUFS, &reqbufs);

        captureBufCount = reqbufs.count;
        captureBufs = (struct mmbuffer *)malloc(captureBufCount *
sizeof(*captureBufs));
        for (size_t i = 0; i < captureBufCount; ++i) {
            struct v4l2_buffer buffer;
            memset(&buffer, 0, sizeof(buffer));
            struct v4l2_plane plane;
            memset(&plane, 0, sizeof(plane));
            buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
            buffer.length = 1;
            buffer.m.planes = &plane;
            buffer.memory = V4L2_MEMORY_MMAP;
            buffer.index = i;
            xioctl(fd, VIDIOC_QUERYBUF, &buffer);

            captureBufs[i].ready = 1;
            captureBufs[i].start = mmap(NULL, plane.length, PROT_READ
| PROT_WRITE, MAP_SHARED,
                fd, plane.m.mem_offset);
            captureBufs[i].length = plane.length;
            if (captureBufs[i].start == MAP_FAILED) {
                fprintf(stderr, "mmap: %s\n", strerror(errno));
                return 1;
            }

            fprintf(stderr, "Mapped buffer %zi: %p, %i\n", i,
captureBufs[i].start, plane.length);
        }
    }

    struct mmbuffer *outputBufs = NULL;
    size_t outputBufCount;
    { // OUTPUT
        struct v4l2_requestbuffers reqbufs;
        memset(&reqbufs, 0, sizeof(reqbufs));
        reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
        reqbufs.memory = V4L2_MEMORY_MMAP;
        reqbufs.count = 4;
        xioctl(fd, VIDIOC_REQBUFS, &reqbufs);

        outputBufCount = reqbufs.count;
        outputBufs = (struct mmbuffer *)malloc(outputBufCount *
sizeof(*captureBufs));
        for (size_t i = 0; i < outputBufCount; ++i) {
            struct v4l2_buffer buffer;
            memset(&buffer, 0, sizeof(buffer));
            struct v4l2_plane plane;
            memset(&plane, 0, sizeof(plane));
            buffer.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
            buffer.length = 1;
            buffer.m.planes = &plane;
            buffer.memory = V4L2_MEMORY_MMAP;
            buffer.index = i;
            xioctl(fd, VIDIOC_QUERYBUF, &buffer);

            outputBufs[i].ready = 1;
            outputBufs[i].start = mmap(NULL, plane.length, PROT_READ |
PROT_WRITE, MAP_SHARED,
                fd, plane.m.mem_offset);
            outputBufs[i].length = plane.length;
            if (outputBufs[i].start == MAP_FAILED) {
                fprintf(stderr, "mmap: %s\n", strerror(errno));
                return 1;
            }

            fprintf(stderr, "Mapped buffer %zi: %p, %i\n", i,
outputBufs[i].start, plane.length);
        }
    }

    // 8. Begin streaming on both OUTPUT and CAPTURE queues via
VIDIOC_STREAMON().
    // This may be performed in any order.

    int buftype = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
    xioctl(fd, VIDIOC_STREAMON, &buftype);

    buftype = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
    xioctl(fd, VIDIOC_STREAMON, &buftype);

    // Then enqueue all the capture buffers, to let the driver put
encoded frames in them
    for (size_t i = 0; i < captureBufCount; ++i) {
        struct v4l2_buffer buffer;
        memset(&buffer, 0, sizeof(buffer));
        struct v4l2_plane plane;
        memset(&plane, 0, sizeof(plane));
        buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
        buffer.index = i;
        buffer.length = 1;
        buffer.m.planes = &plane;
        buffer.memory = V4L2_MEMORY_MMAP;
        xioctl(fd, VIDIOC_QBUF, &buffer);
    }

    // This is the main loop, where we dequeue and re-enqueue
available CAPTURE buffers,
    // dequeue available OUTPUT buffers, and write frames to the OUTPUT
    uint8_t fill = 0;
    while (1) {
        // Handle events from the driver
        struct pollfd pfd = {fd, POLLIN | POLLOUT, 0};
        while (1) {
            int ret = poll(&pfd, 1, 0);
            if (ret < 0 && errno == EINTR) {
                continue;
            } else if (ret < 0) {
                fprintf(stderr, "Poll error: %s\n", strerror(errno));
                return 1;
            } else if (ret == 0) {
                break;
            }

            if (pfd.revents & POLLIN) {
                // A capture buffer is ready, we have encoded data!
                struct v4l2_buffer buffer;
                memset(&buffer, 0, sizeof(buffer));
                struct v4l2_plane plane;
                memset(&plane, 0, sizeof(plane));
                buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
                buffer.memory = V4L2_MEMORY_MMAP;
                buffer.length = 1;
                buffer.m.planes = &plane;
                xioctl(fd, VIDIOC_DQBUF, &buffer);

                // Do something with the data
                struct mmbuffer *buf = &captureBufs[buffer.index];
                fprintf(stderr, "Capture buffer %i dequeued (at: %p,
length: %i)\n", buffer.index, buf->start, plane.bytesused);

                // Re-enqueue the buffer
                size_t index = buffer.index;
                memset(&buffer, 0, sizeof(buffer));
                memset(&plane, 0, sizeof(plane));
                buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
                buffer.memory = V4L2_MEMORY_MMAP;
                buffer.length = 1;
                buffer.m.planes = &plane;
                buffer.index = index;
                xioctl(fd, VIDIOC_QBUF, &buffer);

                fprintf(stderr, "Capture buffer %i enqueued\n", buffer.index);
            }

            if (pfd.revents & POLLOUT) {
                // An output buffer is ready, dequeue it and mark it ready
                struct v4l2_buffer buffer;
                memset(&buffer, 0, sizeof(buffer));
                struct v4l2_plane plane;
                memset(&plane, 0, sizeof(plane));
                buffer.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
                buffer.memory = V4L2_MEMORY_MMAP;
                buffer.length = 1;
                buffer.m.planes = &plane;
                if (ioctl(fd, VIDIOC_DQBUF, &buffer) < 0) {
                    fprintf(stderr, "VIDIOC_DQBUF (output): %s\n",
strerror(errno));
                    return 1;
                }

                fprintf(stderr, "Output buffer %i dequeued, marking
ready\n", buffer.index);
                outputBufs[buffer.index].ready = 1;
            }

            if (pfd.revents & ~(POLLIN | POLLOUT)) {
                fprintf(stderr, "Unexpected revents: %i. Error?\n",
pfd.revents);
                return 1;
            }
        }

        // Find an available output buffer
        int outputIdx = -1;
        struct mmbuffer *outputBuf = NULL;
        for (size_t i = 0; i < outputBufCount; ++i) {
            if (outputBufs[i].ready) {
                outputIdx = i;
                outputBuf = &outputBufs[i];
                break;
            }
        }

        // Produce a raw frame and queue it, if possible
        if (outputBuf) {
            size_t len = width * height + width * height / 2;
            memset(outputBuf->start, fill, len);
            fill += 1;

            struct v4l2_buffer buffer;
            memset(&buffer, 0, sizeof(buffer));
            struct v4l2_plane plane;
            memset(&plane, 0, sizeof(plane));
            buffer.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
            buffer.length = 1;
            buffer.m.planes = &plane;
            buffer.memory = V4L2_MEMORY_MMAP;
            buffer.index = outputIdx;
            plane.bytesused = len;

            if (ioctl(fd, VIDIOC_QBUF, &buffer) < 0) {
                fprintf(stderr, "VIDIOC_QBUF (output): %s\n", strerror(errno));
                return 1;
            }

            fprintf(stderr, "Output buffer %i enqueued, marking not
ready\n", buffer.index);
            outputBufs[outputIdx].ready = 0;
        } else {
            fprintf(stderr, "No output buffers ready!\n");
        }

        usleep(33 * 1000);
    }
}

Any help with this would be greatly appreciated,
because I truly have no idea what I might be doing wrong.

Regards,
Martin

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-10-04  8:17 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-04  8:16 Venus video encoder device doesn't produce any frames Martin Dørum

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).