NvVideoConverter freeing dmabuf_fd after dqBuffer

I am interested in linking an NvVideoConverter with an Argus IFrameConsumer creating NvBuffers.

So far I have used sample 10_camera_recording as a guide and successfully linked an NvVideoEncoder to the stream. But NvVideoConverter seems to do something different with the dmabuf_fd passed in, and I can’t find any samples where a buffer is created and then destroyed, just samples where a queue of buffers is created and re-used.

Right now, just like in sample 10_camera_recording, I am creating an NvBuffer from the IFrameConsumer using INativeBuffer::createNvBuffer() and passing the fd to the encoder by placing it in a struct v4l2_buffer.

void push_buffer(int fd, uint64_t timestamp)
{
    NvBuffer *buffer;
    struct v4l2_buffer v4l2_buf;
    struct v4l2_plane planes[MAX_PLANES];

    memset(&v4l2_buf, 0, sizeof(v4l2_buf));
    memset(&planes, 0, sizeof(planes));

    v4l2_buf.m.planes = planes;

    if(m_buffer_index < MAX_ENCODER_FRAMES) {
        // Initialize each buffer with a unique index
        v4l2_buf.index = m_buffer_index++;
    }
    else {
        // Dequeue and reuse the oldest buffer
        if(m_enc->output_plane.dqBuffer(v4l2_buf, &buffer, nullptr, 10) < 0) {
            DEBUG_ERROR("failed to dequeue buffer");
            m_enc->abort();
        }

        // Release mapped frame data
        NvBufferDestroy(v4l2_buf.m.planes[0].m.fd);
    }

    // Push the frame into V4L2.
    v4l2_buf.m.planes[0].m.fd = fd;
    v4l2_buf.m.planes[0].bytesused = (fd > 0) ? 1 : 0;
    v4l2_buf.flags |= V4L2_BUF_FLAG_TIMESTAMP_COPY;
    v4l2_buf.timestamp.tv_sec = timestamp / 1000000000;
    v4l2_buf.timestamp.tv_usec = (timestamp / 1000) % 1000000;
    if(m_enc->output_plane.qBuffer(v4l2_buf, nullptr) < 0) {
        DEBUG_ERROR("failed to queue buffer");
        m_enc->abort();
    }
}

After MAX_ENCODER_FRAMES is reached we begin to dequeue the v4l2 buffers for re-use. These buffers still have a reference to the NvBuffer dmabuf_fd so we can free it with NvBufferDestroy(v4l2_buf.m.planes[0].m.fd);

However, when I tried to drop in the NvVideoConverter instead I noticed that after I dequeue the v4l2 buffer v4l2_buf.m.planes[0].m.fd is 0. Does NvVideoConverter do something different with that dmabuf_fd? Is it possible to retrieve it after the dequeue, or do I have to keep track of it somewhere else?

Thanks!

Looked more closely at the samples and realized that for the converter you load the dmabuf_fd into the NvBuffer *shared_buffer rather than the struct v4l2_buffer. Then you can free it in the output plane’s dequeue callback.

Seems to be working now.

void push_buffer(int fd, uint64_t timestamp)
{
    NvBuffer *buffer;
    struct v4l2_buffer v4l2_buf;
    struct v4l2_plane planes[MAX_PLANES];

    memset(&v4l2_buf, 0, sizeof(struct v4l2_buffer));
    memset(planes, 0, MAX_PLANES * sizeof(struct v4l2_plane));

    v4l2_buf.m.planes = planes;

    pthread_mutex_lock(&m_conv_lock);
    buffer = m_conv_queue->front();
    m_conv_queue->pop();
    pthread_mutex_unlock(&m_conv_lock);

    v4l2_buf.index = buffer->index;

    DEBUG_VERBOSE("pushing fd=%d", fd);

    buffer->planes[0].bytesused = (fd > 0) ? 1 : 0;
    for(size_t i = 0; i < MAX_PLANES; ++i)
        buffer->planes[i].fd = fd;

    v4l2_buf.flags |= V4L2_BUF_FLAG_TIMESTAMP_COPY;
    v4l2_buf.timestamp.tv_sec = timestamp / 1000000000;;
    v4l2_buf.timestamp.tv_usec = (timestamp / 1000) % 1000000;
    if(m_conv->output_plane.qBuffer(v4l2_buf, buffer) < 0) {
        DEBUG_ERROR("failed to queue buffer");
        m_conv->abort();
    }
}