How to share the buffer in process context?

I want to use nvmap api to get and share the buffer in different process.
use NvBufferCreate to create a buf and than to use ExtractFdFromNvBuffer to get out the fd.but failed in different process.
example:
process A → NvBufferCreate ,and show the phy addr in the NvBufferParams.
process B-> ExtractFdFromNvBuffer (phyaddr_from_A,dmabuf_fd);

this cause the Segment Fault.

Does the V4L2 export the dmabuf_fd can be used in different process?like mmap.

Hi,
There is new NvBuffer APIs on Jetpack 4.6(r32.6.1) for this use-case. Please upgrade to JP4.6 and check nvbuf_utils.h:

/**
 * Gets buffer extended parameters.
 * @param[in] dmabuf_fd `DMABUF FD` of buffer.
 * @param[out] exparams A pointer to the structure to fill with extended parameters.
 *
 * @returns 0 for success, -1 for failure.
 */
int NvBufferGetParamsEx (int dmabuf_fd, NvBufferParamsEx *exparams);
/**
 * Transforms one DMA buffer to another DMA buffer, API to be used for another process.
 * This function can support transforms for copying, scaling, fliping, rotating, and cropping.
 * @param[in] src_dmabuf_fd DMABUF FD of source buffer
 * @param[in] input_params extended input parameters for a hardware buffer.
 * @param[in] dst_dmabuf_fd DMABUF FD of destination buffer
 * @param[in] output_params extended output parameters for a hardware buffer.
 * @param[in] transform_params transform parameters
 *
 * @return 0 for sucess, -1 for failure.
 */
int NvBufferTransformEx (int src_dmabuf_fd, NvBufferParamsEx *input_params, int dst_dmabuf_fd, NvBufferParamsEx *output_params, NvBufferTransformParams *transform_params);

With the API you can send fd through unix domain socket and get the buffer in another process.

1 Like

Thanks DaneLLL:
Would it be so kind for you to show me the sample?
the thing is I can handle the Unix message to send and recv the message,but still not knowing how to use NvBuffer APIs within different process to get the dmabuf_fd.
Process : A send msg
Process : B recv msg
NvBufferGetParamsEx();
PS: in the version from 32.6.1in nvbuffer_utils.h I did not find the API as NvBufferTransformEx instead of NvBufferTransform.

Thanks

You mean the NvBuffer’s dma_fd can cross process with Jetpack 4.6(r32.6.1)?

Hi,
We are still working on the sample. Will update once there is further progress.

I just test the dma_buf fd,it must use Raw2NvBuffer to get buffer into the dmabuf_fd.And the most important thing is : this function use cpu to copy.

Hi

I’m trying to share a buffer between two processes. I succeeded in sharing the file descriptor, however I’m having issues (SEGFAULT) on calling NvBufferTransformEx: Failed to configure NvDdkVic Source Surface.
The documentation on that topic is very sparse. Any chance you could show us a sample of how to use NvBufferTransformEx? Or may you please tell me rough date when we can expect a sample? 🙂

Thanks for your time!

Hi,
In the producer process, please refer to the pseudo code to get information of the buffers:

struct nvbuf_param {
    NvBufferParams params;
    NvBufferParamsEx paramsEx;
};

NvBufferParams params;
NvBufferParamsEx paramsEx;
nvbuf_param buf_par;
NvBufferGetParams(dmabuf_fd, &params);
NvBufferGetParamsEx(dmabuf_fd, &paramsEx);
buf_par.params = params;
buf_par.paramsEx = paramsEx;

And send the information(buf_par) to consumer process through unix socket.

In consumer process, the fd from producer is source buffer. Please create an NvBuffer as destination buffer and then call like:

static void transform_nvbuf(int src_fd, nvbuf_param *src_buf_par, int dst_fd)
{
    NvBufferParams src_params = src_buf_par->params;
    NvBufferParamsEx src_paramsEx = src_buf_par->paramsEx;
    NvBufferParams dst_params;
    NvBufferParamsEx dst_paramsEx;
    NvBufferGetParams(dst_fd, &dst_params);
    NvBufferGetParamsEx(dst_fd, &dst_paramsEx);

    NvBufferTransformParams trans_params;
    memset(&trans_params, 0, sizeof(trans_params));
    trans_params.src_rect = {0, 0, src_params.width[0], src_params.height[0]};
    trans_params.dst_rect = {0, 0, dst_params.width[0], dst_params.height[0]};

    NvBufferTransformEx(src_fd, &src_paramsEx, dst_fd, &dst_paramsEx, &trans_params);
}

Please check above suggestion and give it a try.

Thx for your quick response

I adopted my code to your suggestions! However now I’m getting the following error, when calling NvBufferTransformEx

Invalid snSurfaces[0]

Have you got any pointers what I might be doing wrong?

Here’s the code of my Consumer-process

  while (true) {
    sync_parameters source_params{};
    auto read_count = socket.receive(
        boost::asio::buffer(&source_params, sizeof(source_params)));
    assert(read_count == sizeof(source_params));
    int target_dmabuf_fd{};
    {
      NvBufferCreateParams create_params{};
      create_params.width = source_params.params.width[0];
      create_params.height = source_params.params.height[0];
      create_params.colorFormat = source_params.params.pixel_format;
      int result = NvBufferCreateEx(&target_dmabuf_fd, &create_params);
      assert (result != -1);
    }
    NvBufferParams target_params{};
    {
      int result = NvBufferGetParams(target_dmabuf_fd, &target_params);
      assert (result != -1);
    }
    NvBufferParamsEx target_params_ex{};
    {
      int result = NvBufferGetParamsEx(target_dmabuf_fd, &target_params_ex);
      assert (result != -1);
    }
    {
      NvBufferTransformParams transform_params{};
      memset(&transform_params, 0, sizeof(NvBufferTransformParams));
      transform_params.src_rect = {0, 0, source_params.params.width[0],
                                   source_params.params.height[0]};
      transform_params.dst_rect = {0, 0, target_params.width[0],
                                   target_params.height[0]};
      int source_dmabuf_fd = source_params.params.dmabuf_fd;
      int result = NvBufferTransformEx(
          source_dmabuf_fd, &source_params.params_ex, target_dmabuf_fd,
          &target_params_ex, &transform_params);
      if (result == -1)
        return 1;
    }

The producer Proccess gets the information from gstreamer like this:

GstFlowReturn appsink_new_sample(GstAppSink *appsink, gpointer data) {
  ipc *ipc_ = static_cast<ipc *>(data);

  GstSample *sample = gst_app_sink_pull_sample(appsink);
  assert (sample);

  GstCaps *caps = gst_sample_get_caps(sample);
  assert(caps);

  gst_caps_get_structure(caps, 0);
  GstBuffer *buffer = gst_sample_get_buffer(sample);
  GstMapInfo map = {0};
  gst_buffer_map(buffer, &map, GST_MAP_READ);

  int dmabuf_fd{};
  {
    const int success =
        ExtractFdFromNvBuffer(static_cast<void *>(map.data), &dmabuf_fd);
    assert (success == 0);
  }
  auto send = std::make_shared<sync_parameters>();
  {
    int result = NvBufferGetParamsEx(dmabuf_fd, &send->params_ex);
    assert (result != -1);
  }
  {
    int result = NvBufferGetParams(dmabuf_fd, &send->params);
    assert (result != -1);
  }
  ipc_->send(send);

Any help would be greatly appreciated. thx for your time!

Hi,
Please send the fd through sendmsg() and recvmsg() like:
c - How to use sendmsg() to send a file-descriptor via sockets between 2 processes? - Stack Overflow

You should see that fd is different in the two processes.

Great catch! Yes that worked for me. In my code (asio) specifically the code send_fd and receive_fd helped a lot from here: send_fd.cpp · GitHub

Thanks a lot! Awesome

1 Like

hi,danelll:
i try this test,one process send [1920x1080] yuv dmabuf data;
another process recv yuv dmabuf and NvBufferTransformEx;
but when i send frame every 30ms;and the recv process will failed at the 1011 frame later;
and i try many times,and recv process always failed at the 1011 frame later;
the error code SYNC_IOC_FENCE_INFO ioctl failed with 9

Hi @happy886
Do you send fd in every frame? Or send all fd in initialization? You should have like 6 Nvbuffers for capturing frame data in producer. Please send the fds in initialization to consumers. Once the buffer is updated, please send messages to all consumers. No need to keep sending fd for every frame update.

1 、the send fd is always the same,NvJPEGDecoder decode from a jpg picture;
m_pJpegDec->decodeToFd(jpgfd, pFileBuffer, nFileSize, nPixFmt, nWidth, nHeight)

server.ancil_send_fd(jpgfd);
2、the test is only one producer process and one consumer process;

Hi @happy886
We have checked the code and it does not fit our suggestion. Please check the pseudo code:

sent_fd = false;
while(1)
{
    refresh_jpeg_data_to_pFileBuffer;

    m_pJpegDec->decodeToFd(jpgfd, pFileBuffer, nFileSize, nPixFmt, nWidth, nHeight);
    if (sent_fd == false)
    {
        server.ancil_send_fd(jpgfd);
        sent_fd = true;
    }
    else 
    {
        inform_consumers_buffer_is_updated;
    }
    wait_for_ack_from_consumers_that_buffer_is_read;
}

For informing consumers or waiting for ack from consumers, please use send() and recv():
send(2) - Linux manual page
recv(2) - Linux manual page

1、why “decodeToFd” so many times?could not reuse the jpgfd?
2、“wait_for_ack_from_consumers_that_buffer_is_read” ?just consumer echo a message?or more comsumer process methods?more detailed explanation or example code?

Hi,
We have updated the pseudo code. Please check if it is more clear. Assume you will update new JPEG data to pFileBuffer and then do continuous decoding. It is decoded to the same NvBuffer and then inform consumers the buffer is updated.

For publishing a new sample we would need to go through some process. It is underway and would take some time.

hi qwertzui11,you project NvBufferTransformEx ok ? no SYNC_IOC_FENCE_INFO error ?
My test code always occure SYNC_IOC_FENCE_INFO error after sending 1011 frames,could you help me?

thank you !!!
cross.tar.gz (113.0 KB)

In server producer ,i add "int m_nFlag[MAX_CLIENT] " to save consumer client confirm messages,and send the next new fd which is produced by [00_video_decode sample]; it also failed on 1011 frames;
I did not know how to fix this problem…
why?why always 1011 frames?what is this problem?the fd need to free or destroy?


@DaneLLL @cloundliu @edwardlu @qwertzui11 Could you help me this problem?