Error when multi threading plus tcp_rates issue.

13 views
Skip to first unread message

Steve Quartly

unread,
Dec 5, 2024, 12:41:02 AMDec 5
to OpenJPEG
Hey All,
I am trying to use OpenJPEG v2.5 in a multi threaded environment to encode DCI compliant JPEG2000 frames.
I am running 20 simultaneous threads and it starts off well, but after 200 or so frames I start getting this error:
Not enough memory to allocate m_encoded_tile_data. 12 MB required
Can anyone please give me any advice on how I can address this issue?

Also can someone advise me on how to set the tcp_rates parameter so I can set my data rate. I'm seeing so much conflicting information on how to set it, none of which give me the result I need.

One final question, how does OpenJPEG handle the frame rates for SMPTE DCI compliant DCPs? ie: 25, 30, 60fps etc.

Thanks everyone, my code is below.
Steve Q. :-)

int Image2J2K_OpenJPEG(CDCPProEncoderDlg* dped, unsigned char* imageBuffer8bpp, int width, int height, char* outName, char* inputPath, char* outFilename, CButton* previewEnable, struct ThreadParams* tp, uint16_t* imageBuffer12bpp)
{
int retstatus = STATUS_ALL_OK;

const int components = 3; // RGB
const int bit_depth = 12; // DCI spec

CString tempFileName, outFile, ext;

outFile = outName;

// Get the file extension
ext = outFile.Mid( outFile.ReverseFind( '.' ), 200 );

// Now erase it from the original file
outFile.Replace(ext, "");

if ( tp->performXYZTransform ) outFile += "_XYZ.j2k";
else outFile += ".j2k";

tempFileName = outFilename;

tempFileName += "\\";

tempFileName += outFile;

opj_cparameters_t parameters;

// Set up the OpenJPEG compression parameters
opj_set_default_encoder_parameters(&parameters);

parameters.cod_format = 0;  /** output file format 0: J2K, 1: JP2, 2: JPT */

if (tp->cinemaMode == CINEMA2K_24)
{
parameters.cp_cinema = OPJ_CINEMA2K_24;
parameters.rsiz = OPJ_PROFILE_CINEMA_2K;
}

else if (tp->cinemaMode == CINEMA2K_48)
{
parameters.cp_cinema = OPJ_CINEMA2K_48;
parameters.rsiz = OPJ_PROFILE_CINEMA_2K;
}

else if (tp->cinemaMode == CINEMA2K_24)
{
parameters.cp_cinema = OPJ_CINEMA4K_24;
parameters.rsiz = OPJ_PROFILE_CINEMA_4K;
}

parameters.tcp_rates[0] = 12 /*tp->jpegCompressionAmount*/;

parameters.tcp_numlayers = 1;
parameters.cp_disto_alloc = 1;
parameters.tile_size_on = false;
parameters.cp_tx0 = 0;
parameters.cp_ty0 = 0;
parameters.cp_tdx = 1;
parameters.cp_tdy = 1;

/*Tile part*/
parameters.tp_flag = 'C';
parameters.tp_on = 1;

/*Tile and Image shall be at (0,0)*/
parameters.image_offset_x0 = 0;
parameters.image_offset_y0 = 0;

/*Codeblock size= 32*32*/
parameters.cblockw_init = 32;
parameters.cblockh_init = 32;
parameters.csty |= 0x01;

/*The progression order shall be CPRL*/
parameters.prog_order = OPJ_CPRL;

/* No ROI */
parameters.roi_compno = -1;

parameters.subsampling_dx = 1;
parameters.subsampling_dy = 1;

/* 9-7 transform */
parameters.irreversible = 1;

parameters.numresolution = 6;

/* Decide if MCT should be used */
parameters.tcp_mct = components == 3 ? 1 : 0;

// Setup OpenJPEG image structure
opj_image_cmptparm_t cmptparm[ components ];

memset( &cmptparm, 0, sizeof( cmptparm ) );

for ( int i = 0; i < components; ++i )
{
cmptparm[i].dx = 1;
cmptparm[i].dy = 1;
cmptparm[i].w = width;
cmptparm[i].h = height;
cmptparm[i].x0 = 0;
cmptparm[i].y0 = 0;
cmptparm[i].prec = bit_depth;
cmptparm[i].bpp = bit_depth;
cmptparm[i].sgnd = 0; // Unsigned data
}

// Create the OpenJPEG image
opj_image_t* image = opj_image_create(components, cmptparm, OPJ_CLRSPC_SYCC);

if ( image )
{
image->x0 = 0;
image->y0 = 0;
image->x1 = width;
image->y1 = height;

// Scale the input image buffer from 8 bit to 12 bit
size_t num_pixels = width * height * 3; // 3 components (R, G, B)

// Scaling factor for 8-bit to 12-bit conversion
const float scale_factor = 4095.0f / 255.0f;

// Convert each pixel to 12 bit
for  (size_t i = 0; i < num_pixels; ++i )
{
imageBuffer12bpp[ i ] = static_cast<uint16_t>(imageBuffer8bpp[i] * scale_factor + 0.5f ); // Round to nearest integer
}

// Copy the 12 bit buffer into the OpenJPEG buffer
for ( int c = 0; c < components; c++ )
{
for ( int y = 0; y < height; y++ )
{
for ( int x = 0; x < width; x++ )
{
int index = y * width + x;

image->comps[ c ].data[ index ] = imageBuffer12bpp[ index * components + c ];
}
}
}

// Flash the encoding JPEG2000 LED
dped->m_jpeg2000Led.SetLedState(GREEN_LIGHT);

// Create the OpenJPEG codec
opj_codec_t* codec = opj_create_compress( OPJ_CODEC_J2K );

opj_set_info_handler( codec, info_callback, nullptr );
opj_set_warning_handler( codec, warning_callback, nullptr );
opj_set_error_handler( codec, error_callback, nullptr );

// Setup the OpenJPEG encoder
if ( opj_setup_encoder( codec, &parameters, image ) )
{
// Open output file
FILE* file = fopen( tempFileName, "wb" );

if ( file )
{
// Creat the OpenJPEG stream
opj_stream_t* stream = opj_stream_create_default_file_stream( tempFileName, OPJ_STREAM_WRITE );

if ( stream )
{
// Encode
if ( opj_start_compress( codec, image, stream ) )
{
if ( opj_encode( codec, stream ) )
{
if ( opj_end_compress( codec, stream ) )
{
// Cleanup
opj_stream_destroy( stream );

fclose( file );

opj_image_destroy(image);

opj_destroy_codec( codec );

// This gets the file size
CString fileSize;

fileSize = dped->GetFilesize(tempFileName);

if (fileSize.GetLength() == 6)
{
fileSize.GetBufferSetLength(3);

fileSize += "kb";
}

else if (fileSize.GetLength() == 5)
{
fileSize.GetBufferSetLength(3);

fileSize.Insert(2, '.');

fileSize += "kb";
}

else if (fileSize.GetLength() == 7)
{
fileSize.GetBufferSetLength(3);

fileSize.Insert(1, '.');

fileSize += "meg";
}

else
{
fileSize += "bytes";
}

CString* message;
message = new CString;

message->Format("%d> Generated: %s (%s)", tp->threadIndex + 1, outFile, fileSize);

PostMessage(dped->m_hWnd, ENCODER_JOBLIST_MESSAGE, (LPARAM)RGB(0, 128, 0), (LPARAM)message);
}

else
{
opj_stream_destroy(stream);

fclose(file);

opj_image_destroy(image);

opj_destroy_codec(codec);

retstatus = STATUS_ERROR_OPJ_FINALIZECOMPRESS;
}
}

else
{
opj_stream_destroy(stream);

fclose(file);

opj_image_destroy(image);

opj_destroy_codec(codec);

retstatus = STATUS_ERROR_OPJ_ENCODE;
}
}

else
{
opj_stream_destroy( stream) ;

fclose( file );

opj_image_destroy(image);

opj_destroy_codec( codec );

retstatus = STATUS_ERROR_OPJ_STARTCOMPRESS;
}
}

else
{
fclose( file );

opj_image_destroy(image);

opj_destroy_codec( codec );

retstatus = STATUS_ERROR_OPJ_STREAM;
}
}

else
{
opj_image_destroy(image);

opj_destroy_codec( codec );

retstatus = STATUS_ERROR_FILE;
}
}

else
{
opj_image_destroy(image);

opj_destroy_codec( codec );

retstatus = STATUS_ERROR_OPJ_SETUPENCODER;
}
}

else retstatus = STATUS_ERROR_OPJ_IMAGECREATE;

return retstatus;
}

Steve Quartly

unread,
Dec 12, 2024, 4:50:32 AM (10 days ago) Dec 12
to OpenJPEG
Further to my issue above, I have just tried to load the library dynamically, rather than statically, but it appears to have the same problem.

@Even Rouault, would you have any suggestions please?

Thank you.
Reply all
Reply to author
Forward
0 new messages