Segmentation fault in NvJPEGEncoder::encodeFromBuffer when encoder accessed from multiple threads

Hi,

The program:

#include <vector>
#include <memory>
#include <mutex>
#include <thread>

#include <NvJpegEncoder.h>

std::recursive_mutex cmut;

bool encode_yuv(std::unique_ptr<NvJPEGEncoder>& encoder,
                uint8_t* bufY,
                uint8_t* bufU,
                uint8_t* bufV,
                const uint16_t height,
                const uint16_t width,
                std::vector<uint8_t> &outBuf,
                uint8_t quality = 80)
{
  const std::lock_guard<std::recursive_mutex> lock(cmut);

  if (!encoder)
  {
    return false;
  }

  quality = std::min(quality, static_cast<uint8_t>(100));

  NvBuffer buffer(V4L2_PIX_FMT_YUV420M, width, height, 0);

  buffer.planes[0].data = bufY;
  buffer.planes[0].bytesused = width * height;

  buffer.planes[1].data = bufU;
  buffer.planes[1].bytesused = width * height / 4;

  buffer.planes[2].data = bufV;
  buffer.planes[2].bytesused = width * height / 4;

  uint64_t outBufSize = 3 * width * height / 2;
  outBuf.resize(outBufSize);
  auto outBufPtr = outBuf.data();

  if (encoder->encodeFromBuffer(buffer, JCS_YCbCr, &outBufPtr, outBufSize, quality) < 0)
  {
    return false;
  }

  outBuf.resize(outBufSize);
  return true;
}

void run(std::unique_ptr<NvJPEGEncoder>& encoder)
{
  int cols = 256;
  int rows = 256;

  std::vector<uint8_t> channel0(rows*cols, 1);
  std::vector<uint8_t> channel1((rows/2)*(cols/2), 2);
  std::vector<uint8_t> channel2((rows/2)*(cols/2), 3);

  std::vector<uint8_t> out_jpeg;
  
  std::cout << encode_yuv(
    encoder,
    channel0.data(),
    channel1.data(),
    channel2.data(),
    rows, cols,
    out_jpeg
  ) << std::endl;
}

int main()
{
  std::unique_ptr<NvJPEGEncoder> encoder = std::unique_ptr<NvJPEGEncoder>(NvJPEGEncoder::createJPEGEncoder("jpenenc"));
  std::vector<std::thread> thr;

  for (int i = 0; i < 30; i++)
  {
    thr.push_back(
      std::thread(run, std::ref(encoder))
    );
  }

  for(auto &t: thr)
  {
		t.join();
  }

  return 0;
}

fails with segfault and the following back trace:

(signal SIGSEGV), 0x0000ffffb160fac4 in ?? () from /usr/lib/aarch64-linux-gnu/tegra/libnvvideo.so
#0  0x0000ffffb160fac4 in ?? () from /usr/lib/aarch64-linux-gnu/tegra/libnvvideo.so
#1  0x0000ffffb14432d0 in ?? () from /usr/lib/aarch64-linux-gnu/tegra/libnvmmlite_image.so
#2  0x0000ffffb1443694 in ?? () from /usr/lib/aarch64-linux-gnu/tegra/libnvmmlite_image.so
#3  0x0000ffffee3213b8 in NvMMLiteBlockDoWork () from /usr/lib/aarch64-linux-gnu/tegra/libnvmmlite_utils.so
#4  0x0000ffffee334be0 in ?? () from /usr/lib/aarch64-linux-gnu/tegra/libnvmmlite.so
#5  0x0000fffff7fa56a4 in jpegTegraEncoderCompress () from /usr/lib/aarch64-linux-gnu/tegra/libnvjpeg.so
#6  0x0000fffff7f6bc08 in jpeg_write_raw_data () from /usr/lib/aarch64-linux-gnu/tegra/libnvjpeg.so
#7  0x0000aaaaaada416c in NvJPEGEncoder::encodeFromBuffer (this=0xaaaaabb4ac20, buffer=..., color_space=<optimized out>, out_buf=<optimized out>, out_buf_size=<optimized out>, quality=<optimized out>)
    at /rootfs_arm64/usr/src/jetson_multimedia_api/samples/common/classes/NvJpegEncoder.cpp:258

Could you please help to check this issue? Thanks.

The jetpack version is 5.1.3.

Hi,
Please create individual NvJPEGEncoder object for each thread. Or if you would like to use singe object, please use mutex to ensure encodeFromBuffer() is sequentially called(to avoid calling it concurrently).

Hi,

I would like to use a single object. In the provided code encodeFromBuffer() is already inside the critical section (locked with the mutex in the beginning of the encode_yuv() function). Nevertheless, this does not prevent aforementioned segfault. Could you please tell whether any additional syncronization primitive required or generally is there anything else missing?