TuttleOFX
1
|
00001 #include "J2KWriter.hpp" 00002 #include "J2KCommon.hpp" 00003 00004 #include <tuttle/plugin/exceptions.hpp> 00005 #include <terry/typedefs.hpp> 00006 00007 #include <iostream> 00008 #include <cstring> 00009 #include <string> 00010 #include <vector> 00011 00012 namespace tuttle { 00013 namespace io { 00014 00015 namespace fs = boost::filesystem; 00016 00017 J2KWriter::J2KWriter() 00018 : _width(0) 00019 , _height(0) 00020 , _components(0) 00021 , _precision(0) 00022 , _cinemaMode(OFF) 00023 , _cio(NULL) 00024 { 00025 memset( &_openjpeg, 0, sizeof(OpenJpegStuffs) ); 00026 } 00027 00028 J2KWriter::~J2KWriter() 00029 { 00030 close(); 00031 } 00032 00033 void J2KWriter::open(const std::string & filename, const std::size_t w, const std::size_t h, const std::size_t nc, const std::size_t dprecision) 00034 { 00035 close(); 00036 std::vector<opj_image_cmptparm_t> cmptparm(nc); 00037 OPJ_COLOR_SPACE color_space; 00038 std::size_t j; 00039 int subsampling_dx, subsampling_dy; 00040 00041 /** Routines d'ouverture du fichier **/ 00042 // configure the event callbacks (not required) 00043 // setting of each callback is optionnal 00044 memset(&_openjpeg, 0, sizeof(OpenJpegStuffs)); 00045 00046 /* set encoding parameters to default values */ 00047 opj_set_default_encoder_parameters(&_openjpeg.parameters); 00048 _openjpeg.parameters.cod_format = J2K_CFMT; 00049 _openjpeg.parameters.cp_cinema = _cinemaMode; 00050 00051 switch(_cinemaMode) 00052 { 00053 case OFF: 00054 _openjpeg.parameters.cp_rsiz = STD_RSIZ; 00055 _openjpeg.parameters.irreversible = _lossless ? 0 : 1; 00056 break; 00057 case CINEMA2K_24: 00058 case CINEMA2K_48: 00059 _openjpeg.parameters.cp_rsiz = CINEMA2K; 00060 break; 00061 case CINEMA4K_24: 00062 _openjpeg.parameters.cp_rsiz = CINEMA4K; 00063 break; 00064 } 00065 00066 ////////////////////////////////////////////////////////////////////////// 00067 // if no rate entered, lossless by default 00068 if( _openjpeg.parameters.tcp_numlayers == 0 ) 00069 { 00070 _openjpeg.parameters.tcp_rates[0] = 0; /* MOD antonin : losslessbug */ 00071 _openjpeg.parameters.tcp_numlayers++; 00072 _openjpeg.parameters.cp_disto_alloc = 1; 00073 } 00074 if( _cinemaMode ) 00075 { 00076 cinemaSetupParameters(); 00077 } 00078 00079 // Create comment for codestream 00080 if ( _openjpeg.parameters.cp_comment == NULL ) 00081 { 00082 const char comment[] = "TuttleOFX"; 00083 const std::size_t clen = strlen(comment); 00084 const char *version = "";//opj_version(); 00085 _openjpeg.parameters.cp_comment = (char*)malloc( clen + strlen( version ) + 1 ); 00086 sprintf( _openjpeg.parameters.cp_comment,"%s%s", comment, version ); 00087 } 00088 00089 ////////////////////////////////////////////////////////////////////////// 00090 color_space = CLRSPC_UNKNOWN;//CLRSPC_SRGB; 00091 // initialize image components 00092 memset( &cmptparm[0], 0, nc * sizeof(opj_image_cmptparm_t) ); 00093 subsampling_dx = _openjpeg.parameters.subsampling_dx; 00094 subsampling_dy = _openjpeg.parameters.subsampling_dy; 00095 for ( j = 0; j < nc; j++ ) 00096 { 00097 if ( _openjpeg.parameters.cp_cinema ) 00098 { 00099 cmptparm[j].prec = 12; 00100 cmptparm[j].bpp = 12; 00101 } 00102 else 00103 { 00104 cmptparm[j].prec = dprecision; 00105 cmptparm[j].bpp = dprecision; 00106 } 00107 cmptparm[j].sgnd = 0; 00108 cmptparm[j].dx = subsampling_dx; 00109 cmptparm[j].dy = subsampling_dy; 00110 cmptparm[j].w = w; 00111 cmptparm[j].h = h; 00112 } 00113 00114 /* create the image*/ 00115 _openjpeg.image = opj_image_create( nc, &cmptparm[0], color_space ); 00116 00117 _openjpeg.image->x0 = _openjpeg.parameters.image_offset_x0; 00118 _openjpeg.image->y0 = _openjpeg.parameters.image_offset_y0; 00119 _openjpeg.image->x1 = !_openjpeg.image->x0 ? (w - 1) * subsampling_dx + 1 : _openjpeg.image->x0 + (w - 1) * subsampling_dx + 1; 00120 _openjpeg.image->y1 = !_openjpeg.image->y0 ? (h - 1) * subsampling_dy + 1 : _openjpeg.image->y0 + (h - 1) * subsampling_dy + 1; 00121 00122 /* Decide if MCT should be used */ 00123 _openjpeg.parameters.tcp_mct = _openjpeg.image->numcomps == 3 ? 1 : 0; 00124 00125 if( _openjpeg.parameters.cp_cinema != OFF ) 00126 { 00127 cinemaSetupEncoder(); 00128 } 00129 00130 _outFile.open(filename, std::ios_base::out | std::ios_base::binary); 00131 if( !_outFile.good() ) 00132 { 00133 BOOST_THROW_EXCEPTION( exception::File() 00134 << exception::user("Unable to open output file.") 00135 << exception::filename(filename) ); 00136 } 00137 _components = nc; 00138 _width = w; 00139 _height = h; 00140 } 00141 00142 void J2KWriter::encode(const uint8_t *data, const std::size_t sprecision) 00143 { 00144 using namespace boost::gil; 00145 OPJ_CODEC_FORMAT fmt; 00146 switch( _openjpeg.parameters.cod_format ) 00147 { 00148 case J2K_CFMT: 00149 { 00150 fmt = CODEC_J2K; 00151 break; 00152 } 00153 default: 00154 { 00155 BOOST_THROW_EXCEPTION( exception::Value() 00156 << exception::user() + "Unrecognized output J2K format \"" + _openjpeg.parameters.cod_format + "\"." ); 00157 } 00158 } 00159 00160 // Get a J2K compressor handle 00161 opj_cinfo_t* cinfo = opj_create_compress(fmt); 00162 // Catch events using our callbacks and give a local context 00163 opj_set_event_mgr((opj_common_ptr)cinfo, &_openjpeg.event_mgr, stderr); 00164 // Setup the encoder parameters using the current image and user parameters 00165 opj_setup_encoder(cinfo, &_openjpeg.parameters, _openjpeg.image); 00166 // Open a byte stream for writing 00167 // Allocate memory for all tiles 00168 _cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0); 00169 00170 int j = _width * _height; 00171 // Check cinema mode off/on 00172 std::vector<int*> ch32(_components); 00173 switch( sprecision ) 00174 { 00175 case 8: 00176 { 00177 const uint8_t *sdata = (uint8_t*)data; 00178 for( std::size_t c = 0; c < _components; ++c ) 00179 { 00180 ch32[c] = &_openjpeg.image->comps[c].data[0]; 00181 } 00182 if( _cinemaMode != OFF ) 00183 { 00184 // DCI is always 12 bits encoded 00185 while ( j-- ) 00186 { 00187 for( std::size_t c = 0; c < _components; ++c) 00188 { 00189 gray8_pixel_t sp(*sdata++); 00190 gray12_pixel_t dp; 00191 color_convert(sp, dp); 00192 *ch32[c]++ = get_color(dp, gray_color_t()); 00193 } 00194 } 00195 } 00196 else 00197 { 00198 while ( j-- ) 00199 { 00200 for( std::size_t c = 0; c < _components; ++c) 00201 { 00202 *ch32[c]++ = *sdata++; 00203 } 00204 } 00205 } 00206 break; 00207 } 00208 case 12: 00209 { 00210 const uint16_t *sdata = (uint16_t*)data; 00211 for( std::size_t c = 0; c < _components; ++c) 00212 { 00213 ch32[c] = &_openjpeg.image->comps[c].data[0]; 00214 } 00215 while ( j-- ) 00216 { 00217 for( std::size_t c = 0; c < _components; ++c) 00218 { 00219 *(ch32[c]++) = *sdata++; 00220 } 00221 } 00222 break; 00223 } 00224 case 16: 00225 { 00226 const uint16_t *sdata = (uint16_t*)data; 00227 for( std::size_t c = 0; c < _components; ++c) 00228 { 00229 ch32[c] = &_openjpeg.image->comps[c].data[0]; 00230 } 00231 if( _cinemaMode != OFF ) 00232 { 00233 // DCI is always 12 bits encoded 00234 while ( j-- ) 00235 { 00236 for( std::size_t c = 0; c < _components; ++c) 00237 { 00238 gray16_pixel_t sp(*sdata++ & 0xFFFF); 00239 gray12_pixel_t dp; 00240 color_convert(sp, dp); 00241 *(ch32[c]++) = get_color(dp, gray_color_t()); 00242 } 00243 } 00244 } 00245 else 00246 { 00247 // Encode 12 bits 00248 while ( j-- ) 00249 { 00250 for( std::size_t c = 0; c < _components; ++c) 00251 { 00252 *(ch32[c]++) = *sdata++; 00253 } 00254 } 00255 } 00256 break; 00257 } 00258 case 32: 00259 { 00260 const uint32_t *sdata = (uint32_t*)data; 00261 for( std::size_t c = 0; c < _components; ++c) 00262 { 00263 ch32[c] = &_openjpeg.image->comps[c].data[0]; 00264 } 00265 if( _cinemaMode != OFF ) 00266 { 00267 // DCI is always 12 bits 00268 while( j-- ) 00269 { 00270 for( std::size_t c = 0; c < _components; ++c ) 00271 { 00272 gray32_pixel_t sp(*sdata++); 00273 gray12_pixel_t dp; 00274 color_convert(sp, dp); 00275 *(ch32[c]++) = get_color(dp, gray_color_t()); 00276 } 00277 } 00278 } 00279 else 00280 { 00281 while( j-- ) 00282 { 00283 for( std::size_t c = 0; c < _components; ++c ) 00284 { 00285 *(ch32[c]++) = *sdata++; 00286 } 00287 } 00288 } 00289 break; 00290 } 00291 } 00292 00293 // Encode the image 00294 if( ! opj_encode(cinfo, _cio, _openjpeg.image, NULL) ) 00295 { 00296 opj_cio_close(_cio); 00297 _cio = NULL; 00298 BOOST_THROW_EXCEPTION( exception::Failed() 00299 << exception::user( "Failed to encode image!" ) ); 00300 } 00301 00302 // free remaining compression structures 00303 opj_destroy_compress(cinfo); 00304 } 00305 00306 void J2KWriter::cinemaSetupParameters( ) 00307 { 00308 _openjpeg.parameters.tile_size_on = false; 00309 _openjpeg.parameters.cp_tdx=1; 00310 _openjpeg.parameters.cp_tdy=1; 00311 00312 // Tile part 00313 _openjpeg.parameters.tp_flag = 'C'; 00314 _openjpeg.parameters.tp_on = 1; 00315 00316 // Tile and Image shall be at (0,0) 00317 _openjpeg.parameters.cp_tx0 = 0; 00318 _openjpeg.parameters.cp_ty0 = 0; 00319 _openjpeg.parameters.image_offset_x0 = 0; 00320 _openjpeg.parameters.image_offset_y0 = 0; 00321 00322 // Codeblock size= 32*32 00323 _openjpeg.parameters.cblockw_init = 32; 00324 _openjpeg.parameters.cblockh_init = 32; 00325 _openjpeg.parameters.csty |= 0x01; 00326 00327 // The progression order shall be CPRL 00328 _openjpeg.parameters.prog_order = CPRL; 00329 00330 // No ROI 00331 _openjpeg.parameters.roi_compno = -1; 00332 _openjpeg.parameters.subsampling_dx = 1; 00333 _openjpeg.parameters.subsampling_dy = 1; 00334 00335 // 9-7 transform (instead of 5-3 reversible) 00336 _openjpeg.parameters.irreversible = 1; 00337 } 00338 00339 void J2KWriter::cinemaSetupEncoder() 00340 { 00341 switch( _openjpeg.parameters.cp_cinema ) 00342 { 00343 case CINEMA2K_24: 00344 case CINEMA2K_48: 00345 { 00346 if( _openjpeg.parameters.numresolution > 6 ) 00347 { 00348 _openjpeg.parameters.numresolution = 6; 00349 } 00350 if( _openjpeg.image->comps[0].w != 2048 && _openjpeg.image->comps[0].h != 1080 ) 00351 { 00352 _openjpeg.parameters.cp_rsiz = STD_RSIZ; 00353 BOOST_THROW_EXCEPTION( exception::Logic() 00354 << exception::user() + "Image dimensions " + _openjpeg.image->comps[0].w + " x " + _openjpeg.image->comps[0].h + " is not 2K compliant.\n" 00355 + "JPEG Digital Cinema Profile-3 (2K profile) compliance requires that at least one of coordinates match 2048 x 1080" ); 00356 } 00357 break; 00358 } 00359 case CINEMA4K_24: 00360 { 00361 if( _openjpeg.parameters.numresolution < 1 ) 00362 { 00363 _openjpeg.parameters.numresolution = 1; 00364 } 00365 else if( _openjpeg.parameters.numresolution > 7 ) 00366 { 00367 _openjpeg.parameters.numresolution = 7; 00368 } 00369 if( _openjpeg.image->comps[0].w != 4096 && _openjpeg.image->comps[0].h != 2160 ) 00370 { 00371 _openjpeg.parameters.cp_rsiz = STD_RSIZ; 00372 BOOST_THROW_EXCEPTION( exception::Logic() 00373 << exception::user() + "Image dimensions " + _openjpeg.image->comps[0].w + " x " + _openjpeg.image->comps[0].h + " is not 4K compliant.\n" 00374 + "JPEG Digital Cinema Profile-3 (4K profile) compliance requires that at least one of coordinates match 4096 x 2160" ); 00375 } 00376 _openjpeg.parameters.numpocs = 00377 initialize4Kpocs( _openjpeg.parameters.POC, 00378 _openjpeg.parameters.numresolution ); 00379 break; 00380 } 00381 default: 00382 break; 00383 } 00384 00385 switch( _openjpeg.parameters.cp_cinema ) 00386 { 00387 case CINEMA2K_24: 00388 case CINEMA4K_24: 00389 { 00390 for( int i = 0; i < _openjpeg.parameters.tcp_numlayers ; ++i ) 00391 { 00392 _openjpeg.parameters.tcp_rates[0]= 00393 ((float) (_openjpeg.image->numcomps * _openjpeg.image->comps[0].w * _openjpeg.image->comps[0].h * _openjpeg.image->comps[0].prec)) / 00394 (CINEMA_24_CS * 8 * _openjpeg.image->comps[0].dx * _openjpeg.image->comps[0].dy); 00395 } 00396 _openjpeg.parameters.max_comp_size = COMP_24_CS; 00397 break; 00398 } 00399 case CINEMA2K_48: 00400 { 00401 for( int i = 0 ; i < _openjpeg.parameters.tcp_numlayers ; ++i ) 00402 { 00403 _openjpeg.parameters.tcp_rates[0] = 00404 ((float) ( _openjpeg.image->numcomps * 00405 _openjpeg.image->comps[0].w * 00406 _openjpeg.image->comps[0].h * 00407 _openjpeg.image->comps[0].prec)) / 00408 (CINEMA_48_CS * 8 * _openjpeg.image->comps[0].dx * _openjpeg.image->comps[0].dy); 00409 } 00410 _openjpeg.parameters.max_comp_size = COMP_48_CS; 00411 break; 00412 } 00413 default: 00414 break; 00415 } 00416 _openjpeg.parameters.cp_disto_alloc = 1; 00417 } 00418 00419 int J2KWriter::initialize4Kpocs( opj_poc_t *POC, int numres ) 00420 { 00421 POC[0].tile = 1; 00422 POC[0].resno0 = 0; 00423 POC[0].compno0 = 0; 00424 POC[0].layno1 = 1; 00425 POC[0].resno1 = numres-1; 00426 POC[0].compno1 = 3; 00427 POC[0].prg1 = CPRL; 00428 POC[1].tile = 1; 00429 POC[1].resno0 = numres-1; 00430 POC[1].compno0 = 0; 00431 POC[1].layno1 = 1; 00432 POC[1].resno1 = numres; 00433 POC[1].compno1 = 3; 00434 POC[1].prg1 = CPRL; 00435 return 2; 00436 } 00437 00438 void J2KWriter::close() 00439 { 00440 if( _cio ) 00441 { 00442 // Output the buffer 00443 _outFile.write( (const char*)_cio->buffer, (std::size_t)cio_tell(_cio) ); 00444 // Close and free the byte stream 00445 opj_cio_close( _cio ); 00446 _cio = NULL; 00447 } 00448 00449 _outFile.close(); 00450 00451 if( _openjpeg.image ) 00452 { 00453 opj_image_destroy( _openjpeg.image ); 00454 _openjpeg.image = NULL; 00455 } 00456 } 00457 00458 } 00459 }