首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >nvJPEG:压缩BGR编码

nvJPEG:压缩BGR编码
EN

Stack Overflow用户
提问于 2021-01-28 01:03:29
回答 1查看 1.6K关注 0票数 3

好吧,我的目标很简单--尝试用打包/交织的BGR数据从缓冲区创建JPEG编码的图像(也可以是RGB )。

NVidia文档包含一个示例,正确的图像输入本质上被描述为这里

因此,我尝试了以下几点:

代码语言:javascript
复制
#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, nv_enc_state, NULL, &length, stream);

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

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

  return jpeg;
}

记录器说nvjpegEncodeImage只返回NVJPEG_STATUS_INVALID_PARAMETER,这意味着什么都不起作用。如果您怀疑my_bitmap_type填充错误,下面是类似的涡轮增压编码:

代码语言:javascript
复制
#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,
                            image->width * 3,
                            image->height,
                            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;
}

..。而且它工作得很好。

我很想弄清楚密码里少了什么。会感激你的帮助或建议。

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-01-29 00:14:33

Okaaay,这有点奇怪,但经过一段时间的尝试和错误之后,人们发现NVidia文档缺乏基本的细节:

代码语言:javascript
复制
    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); 

尽管docs清楚地声明JPEG压缩的默认次采样为4:4:4,但编码不能与默认的编码器params一起工作,但必须显式设置次采样。

所以,这一行代码修复了所有的东西。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65929613

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档