I’m currently developing a program for live JPEG encoding images from a camera. After a lot of fumbling around, errors, and testing, I reduced my program down to a CLI that encodes a single “interlaced” RGB8 image (so no separated channels) and writes it to disk. However, after executing, I consistently get an NVJPEG_STATUS_EXECUTION_FAILED error when I call nvjpegEncodeImage()
. Unforunately, I can’t find any documentation on what this error is supposed to mean, how to interpret it, and how to resolve this issue. Could I get some help? You can find the relevant code below:
JpegEncoderCuda::JpegEncoderCuda(const nvjpegInputFormat_t input_format, const uint32_t quality)
: input_format_(input_format), quality_(static_cast<int>(quality)) {
// initialize nvjpeg structures
checkCudaErrors(nvjpegCreateSimple(&nv_handle_));
checkCudaErrors(nvjpegEncoderStateCreate(nv_handle_, &nv_enc_state_, nullptr));
checkCudaErrors(nvjpegEncoderParamsCreate(nv_handle_, &nv_enc_params_, nullptr));
checkCudaErrors(nvjpegEncoderParamsSetQuality(nv_enc_params_, quality_, nullptr));
checkCudaErrors(nvjpegEncoderParamsSetSamplingFactors(nv_enc_params_, NVJPEG_CSS_444, nullptr));
checkCudaErrors(nvjpegEncoderParamsSetOptimizedHuffman(nv_enc_params_, 0, nullptr));
}
[...]
void JpegEncoderCuda::encode(const ImageBase::SharedPtr& input_image, ImageData::SharedPtr jpeg_out) {
nvjpegImage_t nv_image = nvFromImageBase(input_image);
cudaDeviceSynchronize();
// Compress image
checkCudaErrors(nvjpegEncodeImage(nv_handle_,
nv_enc_state_,
nv_enc_params_,
&nv_image,
input_format_,
input_image->getWidth(),
input_image->getHeight(),
nullptr));
// get compressed stream size
size_t length;
checkCudaErrors(nvjpegEncodeRetrieveBitstream(nv_handle_, nv_enc_state_, nullptr, &length, nullptr));
// get stream itself
// checkCudaErrors(cudaStreamSynchronize(stream_));
std::unique_ptr<std::vector<uint8_t>> jpeg = std::make_unique<std::vector<uint8_t>>(length);
checkCudaErrors(nvjpegEncodeRetrieveBitstream(nv_handle_, nv_enc_state_, jpeg->data(), &length, nullptr));
// Return the image in jpeg_out
// [...]
}
nvjpegImage_t JpegEncoderCuda::nvFromImageBase(const ImageBase::SharedPtr& input_image) {
nvjpegImage_t nv_image;
const uint8_t* img_data = input_image->getDataPtr();
// Zero out all channels
for (int i = 0; i < NVJPEG_MAX_COMPONENT; i++) nv_image.channel[i] = nullptr;
for (int i = 0; i < NVJPEG_MAX_COMPONENT; i++) nv_image.pitch[i] = 0;
// For interlaced images like this one, we just put everything in channel 0 as here. You can see the example here:
// https://docs.nvidia.com/cuda/nvjpeg/index.html#using-nvjpegEncodeImage
// nvidia didn't make the `channel` pointers const, likely because this struct is used for outputing decoded images as
// well. Since we're using it to encode, this const cast should be safe
nv_image.channel[0] = const_cast<unsigned char*>(img_data);
nv_image.pitch[0] = input_image->getWidth() * 3;
return nv_image;
}