微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

nvJPEG:编码打包的 BGR

如何解决nvJPEG:编码打包的 BGR

嗯,我的目标很简单——尝试从带有打包/交错 BGR 数据(也可以是 RGB)的缓冲区创建一个 JPEG 编码的图像。

NVidia 文档包含 example,正确的图像输入本质上描述为 here

所以我尝试了以下方法

#include <nvjpeg.h>

// very simple
typedef struct {
    int width;
    int height;
    unsigned char *buffer; 
    unsigned long data_size; 
} my_bitmap_type;


std::vector<unsigned char> BitmapToJpegCUDA(const my_bitmap_type *image) 
{
  nvjpegHandle_t nv_handle;
  nvjpegEncoderState_t nv_enc_state;
  nvjpegEncoderParams_t nv_enc_params;
  cudaStream_t stream = NULL;

  nvjpegStatus_t er;
  nvjpegCreateSimple(&nv_handle);
  nvjpegEncoderStateCreate(nv_handle,&nv_enc_state,stream);
  nvjpegEncoderParamsCreate(nv_handle,&nv_enc_params,stream);

  nvjpegImage_t nv_image;
  nv_image.channel[0] = image->buffer;
  nv_image.pitch[0] = 3 * image->width;

  // nope,that's for planar images!

  // nv_image.channel[0] = image->buffer;
  // nv_image.channel[1] = image->buffer + image->width * image->height;
  // nv_image.channel[2] = image->buffer + 2 * image->width * image->height;
  // nv_image.pitch[0] = image->width;
  // nv_image.pitch[1] = image->width;
  // nv_image.pitch[2] = image->width;

  er = nvjpegEncodeImage(nv_handle,nv_enc_state,nv_enc_params,&nv_image,NVJPEG_INPUT_BGRI,image->width,image->height,stream);
  LOG(ERROR) << "enc " << er;

  size_t length = 0;
  nvjpegEncodeRetrieveBitstream(nv_handle,NULL,&length,stream);

  cudaStreamSynchronize(stream);
  std::vector<unsigned char> jpeg(length);
  nvjpegEncodeRetrieveBitstream(nv_handle,jpeg.data(),0);

  nvjpegEncoderParamsDestroy(nv_enc_params);
  nvjpegEncoderStateDestroy(nv_enc_state);
  nvjpegDestroy(nv_handle);

  return jpeg;
}

记录器说 nvjpegEncodeImage 只返回 NVJPEG_STATUS_INVALID_ParaMETER,这意味着没有任何作用。如果您怀疑 my_bitmap_type 填写错误,这里是类似的 turbojpeg 编码:

#include <turbojpeg.h>

std::vector<unsigned char> BitmapToJpegBuffer(const my_bitmap_type *image)
{
    std::vector<unsigned char> out_data(3 * image->width * image->height);

    cudaError_t err = cudamemcpy(out_data.data(),image->buffer,image->data_size,cudamemcpyDevicetoHost);
    if (cudaSuccess != err) {
        LOG(ERROR) << "Failed to copy CUDA memory: " << err;
    }

    tjhandle jpeg = tjInitCompress();
    unsigned char *encoded_buf = nullptr;
    long unsigned int encoded_sz = 0;

    int tjres = tjCompress2(jpeg,out_data.data(),image->width * 3,TJPF_BGR,&encoded_buf,&encoded_sz,TJSAMP_444,95,TJFLAG_FASTDCT);

    if (tjres != 0) {
        LOG(ERROR) << "jpeg compession Failed!";
        return {};
    }

    std::vector<unsigned char> result(encoded_buf,encoded_buf + encoded_sz);
    tjFree(encoded_buf);
    tjDestroy(jpeg);

    return result;
}

... aa它工作得很好。

我非常想弄清楚代码中缺少什么。非常感谢任何帮助或建议。

UPD: 使用 CentOS 7 / libnvjpeg-11-1.x86_64 (CUDA 11.1) / gcc 4.8.5

解决方法

好吧,这有点奇怪,但经过一段时间的反复试验,发现 NVidia 文档缺少基本细节:

    nvjpegCreateSimple(&nv_handle);
    nvjpegEncoderStateCreate(nv_handle,&nv_enc_state,stream);
    nvjpegEncoderParamsCreate(nv_handle,&nv_enc_params,stream);

    // This has to be done,default params are not sufficient
    nvjpegEncoderParamsSetSamplingFactors(nv_enc_params,NVJPEG_CSS_444,stream); 

尽管文档明确指出 JPEG 压缩的默认子采样为 4:4:4,但编码不适用于默认编码器参数,因此必须明确设置子采样。

所以,那一行代码解决了所有问题。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。