TuttleOFX  1
J2KWriter.cpp
Go to the documentation of this file.
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 }