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(¶meters);
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, ¶meters, 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;
}