nvJPEG:编码打包的 BGR
nvJPEG: encode packed BGR
好吧,我的目标很简单——尝试使用 packed/interleaved BGR 数据(也可以是 RGB)从缓冲区创建 JPEG 编码图像。
NVidia 文档包含 example, the proper image input is essentially described 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, 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
只是 returns 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,
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;
}
...aa 而且效果很好。
我很想弄清楚代码中缺少什么。非常感谢任何帮助或建议。
更新:
使用 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,但编码不适用于默认的编码器参数,必须明确设置子采样。
所以,一行代码解决了所有问题。
好吧,我的目标很简单——尝试使用 packed/interleaved BGR 数据(也可以是 RGB)从缓冲区创建 JPEG 编码图像。
NVidia 文档包含 example, the proper image input is essentially described 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, 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
只是 returns 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,
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;
}
...aa 而且效果很好。
我很想弄清楚代码中缺少什么。非常感谢任何帮助或建议。
更新: 使用 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,但编码不适用于默认的编码器参数,必须明确设置子采样。
所以,一行代码解决了所有问题。