1 /*
2 *			GPAC - Multimedia Framework C SDK
3 *
4  *			Authors: Jean Le Feuvre
5  *			Copyright (c) Telecom ParisTech 2000-2019
6 *					All rights reserved
7 *
8 *  This file is part of GPAC / openjpeg2k decoder filter
9 *
10 *  GPAC is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU Lesser General Public License as published by
12 *  the Free Software Foundation; either version 2, or (at your option)
13 *  any later version.
14 *
15 *  GPAC is distributed in the hope that it will be useful,
16 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 *  GNU Lesser General Public License for more details.
19 *
20 *  You should have received a copy of the GNU Lesser General Public
21 *  License along with this library; see the file COPYING.  If not, write to
22 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25 
26 #include <gpac/filters.h>
27 
28 #ifdef GPAC_HAS_JP2
29 
30 //we MUST set OPJ_STATIC before including openjpeg.h
31 #if !defined(__GNUC__) && (defined(_WIN32_WCE) || defined (WIN32))
32 #  define OPJ_STATIC
33 #endif
34 
35 #include <gpac/constants.h>
36 #include <gpac/isomedia.h>
37 
38 #include <openjpeg.h>
39 
40 #ifdef OPJ_PROFILE_NONE
41 #define OPENJP2	1
42 
43 # if !defined(__GNUC__) && (defined(_WIN32_WCE) || defined (WIN32))
44 #  if defined(_DEBUG)
45 #   pragma comment(lib, "libopenjp2d")
46 #  else
47 #   pragma comment(lib, "libopenjp2")
48 #  endif
49 # endif
50 
51 #else
52 
53 #define OPENJP2	0
54 
55 # if !defined(__GNUC__) && (defined(_WIN32_WCE) || defined (WIN32))
56 #  if defined(_DEBUG)
57 #   pragma comment(lib, "LibOpenJPEGd")
58 #  else
59 #   pragma comment(lib, "LibOpenJPEG")
60 #  endif
61 # endif
62 
63 #endif
64 
65 typedef struct
66 {
67 	GF_FilterPid *ipid, *opid;
68 	u32 cfg_crc;
69 	/*no support for scalability with JPEG (progressive JPEG to test)*/
70 	u32 bpp, nb_comp, width, height, out_size, pixel_format, dsi_size;
71 	char *dsi;
72 } GF_J2KCtx;
73 
74 
j2kdec_configure_pid(GF_Filter * filter,GF_FilterPid * pid,Bool is_remove)75 static GF_Err j2kdec_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
76 {
77 	const GF_PropertyValue *p;
78 	GF_J2KCtx *ctx = gf_filter_get_udta(filter);
79 
80 	if (is_remove) {
81 		if (ctx->opid) gf_filter_pid_remove(ctx->opid);
82 		ctx->opid = NULL;
83 		ctx->ipid = NULL;
84 		return GF_OK;
85 	}
86 	if (! gf_filter_pid_check_caps(pid))
87 		return GF_NOT_SUPPORTED;
88 
89 	p = gf_filter_pid_get_property(pid, GF_PROP_PID_DECODER_CONFIG);
90 	if (p && p->value.data.ptr && p->value.data.size) {
91 		GF_BitStream *bs;
92 		u32 d4cc;
93 		Bool dsi_ok=GF_FALSE;
94 		u32 ex_crc = gf_crc_32(p->value.data.ptr, p->value.data.size);
95 		if (ctx->cfg_crc == ex_crc) {
96 			return GF_OK;
97 		}
98 		ctx->cfg_crc = ex_crc;
99 
100 		//old gpac version used to store only the payload of ihdr in the dsi, but the new version exposes the entire jp2h (without box size and type) as dsi
101 		//so handle both on read
102 		d4cc = 0;
103 		if (p->value.data.size>8)
104 			d4cc = GF_4CC(p->value.data.ptr[4], p->value.data.ptr[5], p->value.data.ptr[6], p->value.data.ptr[7]);
105 
106 		bs = gf_bs_new(p->value.data.ptr, p->value.data.size, GF_BITSTREAM_READ);
107 		if ((d4cc==GF_4CC('i','h','d','r')) || (d4cc==GF_4CC('c','o','l','r'))) {
108 			while (gf_bs_available(bs)) {
109 				u32 bsize = gf_bs_read_u32(bs);
110 				u32 btype = gf_bs_read_u32(bs);
111 				if (btype==GF_4CC('i','h','d','r')) {
112 					dsi_ok=GF_TRUE;
113 					break;
114 				}
115 				gf_bs_skip_bytes(bs, bsize-8);
116 			}
117 		} else {
118 			dsi_ok=GF_TRUE;
119 		}
120 		if (dsi_ok) {
121 			ctx->height = gf_bs_read_u32(bs);
122 			ctx->width = gf_bs_read_u32(bs);
123 			ctx->nb_comp = gf_bs_read_u16(bs);
124 			ctx->bpp = 1 + gf_bs_read_u8(bs);
125 		}
126 		gf_bs_del(bs);
127 
128 		if (!dsi_ok) {
129 			GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[OpenJPEG] Broken decoder config in j2k stream, cannot decode\n"));
130 			return GF_NON_COMPLIANT_BITSTREAM;
131 		}
132 
133 		ctx->out_size = ctx->width * ctx->height * ctx->nb_comp /* * ctx->bpp / 8 */;
134 
135 		switch (ctx->nb_comp) {
136 		case 1:
137 			ctx->pixel_format = GF_PIXEL_GREYSCALE;
138 			break;
139 		case 2:
140 			ctx->pixel_format = GF_PIXEL_ALPHAGREY;
141 			break;
142 		case 3:
143 			ctx->pixel_format = GF_PIXEL_RGB;
144 			break;
145 		case 4:
146 			ctx->pixel_format = GF_PIXEL_RGBA;
147 			break;
148 		default:
149 			return GF_NOT_SUPPORTED;
150 		}
151 	} else {
152 		p = gf_filter_pid_get_property(pid, GF_PROP_PID_WIDTH);
153 		if (p) ctx->width = p->value.uint;
154 		p = gf_filter_pid_get_property(pid, GF_PROP_PID_HEIGHT);
155 		if (p) ctx->height = p->value.uint;
156 		ctx->nb_comp = 0;
157 		ctx->pixel_format = 0;
158 	}
159 
160 	ctx->ipid = pid;
161 	if (!ctx->opid) {
162 		ctx->opid = gf_filter_pid_new(filter);
163 		gf_filter_pid_set_framing_mode(ctx->ipid, GF_TRUE);
164 	}
165 	//copy properties at init or reconfig
166 	gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
167 	gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, &PROP_UINT(GF_CODECID_RAW) );
168 
169 	gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_WIDTH, &PROP_UINT(ctx->width) );
170 	gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_HEIGHT, &PROP_UINT(ctx->height) );
171 	if (ctx->pixel_format) {
172 		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STRIDE, &PROP_UINT( (ctx->pixel_format == GF_PIXEL_YUV) ? ctx->width : ctx->width * ctx->nb_comp) );
173 		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PIXFMT, &PROP_UINT(ctx->pixel_format) );
174 	}
175 	return GF_OK;
176 }
177 
178 /**
179 sample error callback expecting a FILE* client object
180 */
error_callback(const char * msg,void * client_data)181 void error_callback(const char *msg, void *client_data)
182 {
183 	if (msg) {
184 		GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[OpenJPEG] Error %s", msg));
185 	} else {
186 		GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[OpenJPEG] coverage test\n"));
187 	}
188 }
189 /**
190 sample warning callback expecting a FILE* client object
191 */
warning_callback(const char * msg,void * client_data)192 void warning_callback(const char *msg, void *client_data)
193 {
194 	if (msg) {
195 		GF_LOG(GF_LOG_WARNING, GF_LOG_CODEC, ("[OpenJPEG] Warning %s", msg));
196 	} else {
197 		GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[OpenJPEG] coverage test\n"));
198 	}
199 }
200 /**
201 sample debug callback expecting no client object
202 */
info_callback(const char * msg,void * client_data)203 void info_callback(const char *msg, void *client_data)
204 {
205 	if (msg) {
206 		GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("[OpenJPEG] Info %s", msg));
207 	} else {
208 		GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[OpenJPEG] coverage test\n"));
209 	}
210 }
211 
212 /*
213 * Divide an integer by a power of 2 and round upwards.
214 *
215 * a divided by 2^b
216 */
int_ceildivpow2(int a,int b)217 static int int_ceildivpow2(int a, int b) {
218 	return (a + (1 << b) - 1) >> b;
219 }
220 
221 #if OPENJP2
222 typedef struct
223 {
224 	char *data;
225 	u32 len, pos;
226 } OJP2Frame;
227 
j2kdec_stream_read(void * out_buffer,OPJ_SIZE_T nb_bytes,void * user_data)228 static OPJ_SIZE_T j2kdec_stream_read(void *out_buffer, OPJ_SIZE_T nb_bytes, void *user_data)
229 {
230     OJP2Frame *frame = user_data;
231     u32 remain;
232     if (frame->pos == frame->len) return (OPJ_SIZE_T)-1;
233     remain = frame->len - frame->pos;
234     if (nb_bytes > remain) nb_bytes = remain;
235     memcpy(out_buffer, frame->data + frame->pos, nb_bytes);
236     frame->pos += (u32) nb_bytes;
237     return nb_bytes;
238 }
239 
j2kdec_stream_skip(OPJ_OFF_T nb_bytes,void * user_data)240 static OPJ_OFF_T j2kdec_stream_skip(OPJ_OFF_T nb_bytes, void *user_data)
241 {
242     OJP2Frame *frame = user_data;
243     if (!user_data) return 0;
244 
245     if (nb_bytes < 0) {
246         if (frame->pos == 0) return (OPJ_SIZE_T)-1;
247         if (nb_bytes + (s32) frame->pos < 0) {
248             nb_bytes = -frame->pos;
249         }
250     } else {
251         u32 remain;
252         if (frame->pos == frame->len) {
253             return (OPJ_SIZE_T)-1;
254         }
255         remain = frame->len - frame->pos;
256         if (nb_bytes > remain) {
257             nb_bytes = remain;
258         }
259     }
260     frame->pos += (u32) nb_bytes;
261     return nb_bytes;
262 }
263 
j2kdec_stream_seek(OPJ_OFF_T nb_bytes,void * user_data)264 static OPJ_BOOL j2kdec_stream_seek(OPJ_OFF_T nb_bytes, void *user_data)
265 {
266     OJP2Frame *frame = user_data;
267     if (nb_bytes < 0 || nb_bytes > frame->pos) return OPJ_FALSE;
268     frame->pos = (u32)nb_bytes;
269     return OPJ_TRUE;
270 }
271 #endif
272 
273 
j2kdec_process(GF_Filter * filter)274 static GF_Err j2kdec_process(GF_Filter *filter)
275 {
276 	u32 i, w, wr, h, hr, wh, size, pf;
277 	u8 *data, *buffer;
278 	opj_dparameters_t parameters;	/* decompression parameters */
279 #if OPENJP2
280 	s32 res;
281 	opj_codec_t *codec = NULL;
282 	opj_stream_t * stream = NULL;
283 	OJP2Frame ojp2frame;
284 #else
285 	opj_event_mgr_t event_mgr;		/* event manager */
286 	opj_dinfo_t* dinfo = NULL;	/* handle to a decompressor */
287 	opj_cio_t *cio = NULL;
288 	opj_codestream_info_t cinfo;
289 #endif
290 	opj_image_t *image = NULL;
291 	u32 start_offset=0;
292 	GF_J2KCtx *ctx = gf_filter_get_udta(filter);
293 	GF_FilterPacket *pck, *pck_dst;
294 	Bool changed = GF_FALSE;
295 	pck = gf_filter_pid_get_packet(ctx->ipid);
296 	if (!pck) {
297 		if (gf_filter_pid_is_eos(ctx->ipid))
298 			gf_filter_pid_set_eos(ctx->opid);
299 		return GF_OK;
300 	}
301 	data = (char *) gf_filter_pck_get_data(pck, &size);
302 	if (!data) {
303 		gf_filter_pid_drop_packet(ctx->ipid);
304 		return GF_IO_ERR;
305 	}
306 
307 	if (size>=8) {
308 		if ((data[4]=='j') && (data[5]=='p') && (data[6]=='2') && (data[7]=='c'))
309 			start_offset = 8;
310 	}
311 
312 	/* set decoding parameters to default values */
313 	opj_set_default_decoder_parameters(&parameters);
314 
315 #if OPENJP2
316 	codec = opj_create_decompress(OPJ_CODEC_J2K);
317 	if (codec) res = 1;
318 	else res=0;
319 
320 	if (res) res = opj_set_info_handler(codec, info_callback, NULL);
321 	if (res) res = opj_set_warning_handler(codec, warning_callback, NULL);
322 	if (res) res = opj_set_error_handler(codec, error_callback, NULL);
323 
324 	if (res) res = opj_setup_decoder(codec, &parameters);
325 
326 	stream = opj_stream_default_create(OPJ_STREAM_READ);
327     opj_stream_set_read_function(stream, j2kdec_stream_read);
328     opj_stream_set_skip_function(stream, j2kdec_stream_skip);
329     opj_stream_set_seek_function(stream, j2kdec_stream_seek);
330     ojp2frame.data = data+start_offset;
331     ojp2frame.len = size-start_offset;
332     ojp2frame.pos = 0;
333     opj_stream_set_user_data(stream, &ojp2frame, NULL);
334     opj_stream_set_user_data_length(stream, ojp2frame.len);
335 
336 	if (res) res = opj_read_header(stream, codec, &image);
337 	if (res) res = opj_set_decode_area(codec, image, 0, 0, image->x1, image->y1);
338 	if (res) {
339 		res = opj_decode(codec, stream, image);
340 		if (!res) {
341 			GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[OpenJPEG] Decoding failed\n"));
342 			opj_image_destroy(image);
343 			image = NULL;
344 		}
345 	}
346 
347 #else
348 
349 	/* get a decoder handle for raw J2K frames*/
350 	dinfo = opj_create_decompress(CODEC_J2K);
351 
352 	/* configure the event callbacks (not required) */
353 	memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
354 	event_mgr.error_handler = error_callback;
355 	event_mgr.warning_handler = warning_callback;
356 	event_mgr.info_handler = info_callback;
357 
358 	/* catch events using our callbacks and give a local context */
359 	opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr);
360 
361 	/* setup the decoder decoding parameters using the current image and user parameters */
362 	opj_setup_decoder(dinfo, &parameters);
363 
364 	cio = opj_cio_open((opj_common_ptr)dinfo, data+start_offset, size-start_offset);
365 	/* decode the stream and fill the image structure */
366 	image = opj_decode_with_info(dinfo, cio, &cinfo);
367 #endif
368 
369 	if (!image) {
370 #if OPENJP2
371 		opj_stream_destroy(stream);
372 		opj_destroy_codec(codec);
373 #else
374 		opj_destroy_decompress(dinfo);
375 		opj_cio_close(cio);
376 #endif
377 		gf_filter_pid_drop_packet(ctx->ipid);
378 		return GF_IO_ERR;
379 	}
380 
381 #if OPENJP2
382 	ctx->nb_comp = image->numcomps;
383 	w = image->x1;
384 	h = image->y1;
385 #else
386 	ctx->nb_comp = cinfo.numcomps;
387 	w = cinfo.image_w;
388 	h = cinfo.image_h;
389 #endif
390 	ctx->bpp = ctx->nb_comp * 8;
391 	ctx->out_size = ctx->width * ctx->height * ctx->nb_comp /* * ctx->bpp / 8 */;
392 
393 	switch (ctx->nb_comp) {
394 	case 1:
395 		pf = GF_PIXEL_GREYSCALE;
396 		break;
397 	case 2:
398 		pf = GF_PIXEL_ALPHAGREY;
399 		break;
400 	case 3:
401 		pf = GF_PIXEL_RGB;
402 		break;
403 	case 4:
404 		pf = GF_PIXEL_RGBA;
405 		break;
406 	default:
407 		gf_filter_pid_drop_packet(ctx->ipid);
408 		return GF_NOT_SUPPORTED;
409 	}
410 	if ((image->comps[0].w==2*image->comps[1].w)
411 		&& (image->comps[1].w==image->comps[2].w)
412 		&& (image->comps[0].h==2*image->comps[1].h)
413 		&& (image->comps[1].h==image->comps[2].h)) {
414 		pf = GF_PIXEL_YUV;
415 		ctx->out_size = 3*ctx->width*ctx->height/2;
416 		changed = GF_TRUE;
417 	}
418 	if (ctx->pixel_format!=pf) {
419 		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PIXFMT, &PROP_UINT(pf) );
420 		ctx->pixel_format = pf;
421 		changed = GF_TRUE;
422 	}
423 	if (ctx->width!=w) {
424 		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_WIDTH, &PROP_UINT(w) );
425 		ctx->width = w;
426 		changed = GF_TRUE;
427 	}
428 	if (ctx->height!=h) {
429 		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_HEIGHT, &PROP_UINT(h) );
430 		ctx->height = h;
431 		changed = GF_TRUE;
432 	}
433 	if (changed) {
434 		gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STRIDE, &PROP_UINT( (ctx->pixel_format == GF_PIXEL_YUV) ? ctx->width : ctx->width * ctx->nb_comp) );
435 	}
436 
437 #if OPENJP2
438 	opj_end_decompress(codec, stream);
439 	opj_stream_destroy(stream);
440 	stream = NULL;
441 	opj_destroy_codec(codec);
442 	codec = NULL;
443 #else
444 	/* close the byte stream */
445 	opj_cio_close(cio);
446 	cio = NULL;
447 
448 	/* gf_free( remaining structures */
449 	if(dinfo) {
450 		opj_destroy_decompress(dinfo);
451 		dinfo = NULL;
452 	}
453 #endif
454 
455 	pck_dst = gf_filter_pck_new_alloc(ctx->opid, ctx->out_size, &buffer);
456 
457 	w = image->comps[0].w;
458 	wr = int_ceildivpow2(image->comps[0].w, image->comps[0].factor);
459 	h = image->comps[0].h;
460 	hr = int_ceildivpow2(image->comps[0].h, image->comps[0].factor);
461 	wh = wr*hr;
462 
463 	if (ctx->nb_comp==1) {
464 		if ((w==wr) && (h==hr)) {
465 			for (i=0; i<wh; i++) {
466 				buffer[i] = image->comps[0].data[i];
467 			}
468 		} else {
469 			for (i=0; i<wh; i++) {
470 				buffer[i] = image->comps[0].data[w * hr - ((i) / (wr) + 1) * w + (i) % (wr)];
471 			}
472 		}
473 	}
474 	else if (ctx->nb_comp==3) {
475 
476 		if ((image->comps[0].w==2*image->comps[1].w) && (image->comps[1].w==image->comps[2].w)
477 		        && (image->comps[0].h==2*image->comps[1].h) && (image->comps[1].h==image->comps[2].h)) {
478 
479 			if ((w==wr) && (h==hr)) {
480 				for (i=0; i<wh; i++) {
481 					*buffer = image->comps[0].data[i];
482 					buffer++;
483 				}
484 //				w = image->comps[1].w;
485 				wr = int_ceildivpow2(image->comps[1].w, image->comps[1].factor);
486 //				h = image->comps[1].h;
487 				hr = int_ceildivpow2(image->comps[1].h, image->comps[1].factor);
488 				wh = wr*hr;
489 				for (i=0; i<wh; i++) {
490 					*buffer = image->comps[1].data[i];
491 					buffer++;
492 				}
493 				for (i=0; i<wh; i++) {
494 					*buffer = image->comps[2].data[i];
495 					buffer++;
496 				}
497 			} else {
498 				for (i=0; i<wh; i++) {
499 					*buffer = image->comps[0].data[w * hr - ((i) / (wr) + 1) * w + (i) % (wr)];
500 				}
501 				w = image->comps[1].w;
502 				wr = int_ceildivpow2(image->comps[1].w, image->comps[1].factor);
503 //				h = image->comps[1].h;
504 				hr = int_ceildivpow2(image->comps[1].h, image->comps[1].factor);
505 				wh = wr*hr;
506 				for (i=0; i<wh; i++) {
507 					*buffer = image->comps[1].data[w * hr - ((i) / (wr) + 1) * w + (i) % (wr)];
508 				}
509 				for (i=0; i<wh; i++) {
510 					*buffer = image->comps[2].data[w * hr - ((i) / (wr) + 1) * w + (i) % (wr)];
511 				}
512 			}
513 
514 
515 		} else if ((image->comps[0].w==image->comps[1].w) && (image->comps[1].w==image->comps[2].w)
516 		           && (image->comps[0].h==image->comps[1].h) && (image->comps[1].h==image->comps[2].h)) {
517 
518 			if ((w==wr) && (h==hr)) {
519 				for (i=0; i<wh; i++) {
520 					u32 idx = 3*i;
521 					buffer[idx] = image->comps[0].data[i];
522 					buffer[idx+1] = image->comps[1].data[i];
523 					buffer[idx+2] = image->comps[2].data[i];
524 				}
525 			} else {
526 				for (i=0; i<wh; i++) {
527 					u32 idx = 3*i;
528 					buffer[idx] = image->comps[0].data[w * hr - ((i) / (wr) + 1) * w + (i) % (wr)];
529 					buffer[idx+1] = image->comps[1].data[w * hr - ((i) / (wr) + 1) * w + (i) % (wr)];
530 					buffer[idx+2] = image->comps[2].data[w * hr - ((i) / (wr) + 1) * w + (i) % (wr)];
531 				}
532 			}
533 		}
534 	}
535 	else if (ctx->nb_comp==4) {
536 		if ((image->comps[0].w==image->comps[1].w) && (image->comps[1].w==image->comps[2].w) && (image->comps[2].w==image->comps[3].w)
537 		        && (image->comps[0].h==image->comps[1].h) && (image->comps[1].h==image->comps[2].h) && (image->comps[2].h==image->comps[3].h)) {
538 
539 			if ((w==wr) && (h==hr)) {
540 				for (i=0; i<wh; i++) {
541 					u32 idx = 4*i;
542 					buffer[idx] = image->comps[0].data[i];
543 					buffer[idx+1] = image->comps[1].data[i];
544 					buffer[idx+2] = image->comps[2].data[i];
545 					buffer[idx+3] = image->comps[3].data[i];
546 				}
547 			} else {
548 				for (i=0; i<wh; i++) {
549 					u32 idx = 4*i;
550 					buffer[idx] = image->comps[0].data[w * hr - ((i) / (wr) + 1) * w + (i) % (wr)];
551 					buffer[idx+1] = image->comps[1].data[w * hr - ((i) / (wr) + 1) * w + (i) % (wr)];
552 					buffer[idx+2] = image->comps[2].data[w * hr - ((i) / (wr) + 1) * w + (i) % (wr)];
553 					buffer[idx+3] = image->comps[3].data[w * hr - ((i) / (wr) + 1) * w + (i) % (wr)];
554 				}
555 			}
556 		}
557 	}
558 
559 	opj_image_destroy(image);
560 	image = NULL;
561 
562 	if (gf_filter_pck_get_seek_flag(pck)) {
563 		gf_filter_pck_discard(pck_dst);
564 	} else {
565 		gf_filter_pck_merge_properties(pck, pck_dst);
566 		gf_filter_pck_send(pck_dst);
567 	}
568 	gf_filter_pid_drop_packet(ctx->ipid);
569 	return GF_OK;
570 }
571 
j2kdec_initialize(GF_Filter * filter)572 static GF_Err j2kdec_initialize(GF_Filter *filter)
573 {
574 #ifdef GPAC_ENABLE_COVERAGE
575 	if (gf_sys_is_cov_mode()) {
576 		error_callback(NULL, NULL);
577 		warning_callback(NULL, NULL);
578 		info_callback(NULL, NULL);
579 #if OPENJP2
580 		j2kdec_stream_skip(0, NULL);
581 #endif
582 	}
583 #endif
584 	return GF_OK;
585 }
586 
587 static const GF_FilterCapability J2KCaps[] =
588 {
589 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
590 	CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_J2K),
591 	CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
592 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
593 	CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_RAW),
594 };
595 
596 GF_FilterRegister J2KRegister = {
597 	.name = "j2kdec",
598 #ifdef OPENJPEG_VERSION
599 	.version = ""OPENJPEG_VERSION,
600 #elif OPENJP2
601 	.version = "2.x",
602 #else
603 	.version = "1.x",
604 #endif
605 	GF_FS_SET_DESCRIPTION("OpenJPEG2000 decoder")
606 	GF_FS_SET_HELP("This filter decodes JPEG2000 streams through OpenJPEG2000 library.")
607 	.private_size = sizeof(GF_J2KCtx),
608 	.priority = 1,
609 	SETCAPS(J2KCaps),
610 	.initialize = j2kdec_initialize,
611 	.configure_pid = j2kdec_configure_pid,
612 	.process = j2kdec_process,
613 };
614 
615 #endif
616 
j2kdec_register(GF_FilterSession * session)617 const GF_FilterRegister *j2kdec_register(GF_FilterSession *session)
618 {
619 #ifdef GPAC_HAS_JP2
620 	return &J2KRegister;
621 #else
622 	return NULL;
623 #endif
624 }
625 
626