Hi, we are migrating the usage of MMAPI to JetPack 5.x from 4.x, and we use /usr/src/jetson_multimedia_api/include/NvJpegDecoder.h
for JPEG decoding purpose.
We found that if we use the same decoder to decode multiple JPEG images with different sizes, the later ones will fail to decode.
Here attached the demo code:
#include <fstream>
#include <memory>
#include <cassert>
#include "NvJpegDecoder.h"
#include "NvJpegEncoder.h"
#include "nvbufsurface.h"
#include "nvbufsurftransform.h"
void test_decode(std::shared_ptr<NvJPEGDecoder> dec, const std::string &path, int index) {
// read
std::ifstream in(path);
in.seekg(0, std::ios::end);
const std::streamsize size = in.tellg();
std::string data;
data.resize(size);
in.seekg(0, std::ios::beg);
in.read(const_cast<char *>(data.data()), size);
in.close();
// decode
int decoded_fd = -1;
uint32_t pixfmt = 0;
uint32_t width = 0;
uint32_t height = 0;
int ret = dec->decodeToFd(decoded_fd, (unsigned char *) data.data(), data.size(), pixfmt, width, height);
assert(ret == 0);
NvBufSurface *decoded_surf = nullptr;
ret = NvBufSurfaceFromFd(decoded_fd, (void **) &decoded_surf);
assert(ret == 0 && decoded_surf != nullptr);
// allocate
NvBufSurfaceAllocateParams create_params;
memset(&create_params, 0, sizeof(create_params));
create_params.params.width = width;
create_params.params.height = height;
create_params.params.memType = NVBUF_MEM_SURFACE_ARRAY;
create_params.params.layout = NVBUF_LAYOUT_PITCH;
create_params.params.colorFormat = NVBUF_COLOR_FORMAT_YUV420;
create_params.memtag = NvBufSurfaceTag_VIDEO_CONVERT;
NvBufSurface *cropped_surf;
ret = NvBufSurfaceAllocate(&cropped_surf, 1, &create_params);
assert(ret == 0);
// crop
NvBufSurfTransformParams transform_params;
memset(&transform_params, 0, sizeof(transform_params));
NvBufSurfTransformRect src_rect;
src_rect.left = 0;
src_rect.top = 0;
src_rect.width = width;
src_rect.height = height;
transform_params.transform_flag = NVBUFSURF_TRANSFORM_CROP_SRC;
transform_params.src_rect = &src_rect;
ret = NvBufSurfTransform(decoded_surf, cropped_surf, &transform_params);
assert(ret == 0);
// encode
int cropped_fd = cropped_surf->surfaceList[0].bufferDesc;
auto enc = std::shared_ptr<NvJPEGEncoder>(NvJPEGEncoder::createJPEGEncoder("enc"));
unsigned long buf_size = width * height * 3 / 2;
unsigned char *buf = new unsigned char[buf_size];
ret = enc->encodeFromFd(cropped_fd, JCS_YCbCr, &buf, buf_size, 90);
assert(ret == 0);
std::ofstream out("out_" + std::to_string(index) + ".jpg");
out.write((char *) buf, buf_size);
delete[] buf;
ret = NvBufSurfaceDestroy(cropped_surf);
assert(ret == 0);
}
int main(int argc, char *argv[]) {
auto dec = std::shared_ptr<NvJPEGDecoder>(NvJPEGDecoder::createJPEGDecoder("dec"));
for (int i = 1; i < argc; ++i) {
test_decode(dec, argv[i], i);
}
}
Usage:
./jpeg_decode xxx.jpg yyy.jpg
The output would be like:
If we create a new decoder every time, it just works fine:
int main(int argc, char *argv[]) {
for (int i = 1; i < argc; ++i) {
auto dec = std::shared_ptr<NvJPEGDecoder>(NvJPEGDecoder::createJPEGDecoder("dec"));
test_decode(dec, argv[i], i);
}
}
However, this is not required in JetPack 4.4.
Since it’s not appropriate to create a new decoder per image, anything we can do to fix this problem?