想要一些关于如何使用 nvjpegEncodeYUV() 的指南
Want some guide about how to use nvjpegEncodeYUV()
我正在尝试基于以下示例代码实现一些 jpeg 编码 cuda 代码:
https://docs.nvidia.com/cuda/nvjpeg/index.html#nvjpeg-encode-examples
我post所有的代码,测试结果和Makefile和输入文件。
我正在使用 NVIDIA 2080 HW + cuda 11.2 进行测试
但是从这道题可以看出,结果是fail。第一次失败是从 nvjpegEncodeYUV() 返回的错误代码是 2。抱怨一些无效参数。
但是我不知道哪里出了问题....你能帮我找出问题所在吗?
#include <iterator>
#include <fstream>
#include <iostream>
#include <vector>
#include <cassert>
#include <unistd.h>
#include "nppdefs.h"
#include "nppi_support_functions.h"
#include "nppi_color_conversion.h"
#include "nvjpeg.h"
#include "cuda_runtime.h"
#define DEFAULT_RAWFILE "./uyvy422.raw"
//file >>> buff_UYVY
int read_raw(const char *file2read, unsigned char *buff_UYVY)
{
if (!file2read) {
std::cout << "file2read empty!!" << std::endl;
return 1;
}
if (!buff_UYVY) {
std::cout << "buff_UYVY empty!!" << std::endl;
return 1;
}
std::string file_uyvy(file2read);
std::ifstream stream_uyvy;
stream_uyvy.open(file_uyvy, std::ios::in | std::ios::binary);
if (!stream_uyvy.is_open())
{
std::cerr << "[ERROR] cannot open the raw file " << file_uyvy
<< std::endl;
std::cerr << std::endl;
assert(0);
}
stream_uyvy.read((char*)buff_UYVY, 1920*1080*2);
stream_uyvy.close();
return 0;
}
int main(int argc, char*argv[])
{
unsigned char *buff_UYVY =
new unsigned char[1920 * 1080 * 2];
//file >>> buff_UYVY
int ret;
if (argv[1]) {
ret = read_raw(argv[1], buff_UYVY);
} else {
ret = read_raw(DEFAULT_RAWFILE, buff_UYVY);
}
if (ret != 0) {
std::cout << "read_raw() failed!!" << std::endl;
return ret;
}
if (!buff_UYVY) {
std::cout << "buff_UYVY empty!!" << std::endl;
return 1;
}
cudaError_t err_cu_api;
Npp8u* gpu_buff_CbYCr422;
err_cu_api = cudaMalloc((void**)&gpu_buff_CbYCr422,
1920*1080*2);
err_cu_api = cudaMemcpy((void*)gpu_buff_CbYCr422,
(const void*)buff_UYVY,
1920*1080*2,
cudaMemcpyHostToDevice);
//////////////////////////////////////////////////////////////////////////////
//https://docs.nvidia.com/cuda/nvjpeg/index.html#nvjpeg-encode-examples
nvjpegStatus_t status;
nvjpegHandle_t nv_handle;
nvjpegEncoderState_t nv_enc_state;
nvjpegEncoderParams_t nv_enc_params;
cudaStream_t stream = 0;
// initialize nvjpeg structures
status = nvjpegCreateSimple(&nv_handle);
std::cout << "nvjpegCreateSimple : " << status << std::endl;
status = nvjpegEncoderStateCreate(nv_handle, &nv_enc_state, stream);
std::cout << "nvjpegEncoderStateCreate : " << status << std::endl;
status = nvjpegEncoderParamsCreate(nv_handle, &nv_enc_params, stream);
std::cout << "nvjpegEncoderParamsCreate : " << status << std::endl;
nvjpegImage_t imgdesc =
{
{
gpu_buff_CbYCr422,
gpu_buff_CbYCr422 + 1920*1080,
gpu_buff_CbYCr422 + 1920*1080*2,
gpu_buff_CbYCr422 + 1920*1080*3
},
{
1920,
1920,
1920,
1920
}
};
// Compress image
status = nvjpegEncodeYUV(nv_handle, nv_enc_state, nv_enc_params,
&imgdesc, NVJPEG_CSS_422, 1920, 1080,
stream);
std::cout << "nvjpegEncodeYUV : " << status << std::endl;
// get compressed stream size
size_t length;
status = nvjpegEncodeRetrieveBitstream(nv_handle, nv_enc_state, NULL,
&length, stream);
std::cout << "nvjpegEncodeRetrieveBitstream : " << status << std::endl;
// get stream itself
cudaStreamSynchronize(stream);
std::vector<char> jpeg(length);
status = nvjpegEncodeRetrieveBitstream(nv_handle, nv_enc_state,
(unsigned char*)jpeg.data(), &length, 0);
std::cout << "nvjpegEncodeRetrieveBitstream : " << status << std::endl;
// write stream to file
cudaStreamSynchronize(stream);
std::ofstream output_file("test.jpg", std::ios::out | std::ios::binary);
output_file.write(jpeg.data(), length);
output_file.close();
//https://docs.nvidia.com/cuda/nvjpeg/index.html#nvjpeg-encode-examples
//////////////////////////////////////////////////////////////////////////////
cudaFree(gpu_buff_CbYCr422);
err_cu_api = err_cu_api;
delete[] buff_UYVY;
return 0;
}
$ ./test
nvjpegCreateSimple : 0
nvjpegEncoderStateCreate : 0
nvjpegEncoderParamsCreate : 0
nvjpegEncodeYUV : 2
nvjpegEncodeRetrieveBitstream : 2
nvjpegEncodeRetrieveBitstream : 2
CC = g++
CFLAGS = -v -Wall -I/usr/local/cuda/include -g
LDFLAGS += -L/usr/local/cuda/lib64
SRCS = main_gpu.cpp
PROG = test
OPENCV = `pkg-config opencv4 --cflags --libs`
LIBS = $(OPENCV) \
-lcudart \
-lnppisu \
-lnpps \
-lnppc \
-lnppial \
-lnppicc \
-lnppidei \
-lnppif \
-lnppig \
-lnppim \
-lnppist \
-lnppitc \
-lnvjpeg
.PHONY: all clean
all: $(PROG)
$(PROG):$(SRCS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $(PROG) $(SRCS) $(LIBS)
clean:
rm -f $(OBJS) $(PROG) *.jpg *.bmp
正在获取输入文件:
git clone https://github.com/jumogehn/Jumogehn.git
uyvy422.raw是吗
根据我在你的代码中看到的内容,我猜你的输入存储格式是 ordinary YUV422:
U0 Y0 V0 Y1 U2 Y2 V2 Y3 U4 Y4 V4…
这是一种交错存储格式。但是 docs for nvjpegEncodeYUV 状态:
The source argument should be filled with the corresponding YUV planar data.
因此您需要将交错输入转换为 planar storage of a Y plane followed by a U plane followed by a V plane。
因此,您的 imgdesc
需要更改,因为 U 和 V 平面的间距是 Y 平面的一半:
nvjpegImage_t imgdesc =
{
{
gpu_buff_CbYCr422, // pointer to start of Y plane
gpu_buff_CbYCr422 + 1920*1080, // pointer to start of U plane
gpu_buff_CbYCr422 + 1920*1080 + 960*1080, // pointer to start of V plane
NULL
},
{
1920, // pitch of Y plane
960, // pitch of U plane
960, // pitch of V plane
0
}
};
最后,您需要在参数中设置采样因子:
$ cat t2017.cpp
#include "nvjpeg.h"
#include "cuda_runtime.h"
#include <iostream>
#define DEFAULT_RAWFILE "./uyvy422.raw"
int main(int argc, char*argv[])
{
unsigned char *buff_UYVY =
new unsigned char[1920 * 1080 * 2];
cudaError_t err_cu_api;
unsigned char* gpu_buff_CbYCr422;
err_cu_api = cudaMalloc((void**)&gpu_buff_CbYCr422,
1920*1080*2);
err_cu_api = cudaMemcpy((void*)gpu_buff_CbYCr422,
(const void*)buff_UYVY,
1920*1080*2,
cudaMemcpyHostToDevice);
//////////////////////////////////////////////////////////////////////////////
//https://docs.nvidia.com/cuda/nvjpeg/index.html#nvjpeg-encode-examples
nvjpegStatus_t status;
nvjpegHandle_t nv_handle;
nvjpegEncoderState_t nv_enc_state;
nvjpegEncoderParams_t nv_enc_params;
cudaStream_t stream = 0;
// initialize nvjpeg structures
status = nvjpegCreateSimple(&nv_handle);
std::cout << "nvjpegCreateSimple : " << status << std::endl;
status = nvjpegEncoderStateCreate(nv_handle, &nv_enc_state, stream);
std::cout << "nvjpegEncoderStateCreate : " << status << std::endl;
status = nvjpegEncoderParamsCreate(nv_handle, &nv_enc_params, stream);
std::cout << "nvjpegEncoderParamsCreate : " << status << std::endl;
nvjpegImage_t imgdesc =
{
{
gpu_buff_CbYCr422,
gpu_buff_CbYCr422 + 1920*1080,
gpu_buff_CbYCr422 + 1920*1080 + 960*1080,
NULL
},
{
1920,
960,
960,
0
}
};
status = nvjpegEncoderParamsSetSamplingFactors(nv_enc_params, NVJPEG_CSS_422, stream);
std::cout << "nvjpegEncoderParamsSetSamplingFactors: " << status << std::endl;
// Compress image
status = nvjpegEncodeYUV(nv_handle, nv_enc_state, nv_enc_params,
&imgdesc, NVJPEG_CSS_422, 1920, 1080,
stream);
std::cout << "nvjpegEncodeYUV : " << status << std::endl;
}
$ g++ t2017.cpp -I/usr/local/cuda/include -L/usr/local/cuda/lib64 -lnvjpeg -lcudart -o t2017
$ ./t2017
nvjpegCreateSimple : 0
nvjpegEncoderStateCreate : 0
nvjpegEncoderParamsCreate : 0
nvjpegEncoderParamsSetSamplingFactors: 0
nvjpegEncodeYUV : 0
$
我并不是说这会修复代码中所有可能的错误,只是它似乎解决了这个问题:
First fail is from nvjpegEncodeYUV() The returned error code is 2. That complains for some invalid parameters. But I have no idea what is wrong.... Could you please help me find what went wrong?
我正在尝试基于以下示例代码实现一些 jpeg 编码 cuda 代码: https://docs.nvidia.com/cuda/nvjpeg/index.html#nvjpeg-encode-examples
我post所有的代码,测试结果和Makefile和输入文件。
我正在使用 NVIDIA 2080 HW + cuda 11.2 进行测试
但是从这道题可以看出,结果是fail。第一次失败是从 nvjpegEncodeYUV() 返回的错误代码是 2。抱怨一些无效参数。 但是我不知道哪里出了问题....你能帮我找出问题所在吗?
#include <iterator>
#include <fstream>
#include <iostream>
#include <vector>
#include <cassert>
#include <unistd.h>
#include "nppdefs.h"
#include "nppi_support_functions.h"
#include "nppi_color_conversion.h"
#include "nvjpeg.h"
#include "cuda_runtime.h"
#define DEFAULT_RAWFILE "./uyvy422.raw"
//file >>> buff_UYVY
int read_raw(const char *file2read, unsigned char *buff_UYVY)
{
if (!file2read) {
std::cout << "file2read empty!!" << std::endl;
return 1;
}
if (!buff_UYVY) {
std::cout << "buff_UYVY empty!!" << std::endl;
return 1;
}
std::string file_uyvy(file2read);
std::ifstream stream_uyvy;
stream_uyvy.open(file_uyvy, std::ios::in | std::ios::binary);
if (!stream_uyvy.is_open())
{
std::cerr << "[ERROR] cannot open the raw file " << file_uyvy
<< std::endl;
std::cerr << std::endl;
assert(0);
}
stream_uyvy.read((char*)buff_UYVY, 1920*1080*2);
stream_uyvy.close();
return 0;
}
int main(int argc, char*argv[])
{
unsigned char *buff_UYVY =
new unsigned char[1920 * 1080 * 2];
//file >>> buff_UYVY
int ret;
if (argv[1]) {
ret = read_raw(argv[1], buff_UYVY);
} else {
ret = read_raw(DEFAULT_RAWFILE, buff_UYVY);
}
if (ret != 0) {
std::cout << "read_raw() failed!!" << std::endl;
return ret;
}
if (!buff_UYVY) {
std::cout << "buff_UYVY empty!!" << std::endl;
return 1;
}
cudaError_t err_cu_api;
Npp8u* gpu_buff_CbYCr422;
err_cu_api = cudaMalloc((void**)&gpu_buff_CbYCr422,
1920*1080*2);
err_cu_api = cudaMemcpy((void*)gpu_buff_CbYCr422,
(const void*)buff_UYVY,
1920*1080*2,
cudaMemcpyHostToDevice);
//////////////////////////////////////////////////////////////////////////////
//https://docs.nvidia.com/cuda/nvjpeg/index.html#nvjpeg-encode-examples
nvjpegStatus_t status;
nvjpegHandle_t nv_handle;
nvjpegEncoderState_t nv_enc_state;
nvjpegEncoderParams_t nv_enc_params;
cudaStream_t stream = 0;
// initialize nvjpeg structures
status = nvjpegCreateSimple(&nv_handle);
std::cout << "nvjpegCreateSimple : " << status << std::endl;
status = nvjpegEncoderStateCreate(nv_handle, &nv_enc_state, stream);
std::cout << "nvjpegEncoderStateCreate : " << status << std::endl;
status = nvjpegEncoderParamsCreate(nv_handle, &nv_enc_params, stream);
std::cout << "nvjpegEncoderParamsCreate : " << status << std::endl;
nvjpegImage_t imgdesc =
{
{
gpu_buff_CbYCr422,
gpu_buff_CbYCr422 + 1920*1080,
gpu_buff_CbYCr422 + 1920*1080*2,
gpu_buff_CbYCr422 + 1920*1080*3
},
{
1920,
1920,
1920,
1920
}
};
// Compress image
status = nvjpegEncodeYUV(nv_handle, nv_enc_state, nv_enc_params,
&imgdesc, NVJPEG_CSS_422, 1920, 1080,
stream);
std::cout << "nvjpegEncodeYUV : " << status << std::endl;
// get compressed stream size
size_t length;
status = nvjpegEncodeRetrieveBitstream(nv_handle, nv_enc_state, NULL,
&length, stream);
std::cout << "nvjpegEncodeRetrieveBitstream : " << status << std::endl;
// get stream itself
cudaStreamSynchronize(stream);
std::vector<char> jpeg(length);
status = nvjpegEncodeRetrieveBitstream(nv_handle, nv_enc_state,
(unsigned char*)jpeg.data(), &length, 0);
std::cout << "nvjpegEncodeRetrieveBitstream : " << status << std::endl;
// write stream to file
cudaStreamSynchronize(stream);
std::ofstream output_file("test.jpg", std::ios::out | std::ios::binary);
output_file.write(jpeg.data(), length);
output_file.close();
//https://docs.nvidia.com/cuda/nvjpeg/index.html#nvjpeg-encode-examples
//////////////////////////////////////////////////////////////////////////////
cudaFree(gpu_buff_CbYCr422);
err_cu_api = err_cu_api;
delete[] buff_UYVY;
return 0;
}
$ ./test
nvjpegCreateSimple : 0
nvjpegEncoderStateCreate : 0
nvjpegEncoderParamsCreate : 0
nvjpegEncodeYUV : 2
nvjpegEncodeRetrieveBitstream : 2
nvjpegEncodeRetrieveBitstream : 2
CC = g++
CFLAGS = -v -Wall -I/usr/local/cuda/include -g
LDFLAGS += -L/usr/local/cuda/lib64
SRCS = main_gpu.cpp
PROG = test
OPENCV = `pkg-config opencv4 --cflags --libs`
LIBS = $(OPENCV) \
-lcudart \
-lnppisu \
-lnpps \
-lnppc \
-lnppial \
-lnppicc \
-lnppidei \
-lnppif \
-lnppig \
-lnppim \
-lnppist \
-lnppitc \
-lnvjpeg
.PHONY: all clean
all: $(PROG)
$(PROG):$(SRCS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $(PROG) $(SRCS) $(LIBS)
clean:
rm -f $(OBJS) $(PROG) *.jpg *.bmp
正在获取输入文件:
git clone https://github.com/jumogehn/Jumogehn.git
uyvy422.raw是吗
根据我在你的代码中看到的内容,我猜你的输入存储格式是 ordinary YUV422:
U0 Y0 V0 Y1 U2 Y2 V2 Y3 U4 Y4 V4…
这是一种交错存储格式。但是 docs for nvjpegEncodeYUV 状态:
The source argument should be filled with the corresponding YUV planar data.
因此您需要将交错输入转换为 planar storage of a Y plane followed by a U plane followed by a V plane。
因此,您的 imgdesc
需要更改,因为 U 和 V 平面的间距是 Y 平面的一半:
nvjpegImage_t imgdesc =
{
{
gpu_buff_CbYCr422, // pointer to start of Y plane
gpu_buff_CbYCr422 + 1920*1080, // pointer to start of U plane
gpu_buff_CbYCr422 + 1920*1080 + 960*1080, // pointer to start of V plane
NULL
},
{
1920, // pitch of Y plane
960, // pitch of U plane
960, // pitch of V plane
0
}
};
最后,
$ cat t2017.cpp
#include "nvjpeg.h"
#include "cuda_runtime.h"
#include <iostream>
#define DEFAULT_RAWFILE "./uyvy422.raw"
int main(int argc, char*argv[])
{
unsigned char *buff_UYVY =
new unsigned char[1920 * 1080 * 2];
cudaError_t err_cu_api;
unsigned char* gpu_buff_CbYCr422;
err_cu_api = cudaMalloc((void**)&gpu_buff_CbYCr422,
1920*1080*2);
err_cu_api = cudaMemcpy((void*)gpu_buff_CbYCr422,
(const void*)buff_UYVY,
1920*1080*2,
cudaMemcpyHostToDevice);
//////////////////////////////////////////////////////////////////////////////
//https://docs.nvidia.com/cuda/nvjpeg/index.html#nvjpeg-encode-examples
nvjpegStatus_t status;
nvjpegHandle_t nv_handle;
nvjpegEncoderState_t nv_enc_state;
nvjpegEncoderParams_t nv_enc_params;
cudaStream_t stream = 0;
// initialize nvjpeg structures
status = nvjpegCreateSimple(&nv_handle);
std::cout << "nvjpegCreateSimple : " << status << std::endl;
status = nvjpegEncoderStateCreate(nv_handle, &nv_enc_state, stream);
std::cout << "nvjpegEncoderStateCreate : " << status << std::endl;
status = nvjpegEncoderParamsCreate(nv_handle, &nv_enc_params, stream);
std::cout << "nvjpegEncoderParamsCreate : " << status << std::endl;
nvjpegImage_t imgdesc =
{
{
gpu_buff_CbYCr422,
gpu_buff_CbYCr422 + 1920*1080,
gpu_buff_CbYCr422 + 1920*1080 + 960*1080,
NULL
},
{
1920,
960,
960,
0
}
};
status = nvjpegEncoderParamsSetSamplingFactors(nv_enc_params, NVJPEG_CSS_422, stream);
std::cout << "nvjpegEncoderParamsSetSamplingFactors: " << status << std::endl;
// Compress image
status = nvjpegEncodeYUV(nv_handle, nv_enc_state, nv_enc_params,
&imgdesc, NVJPEG_CSS_422, 1920, 1080,
stream);
std::cout << "nvjpegEncodeYUV : " << status << std::endl;
}
$ g++ t2017.cpp -I/usr/local/cuda/include -L/usr/local/cuda/lib64 -lnvjpeg -lcudart -o t2017
$ ./t2017
nvjpegCreateSimple : 0
nvjpegEncoderStateCreate : 0
nvjpegEncoderParamsCreate : 0
nvjpegEncoderParamsSetSamplingFactors: 0
nvjpegEncodeYUV : 0
$
我并不是说这会修复代码中所有可能的错误,只是它似乎解决了这个问题:
First fail is from nvjpegEncodeYUV() The returned error code is 2. That complains for some invalid parameters. But I have no idea what is wrong.... Could you please help me find what went wrong?