PageRenderTime 57ms CodeModel.GetById 17ms app.highlight 34ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/llimagej2coj/llimagej2coj.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 491 lines | 283 code | 93 blank | 115 comment | 29 complexity | 5eecdc091c0942d8208945ed392407ea MD5 | raw file
  1/** 
  2 * @file llimagej2coj.cpp
  3 * @brief This is an implementation of JPEG2000 encode/decode using OpenJPEG.
  4 *
  5 * $LicenseInfo:firstyear=2006&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#include "linden_common.h"
 28#include "llimagej2coj.h"
 29
 30// this is defined so that we get static linking.
 31#include "openjpeg.h"
 32
 33#include "lltimer.h"
 34//#include "llmemory.h"
 35
 36const char* fallbackEngineInfoLLImageJ2CImpl()
 37{
 38	static std::string version_string =
 39		std::string("OpenJPEG: " OPENJPEG_VERSION ", Runtime: ")
 40		+ opj_version();
 41	return version_string.c_str();
 42}
 43
 44LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl()
 45{
 46	return new LLImageJ2COJ();
 47}
 48
 49void fallbackDestroyLLImageJ2CImpl(LLImageJ2CImpl* impl)
 50{
 51	delete impl;
 52	impl = NULL;
 53}
 54
 55// Return string from message, eliminating final \n if present
 56static std::string chomp(const char* msg)
 57{
 58	// stomp trailing \n
 59	std::string message = msg;
 60	if (!message.empty())
 61	{
 62		size_t last = message.size() - 1;
 63		if (message[last] == '\n')
 64		{
 65			message.resize( last );
 66		}
 67	}
 68	return message;
 69}
 70
 71/**
 72sample error callback expecting a LLFILE* client object
 73*/
 74void error_callback(const char* msg, void*)
 75{
 76	lldebugs << "LLImageJ2COJ: " << chomp(msg) << llendl;
 77}
 78/**
 79sample warning callback expecting a LLFILE* client object
 80*/
 81void warning_callback(const char* msg, void*)
 82{
 83	lldebugs << "LLImageJ2COJ: " << chomp(msg) << llendl;
 84}
 85/**
 86sample debug callback expecting no client object
 87*/
 88void info_callback(const char* msg, void*)
 89{
 90	lldebugs << "LLImageJ2COJ: " << chomp(msg) << llendl;
 91}
 92
 93// Divide a by 2 to the power of b and round upwards
 94int ceildivpow2(int a, int b)
 95{
 96	return (a + (1 << b) - 1) >> b;
 97}
 98
 99
100LLImageJ2COJ::LLImageJ2COJ()
101	: LLImageJ2CImpl()
102{
103}
104
105
106LLImageJ2COJ::~LLImageJ2COJ()
107{
108}
109
110BOOL LLImageJ2COJ::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level, int* region)
111{
112	// No specific implementation for this method in the OpenJpeg case
113	return FALSE;
114}
115
116BOOL LLImageJ2COJ::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size, int precincts_size, int levels)
117{
118	// No specific implementation for this method in the OpenJpeg case
119	return FALSE;
120}
121
122BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count)
123{
124	//
125	// FIXME: Get the comment field out of the texture
126	//
127
128	LLTimer decode_timer;
129
130	opj_dparameters_t parameters;	/* decompression parameters */
131	opj_event_mgr_t event_mgr;		/* event manager */
132	opj_image_t *image = NULL;
133
134	opj_dinfo_t* dinfo = NULL;	/* handle to a decompressor */
135	opj_cio_t *cio = NULL;
136
137
138	/* configure the event callbacks (not required) */
139	memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
140	event_mgr.error_handler = error_callback;
141	event_mgr.warning_handler = warning_callback;
142	event_mgr.info_handler = info_callback;
143
144	/* set decoding parameters to default values */
145	opj_set_default_decoder_parameters(&parameters);
146
147	parameters.cp_reduce = base.getRawDiscardLevel();
148
149	/* decode the code-stream */
150	/* ---------------------- */
151
152	/* JPEG-2000 codestream */
153
154	/* get a decoder handle */
155	dinfo = opj_create_decompress(CODEC_J2K);
156
157	/* catch events using our callbacks and give a local context */
158	opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr);			
159
160	/* setup the decoder decoding parameters using user parameters */
161	opj_setup_decoder(dinfo, &parameters);
162
163	/* open a byte stream */
164	cio = opj_cio_open((opj_common_ptr)dinfo, base.getData(), base.getDataSize());
165
166	/* decode the stream and fill the image structure */
167	image = opj_decode(dinfo, cio);
168
169	/* close the byte stream */
170	opj_cio_close(cio);
171
172	/* free remaining structures */
173	if(dinfo)
174	{
175		opj_destroy_decompress(dinfo);
176	}
177
178	// The image decode failed if the return was NULL or the component
179	// count was zero.  The latter is just a sanity check before we
180	// dereference the array.
181	if(!image || !image->numcomps)
182	{
183		LL_DEBUGS("Texture") << "ERROR -> decodeImpl: failed to decode image!" << LL_ENDL;
184		if (image)
185		{
186			opj_image_destroy(image);
187		}
188
189		return TRUE; // done
190	}
191
192	// sometimes we get bad data out of the cache - check to see if the decode succeeded
193	for (S32 i = 0; i < image->numcomps; i++)
194	{
195		if (image->comps[i].factor != base.getRawDiscardLevel())
196		{
197			// if we didn't get the discard level we're expecting, fail
198			opj_image_destroy(image);
199			base.mDecoding = FALSE;
200			return TRUE;
201		}
202	}
203	
204	if(image->numcomps <= first_channel)
205	{
206		llwarns << "trying to decode more channels than are present in image: numcomps: " << image->numcomps << " first_channel: " << first_channel << llendl;
207		if (image)
208		{
209			opj_image_destroy(image);
210		}
211			
212		return TRUE;
213	}
214
215	// Copy image data into our raw image format (instead of the separate channel format
216
217	S32 img_components = image->numcomps;
218	S32 channels = img_components - first_channel;
219	if( channels > max_channel_count )
220		channels = max_channel_count;
221
222	// Component buffers are allocated in an image width by height buffer.
223	// The image placed in that buffer is ceil(width/2^factor) by
224	// ceil(height/2^factor) and if the factor isn't zero it will be at the
225	// top left of the buffer with black filled in the rest of the pixels.
226	// It is integer math so the formula is written in ceildivpo2.
227	// (Assuming all the components have the same width, height and
228	// factor.)
229	S32 comp_width = image->comps[0].w;
230	S32 f=image->comps[0].factor;
231	S32 width = ceildivpow2(image->x1 - image->x0, f);
232	S32 height = ceildivpow2(image->y1 - image->y0, f);
233	raw_image.resize(width, height, channels);
234	U8 *rawp = raw_image.getData();
235
236	// first_channel is what channel to start copying from
237	// dest is what channel to copy to.  first_channel comes from the
238	// argument, dest always starts writing at channel zero.
239	for (S32 comp = first_channel, dest=0; comp < first_channel + channels;
240		comp++, dest++)
241	{
242		if (image->comps[comp].data)
243		{
244			S32 offset = dest;
245			for (S32 y = (height - 1); y >= 0; y--)
246			{
247				for (S32 x = 0; x < width; x++)
248				{
249					rawp[offset] = image->comps[comp].data[y*comp_width + x];
250					offset += channels;
251				}
252			}
253		}
254		else // Some rare OpenJPEG versions have this bug.
255		{
256			LL_DEBUGS("Texture") << "ERROR -> decodeImpl: failed to decode image! (NULL comp data - OpenJPEG bug)" << LL_ENDL;
257			opj_image_destroy(image);
258
259			return TRUE; // done
260		}
261	}
262
263	/* free image data structure */
264	opj_image_destroy(image);
265
266	return TRUE; // done
267}
268
269
270BOOL LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time, BOOL reversible)
271{
272	const S32 MAX_COMPS = 5;
273	opj_cparameters_t parameters;	/* compression parameters */
274	opj_event_mgr_t event_mgr;		/* event manager */
275
276
277	/* 
278	configure the event callbacks (not required)
279	setting of each callback is optional 
280	*/
281	memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
282	event_mgr.error_handler = error_callback;
283	event_mgr.warning_handler = warning_callback;
284	event_mgr.info_handler = info_callback;
285
286	/* set encoding parameters to default values */
287	opj_set_default_encoder_parameters(&parameters);
288	parameters.cod_format = 0;
289	parameters.cp_disto_alloc = 1;
290
291	if (reversible)
292	{
293		parameters.tcp_numlayers = 1;
294		parameters.tcp_rates[0] = 0.0f;
295	}
296	else
297	{
298		parameters.tcp_numlayers = 5;
299                parameters.tcp_rates[0] = 1920.0f;
300                parameters.tcp_rates[1] = 480.0f;
301                parameters.tcp_rates[2] = 120.0f;
302                parameters.tcp_rates[3] = 30.0f;
303		parameters.tcp_rates[4] = 10.0f;
304		parameters.irreversible = 1;
305		if (raw_image.getComponents() >= 3)
306		{
307			parameters.tcp_mct = 1;
308		}
309	}
310
311	if (!comment_text)
312	{
313		parameters.cp_comment = (char *) "";
314	}
315	else
316	{
317		// Awful hacky cast, too lazy to copy right now.
318		parameters.cp_comment = (char *) comment_text;
319	}
320
321	//
322	// Fill in the source image from our raw image
323	//
324	OPJ_COLOR_SPACE color_space = CLRSPC_SRGB;
325	opj_image_cmptparm_t cmptparm[MAX_COMPS];
326	opj_image_t * image = NULL;
327	S32 numcomps = raw_image.getComponents();
328	S32 width = raw_image.getWidth();
329	S32 height = raw_image.getHeight();
330
331	memset(&cmptparm[0], 0, MAX_COMPS * sizeof(opj_image_cmptparm_t));
332	for(S32 c = 0; c < numcomps; c++) {
333		cmptparm[c].prec = 8;
334		cmptparm[c].bpp = 8;
335		cmptparm[c].sgnd = 0;
336		cmptparm[c].dx = parameters.subsampling_dx;
337		cmptparm[c].dy = parameters.subsampling_dy;
338		cmptparm[c].w = width;
339		cmptparm[c].h = height;
340	}
341
342	/* create the image */
343	image = opj_image_create(numcomps, &cmptparm[0], color_space);
344
345	image->x1 = width;
346	image->y1 = height;
347
348	S32 i = 0;
349	const U8 *src_datap = raw_image.getData();
350	for (S32 y = height - 1; y >= 0; y--)
351	{
352		for (S32 x = 0; x < width; x++)
353		{
354			const U8 *pixel = src_datap + (y*width + x) * numcomps;
355			for (S32 c = 0; c < numcomps; c++)
356			{
357				image->comps[c].data[i] = *pixel;
358				pixel++;
359			}
360			i++;
361		}
362	}
363
364
365
366	/* encode the destination image */
367	/* ---------------------------- */
368
369	int codestream_length;
370	opj_cio_t *cio = NULL;
371
372	/* get a J2K compressor handle */
373	opj_cinfo_t* cinfo = opj_create_compress(CODEC_J2K);
374
375	/* catch events using our callbacks and give a local context */
376	opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr);			
377
378	/* setup the encoder parameters using the current image and using user parameters */
379	opj_setup_encoder(cinfo, &parameters, image);
380
381	/* open a byte stream for writing */
382	/* allocate memory for all tiles */
383	cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0);
384
385	/* encode the image */
386	bool bSuccess = opj_encode(cinfo, cio, image, NULL);
387	if (!bSuccess)
388	{
389		opj_cio_close(cio);
390		LL_DEBUGS("Texture") << "Failed to encode image." << LL_ENDL;
391		return FALSE;
392	}
393	codestream_length = cio_tell(cio);
394
395	base.copyData(cio->buffer, codestream_length);
396	base.updateData(); // set width, height
397
398	/* close and free the byte stream */
399	opj_cio_close(cio);
400
401	/* free remaining compression structures */
402	opj_destroy_compress(cinfo);
403
404
405	/* free user parameters structure */
406	if(parameters.cp_matrice) free(parameters.cp_matrice);
407
408	/* free image data */
409	opj_image_destroy(image);
410	return TRUE;
411}
412
413BOOL LLImageJ2COJ::getMetadata(LLImageJ2C &base)
414{
415	//
416	// FIXME: We get metadata by decoding the ENTIRE image.
417	//
418
419	// Update the raw discard level
420	base.updateRawDiscardLevel();
421
422	opj_dparameters_t parameters;	/* decompression parameters */
423	opj_event_mgr_t event_mgr;		/* event manager */
424	opj_image_t *image = NULL;
425
426	opj_dinfo_t* dinfo = NULL;	/* handle to a decompressor */
427	opj_cio_t *cio = NULL;
428
429
430	/* configure the event callbacks (not required) */
431	memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
432	event_mgr.error_handler = error_callback;
433	event_mgr.warning_handler = warning_callback;
434	event_mgr.info_handler = info_callback;
435
436	/* set decoding parameters to default values */
437	opj_set_default_decoder_parameters(&parameters);
438
439	// Only decode what's required to get the size data.
440	parameters.cp_limit_decoding=LIMIT_TO_MAIN_HEADER;
441
442	//parameters.cp_reduce = mRawDiscardLevel;
443
444	/* decode the code-stream */
445	/* ---------------------- */
446
447	/* JPEG-2000 codestream */
448
449	/* get a decoder handle */
450	dinfo = opj_create_decompress(CODEC_J2K);
451
452	/* catch events using our callbacks and give a local context */
453	opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr);			
454
455	/* setup the decoder decoding parameters using user parameters */
456	opj_setup_decoder(dinfo, &parameters);
457
458	/* open a byte stream */
459	cio = opj_cio_open((opj_common_ptr)dinfo, base.getData(), base.getDataSize());
460
461	/* decode the stream and fill the image structure */
462	image = opj_decode(dinfo, cio);
463
464	/* close the byte stream */
465	opj_cio_close(cio);
466
467	/* free remaining structures */
468	if(dinfo)
469	{
470		opj_destroy_decompress(dinfo);
471	}
472
473	if(!image)
474	{
475		llwarns << "ERROR -> getMetadata: failed to decode image!" << llendl;
476		return FALSE;
477	}
478
479	// Copy image data into our raw image format (instead of the separate channel format
480	S32 width = 0;
481	S32 height = 0;
482
483	S32 img_components = image->numcomps;
484	width = image->x1 - image->x0;
485	height = image->y1 - image->y0;
486	base.setSize(width, height, img_components);
487
488	/* free image data structure */
489	opj_image_destroy(image);
490	return TRUE;
491}