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(¶meters);
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, ¶meters);
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, ¶meters);
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