Thanks Dzonatas, code is always very much appreciated :)

Clearly, since OpenJPEG v2 is still alpha code, it is certainly too  
early to get that integrated in snowglobe but I created a JIRA to  
track that down the road:
        VWR-13699

It'll make easier also for folks on this list to grab your patch  
(attached to the JIRA) and add comments on their experimentation with  
v2.

Cheers,
- Merov

On May 25, 2009, at 8:47 AM, Dzonatas Sol wrote:

> Here is the replacement llimagej2coj.cpp I mentioned earlier. I only  
> used it to test the alpha version of OpenJPEG v2. This is only  
> posted for those that just want to mess around with OpenJPEG v2. Any  
> other OpenJPEG v2 comments should be directed to the openjpeg mail- 
> list.
>
>
> /**
> * @file llimagej2coj.cpp
> * @brief This is an implementation of JPEG2000 encode/decode using  
> OpenJPEG.
> *
> * $LicenseInfo:firstyear=2006&license=viewergpl$
> *
> * Copyright (c) 2006-2008, Linden Research, Inc.
> *
> * Second Life Viewer Source Code
> * The source code in this file ("Source Code") is provided by Linden  
> Lab
> * to you under the terms of the GNU General Public License, version  
> 2.0
> * ("GPL"), unless you have obtained a separate licensing agreement
> * ("Other License"), formally executed by you and Linden Lab.  Terms  
> of
> * the GPL can be found in doc/GPL-license.txt in this distribution, or
> * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
> *
> * There are special exceptions to the terms and conditions of the  
> GPL as
> * it is applied to this Source Code. View the full text of the  
> exception
> * in the file doc/FLOSS-exception.txt in this software distribution,  
> or
> * online at 
> http://secondlifegrid.net/programs/open_source/licensing/flossexception
> *
> * By copying, modifying or distributing this software, you acknowledge
> * that you have read and understood your obligations described above,
> * and agree to abide by those obligations.
> *
> * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
> * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
> * COMPLETENESS OR PERFORMANCE.
> * $/LicenseInfo$
> */
>
> /* Parts of this file is copyrighted by the OpenJPEG 2000 team.  
> Please is openjpeg.h include file for full copyright notice */
>
> #include "linden_common.h"
> #include "llimagej2coj.h"
>
> #define USE_OPJ_DEPRECATED
> #include "openjpeg.h"
>
> #include "lltimer.h"
> #include "llmemory.h"
>
> class OMVJ2KStream
>       {
>       U32           mStreamPosition ;
>       LLImageJ2C*   mImageJ2C ;
>
> public:
>       opj_stream_t* stream;
>
>       static OPJ_UINT32 _read (void * p_buffer, OPJ_UINT32 p_nb_bytes,  
> void * p_user_data)
>               {
>               return ((OMVJ2KStream*)p_user_data)->read( (U8*) p_buffer, 
> (U32)  
> p_nb_bytes) ;
>               }
>       static OPJ_UINT32 _write (void * p_buffer, OPJ_UINT32 p_nb_bytes,  
> void * p_user_data)
>               {
>               return ((OMVJ2KStream*)p_user_data)->write((U8*) p_buffer, 
> (U32)  
> p_nb_bytes) ;
>               }
>       static OPJ_SIZE_T _skip (OPJ_SIZE_T p_nb_bytes, void * p_user_data)
>               {
>               return ((OMVJ2KStream*)p_user_data)->skip((U32) p_nb_bytes) ;
>               }
>       static bool _seek (OPJ_SIZE_T p_nb_bytes, void * p_user_data)
>               {
>               return ((OMVJ2KStream*)p_user_data)->seek((U32) p_nb_bytes) ;
>               }
>       U32 read ( U8 * p_buffer, U32 p_nb_bytes)
>       {
>               if(!mImageJ2C->getData())
>                       return -1 ;
>               U32 bytes = p_nb_bytes ;
>               if( mStreamPosition + p_nb_bytes >= mImageJ2C->getDataSize() )
>                       {
>                       if( mImageJ2C->getDataSize() <= mStreamPosition )
>                               return -1 ;
>                       bytes = mImageJ2C->getDataSize() - mStreamPosition ;
>                       }
>               memcpy( p_buffer, mImageJ2C->getData() + mStreamPosition, bytes 
> ) ;
>               mStreamPosition += bytes ;
>               return bytes ;
>       }
>       U32 write( U8 * p_buffer, U32 p_nb_bytes)
>       {
>               S32 newpos = mStreamPosition + p_nb_bytes ;
>               if( !mImageJ2C->getData() )
>                       mImageJ2C->allocateData( (S32) p_nb_bytes ) ;
>               else if( newpos > mImageJ2C->getDataSize() )
>                       mImageJ2C->reallocateData( newpos ) ;
>               memcpy( mImageJ2C->getData() + mStreamPosition, p_buffer,  
> p_nb_bytes );
>               mStreamPosition = newpos ;
>               return p_nb_bytes ;
>       }
>       U32 skip(U32 p_nb_bytes)  // TODO: return value should be size_t,  
> yet opj defines it as U32 value for now
>       {
>               mStreamPosition += p_nb_bytes ;
>               return p_nb_bytes ;
>       }
>       bool seek(U32 p_nb_bytes)
>       {
>               mStreamPosition = p_nb_bytes ;
>               return true ;
>       }
>       OMVJ2KStream( bool writable, LLImageJ2C* llimagej2c )
>               {
>               mStreamPosition = 0 ;
>               mImageJ2C       = llimagej2c ;
>
>               stream = opj_stream_create(J2K_STREAM_CHUNK_SIZE, writable);
>
>               opj_stream_set_user_data(stream, this);
>               opj_stream_set_read_function(stream, _read);
>               opj_stream_set_write_function(stream, _write);
>               opj_stream_set_skip_function(stream, _skip);
>               opj_stream_set_seek_function(stream, _seek);
>               }
>       ~OMVJ2KStream()
>               {
>               opj_stream_destroy(stream);
>               }
>       };
>
> const char* fallbackEngineInfoLLImageJ2CImpl()
> {
>       static std::string version_string =
>               std::string("OpenJPEG: " OPENJPEG_VERSION ", Runtime: ")
>               + opj_version();
>       return version_string.c_str();
> }
>
> LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl()
> {
>       return new LLImageJ2COJ();
> }
>
> void fallbackDestroyLLImageJ2CImpl(LLImageJ2CImpl* impl)
> {
>       delete impl;
>       impl = NULL;
> }
>
> /**
> sample error callback expecting a LLFILE* client object
> */
> void error_callback(const char* msg, void*)
> {
> //    printf("[J2K] %s\n", msg) ;
>       lldebugs << "LLImageJ2CImpl error_callback: " << msg << llendl;
> }
> /**
> sample warning callback expecting a LLFILE* client object
> */
> void warning_callback(const char* msg, void*)
> {
> //    printf("[J2K] %s\n", msg) ;
>       lldebugs << "LLImageJ2CImpl warning_callback: " << msg << llendl;
> }
> /**
> sample debug callback expecting no client object
> */
> void info_callback(const char* msg, void*)
> {
> //    printf("[J2K] %s\n", msg) ;
>       lldebugs << "LLImageJ2CImpl info_callback: " << msg << llendl;
> }
>
>
> LLImageJ2COJ::LLImageJ2COJ() : LLImageJ2CImpl()
> {
> }
>
>
> LLImageJ2COJ::~LLImageJ2COJ()
> {
> }
>
>
>
> BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw  
> &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count)
> {
>       //
>       // FIXME: Get the comment field out of the texture
>       //
>
>       LLTimer decode_timer;
>
>       opj_dparameters_t parameters;   /* decompression parameters */
>       opj_image_t *image = NULL;
>
>       opj_codec_t* dinfo = NULL;      /* handle to a decompressor */
>
>       OMVJ2KStream j2k( true, &base ) ;
>
>       /* set decoding parameters to default values */
>       opj_set_default_decoder_parameters(&parameters);
>
>       parameters.cp_reduce = base.getRawDiscardLevel();
>
>
>       /* get a decoder handle */
>       dinfo = opj_create_decompress(CODEC_J2K);
>
>       /* catch events using our callbacks and give a local context */
>       opj_set_info_handler(dinfo, info_callback, NULL);
>       opj_set_warning_handler(dinfo, warning_callback, NULL);
>       opj_set_error_handler(dinfo, error_callback, NULL);
>
>       /* setup the decoder decoding parameters using user parameters */
>       opj_setup_decoder(dinfo, &parameters);
>
>       OPJ_INT32 x0, y0 ;
>       OPJ_UINT32 x1, y1, tiles_x, tiles_y;
>
>       bool success = opj_read_header( dinfo, &image, &x0, &y0, &x1, &y1,  
> &tiles_x, &tiles_y, j2k.stream) ;
>       if(!success)
>       {
>               fprintf(stderr, "ERROR -> decodeImpl: failed to decode image  
> header!\n");
>               if (image)
>               {
>                       opj_image_destroy(image);
>               }
>               opj_destroy_codec(dinfo);
>               base.mDecoding = FALSE;
>
>               return TRUE; // done
>       }
>
>       image = opj_decode(dinfo, j2k.stream);
>
>       if(!image)
>       {
>               opj_destroy_codec(dinfo);
>               raw_image.resize( x1/2, y1/2, 4); //TODO:DZ truncated data 
> stream,  
> we set half size to signal there is more to read, and fill white/ 
> alpha. this is temporary, for openjpeg v2 alpha version
>               U8 *rawp = raw_image.getData();
>               for (S32 y = ( (y1/2) - 1); y >= 0; y--)
>               {
>                       for (S32 x = 0; x < (x1/2); x++)
>                       {
>                               *(rawp++) = 255;
>                               *(rawp++) = 255;
>                               *(rawp++) = 255;
>                               *(rawp++) = 127;
>                       }
>               }
>               return TRUE;
>       }
>
>       opj_end_decompress(dinfo, j2k.stream);
> //    opj_destroy_codec(dinfo);
>
>
> #if 0
>       // sometimes we get bad data out of the cache - check to see if the  
> decode succeeded
>       int decompdifference = 0;
>       if (cinfo.numdecompos) // sanity
>       {
>               for (int comp = 0; comp < image->numcomps; comp++)
>               {       /* get maximum decomposition level difference, first 
> field is  
> from the COD header and the second
>                          is what is actually met in the codestream, NB: if 
> everything  
> was ok, this calculation will
>                          return what was set in the cp_reduce value! */
>                       decompdifference = std::max(decompdifference,  
> cinfo.numdecompos[comp] - image->comps[comp].resno_decoded);
>               }
>               if (decompdifference < 0) // sanity
>               {
>                       decompdifference = 0;
>               }
>       }
>
>       /* if OpenJPEG failed to decode all requested decomposition levels
>          the difference will be greater than this level */
>       if (decompdifference > base.getRawDiscardLevel())
>       {
>               llwarns << "not enough data for requested discard level, 
> setting  
> mDecoding to FALSE, difference: " << (decompdifference -  
> base.getRawDiscardLevel()) << llendl;
>               opj_image_destroy(image);
>
>               base.mDecoding = FALSE;
>               return TRUE;
>       }
>
>       if(image->numcomps <= first_channel)
>       {
>               // sanity
>               llwarns << "trying to decode more channels than are present in  
> image: numcomps: " << image->numcomps << " first_channel: " <<  
> first_channel << llendl;
>               opj_destroy_cstr_info(&cinfo);
>               opj_image_destroy(image);
>               return TRUE;
>       }
> #endif
>       // Copy image data into our raw image format (instead of the  
> separate channel format
>
>       S32 img_components = image->numcomps ;
>       S32 channels = img_components - first_channel;
>       if( channels > max_channel_count )
>               channels = max_channel_count;
>
>       // Component buffers are allocated in an image width by height  
> buffer.
>       // The image placed in that buffer is ceil(width/2^factor) by
>       // ceil(height/2^factor) and if the factor isn't zero it will be at  
> the
>       // top left of the buffer with black filled in the rest of the  
> pixels.
>       // It is integer math so the formula is written in ceildivpo2.
>       // (Assuming all the components have the same width, height and
>       // factor.)
>       S32 comp_width = image->comps[0].w;
>       S32 f=image->comps[0].factor;
>       S32 width = ceildivpow2(image->x1 - image->x0, f);
>       S32 height = ceildivpow2(image->y1 - image->y0, f);
>       raw_image.resize(width, height, channels);
>       U8 *rawp = raw_image.getData();
>
>
>       // first_channel is what channel to start copying from
>       // dest is what channel to copy to.  first_channel comes from the
>       // argument, dest always starts writing at channel zero.
>       for (S32 comp = first_channel, dest=0; comp < first_channel +  
> channels;
>               comp++, dest++)
>       {
>               if (image->comps[comp].data)
>               {
>                       S32 offset = dest;
>                       for (S32 y = (height - 1); y >= 0; y--)
>                       {
>                               for (S32 x = 0; x < width; x++)
>                               {
>                                       rawp[offset] = 
> image->comps[comp].data[y*comp_width + x];
>                                       offset += channels;
>                               }
>                       }
>               }
>               else // Some rare OpenJPEG versions have this bug.
>               {
>                       fprintf(stderr, "ERROR -> decodeImpl: failed to decode 
> image!  
> (NULL comp data - OpenJPEG bug)\n");
>                       opj_image_destroy(image);
>                       opj_destroy_codec(dinfo);
>
>                       return TRUE; // done
>               }
>       }
>
>       /* free opj data structures */
>       opj_image_destroy(image);
>       opj_destroy_codec(dinfo);
>
>       return TRUE; // done
> }
>
>
> BOOL LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw  
> &raw_image, const char* comment_text, F32 encode_time, BOOL  
> reversible)
> {
>       const S32 MAX_COMPS = 5;
>       opj_cparameters_t parameters;   /* compression parameters */
>
>
>       /* set encoding parameters to default values */
>       opj_set_default_encoder_parameters(&parameters);
>       parameters.cod_format = 0;
>       parameters.cp_disto_alloc = 1;
>
>       if (reversible)
>       {
>               parameters.tcp_numlayers = 1;
>               parameters.tcp_rates[0] = 0.0f;
>       }
>       else
>       {
>               parameters.tcp_numlayers = 5;
>               parameters.tcp_rates[0] = 1920.0f;
>               parameters.tcp_rates[1] = 480.0f;
>               parameters.tcp_rates[2] = 120.0f;
>               parameters.tcp_rates[3] = 30.0f;
>               parameters.tcp_rates[4] = 10.0f;
>               parameters.irreversible = 1;
>               if (raw_image.getComponents() == 3) // TODO: if 4 comps and  
> opacity plane is fully opaque, then set mct=1 and numcomps=3 (drop  
> opacity plane), otherwise leave as mct=0 to favor rgb/spatial  
> instead of YUV
>               {
>                       parameters.tcp_mct = 1;
>               }
>       }
>
>       if (!comment_text)
>       {
>               parameters.cp_comment = (char *) "";
>       }
>       else
>       {
>               // Awful hacky cast, too lazy to copy right now.
>               parameters.cp_comment = (char *) comment_text;
>       }
>
>       //
>       // Fill in the source image from our raw image
>       //
>       OPJ_COLOR_SPACE color_space = CLRSPC_SRGB;
>       opj_image_cmptparm_t cmptparm[MAX_COMPS];
>       opj_image_t * image = NULL;
>       S32 numcomps = raw_image.getComponents();
>       S32 width = raw_image.getWidth();
>       S32 height = raw_image.getHeight();
>
>       memset(&cmptparm[0], 0, MAX_COMPS * sizeof(opj_image_cmptparm_t));
>       for(S32 c = 0; c < numcomps; c++) {
>               cmptparm[c].prec = 8;
>               cmptparm[c].bpp = 8;
>               cmptparm[c].sgnd = 0;
>               cmptparm[c].dx = parameters.subsampling_dx;
>               cmptparm[c].dy = parameters.subsampling_dy;
>               cmptparm[c].w = width;
>               cmptparm[c].h = height;
>       }
>
>       /* create the image */
>       image = opj_image_create(numcomps, &cmptparm[0], color_space);
>
>       image->x1 = width;
>       image->y1 = height;
>
>       S32 i = 0;
>       const U8 *src_datap = raw_image.getData();
>       for (S32 y = height - 1; y >= 0; y--)
>       {
>               for (S32 x = 0; x < width; x++)
>               {
>                       const U8 *pixel = src_datap + (y*width + x) * numcomps;
>                       for (S32 c = 0; c < numcomps; c++)
>                       {
>                               image->comps[c].data[i] = *pixel;
>                               pixel++;
>                       }
>                       i++;
>               }
>       }
>
>
>
>       /* encode the destination image */
>       /* ---------------------------- */
>
>       OMVJ2KStream j2k( false, &base ) ;
>
>       /* get a J2K compressor handle */
>       opj_codec_t* cinfo = opj_create_compress(CODEC_J2K);
>
>       /* catch events using our callbacks and give a local context */
>       opj_set_info_handler(cinfo, info_callback, NULL);
>       opj_set_warning_handler(cinfo, warning_callback, NULL);
>       opj_set_error_handler(cinfo, error_callback, NULL);
>
>       /* setup the encoder parameters using the current image and using  
> user parameters */
>       opj_setup_encoder(cinfo, &parameters, image);
>
>
>       /* encode the image */
>       /*if (*indexfilename)                                   // If need to 
> extract codestream  
> information
>               bSuccess = opj_encode_with_info(cinfo, cio, image, &cstr_info);
>               else*/
>       bool bSuccess = opj_start_compress( cinfo, image, j2k.stream );
>       bSuccess = bSuccess && opj_encode( cinfo, j2k.stream );
>       bSuccess = bSuccess && opj_end_compress( cinfo, j2k.stream );
>
>       base.updateData(); // set width, height
>
>       /* free remaining compression structures */
>       opj_destroy_codec(cinfo);
>
>       /* free user parameters structure */
>       if(parameters.cp_matrice) free(parameters.cp_matrice);
>
>       /* free image data */
>       opj_image_destroy(image);
>       return TRUE;
> }
>
> BOOL LLImageJ2COJ::getMetadata(LLImageJ2C &base)
> {
>       //
>       // FIXME: We get metadata by decoding the ENTIRE image.
>       //
>
>       // Update the raw discard level
>       base.updateRawDiscardLevel();
>
>       opj_dparameters_t parameters;   /* decompression parameters */
>       opj_image_t *image = NULL;
>
>       opj_codec_t* dinfo = NULL;      /* handle to a decompressor */
>
>
>       /* set decoding parameters to default values */
>       opj_set_default_decoder_parameters(&parameters);
>
>       //parameters.cp_reduce = mRawDiscardLevel;
>
>       /* decode the code-stream */
>       /* ---------------------- */
>
>       /* JPEG-2000 codestream */
>       OMVJ2KStream j2k( true, &base ) ;
>
>       /* get a decoder handle */
>       dinfo = opj_create_decompress(CODEC_J2K);
>
>       /* catch events using our callbacks and give a local context */
>       // opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr);
>
>       /* setup the decoder decoding parameters using user parameters */
>       opj_setup_decoder(dinfo, &parameters);
>
>       OPJ_INT32 x0, y0 ;
>       OPJ_UINT32 x1, y1, tiles_x, tiles_y;
>
>       bool bResult = opj_read_header( dinfo, &image, &x0, &y0, &x1, &y1,  
> &tiles_x, &tiles_y, j2k.stream) ;
>
>       // TODO:DZ      try extract numcomps: if(! opj_read_tile_header( dinfo, 
>  
> &l_tile_index, &l_data_size, &l_current_tile_x0, &l_current_tile_y0,  
> &l_current_tile_x1, &l_current_tile_y1, &l_nb_comps, &l_go_on,  
> j2k.stream))
>
>       /* free remaining structures */
>       if(dinfo)
>       {
>               opj_destroy_codec(dinfo);
>       }
>       if(!bResult)
>       {
>               fprintf(stderr, "ERROR -> getMetadata: failed to decode 
> image!\n");
>               return FALSE;
>       }
>
>       base.setSize( x1, y1, 4);
>
>       return TRUE;
> }
> _______________________________________________
> Policies and (un)subscribe information available here:
> http://wiki.secondlife.com/wiki/SLDev
> Please read the policies before posting to keep unmoderated posting  
> privileges

_______________________________________________
Policies and (un)subscribe information available here:
http://wiki.secondlife.com/wiki/SLDev
Please read the policies before posting to keep unmoderated posting privileges

Reply via email to