X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fopenjp2%2Ft2.c;h=ebda005267e64967fe61006497ac248604d41199;hb=1462e9403fb7d1186e999701dfe72980262a089c;hp=5d5e33eab7547be57435de8eee769569fd4ee00e;hpb=ca34d13e76a588a00171e57690c1deeaf068723a;p=openjpeg.git diff --git a/src/lib/openjp2/t2.c b/src/lib/openjp2/t2.c index 5d5e33ea..ebda0052 100644 --- a/src/lib/openjp2/t2.c +++ b/src/lib/openjp2/t2.c @@ -13,6 +13,7 @@ * Copyright (c) 2005, Herve Drolon, FreeImage Team * Copyright (c) 2008, 2011-2012, Centre National d'Etudes Spatiales (CNES), FR * Copyright (c) 2012, CS Systemes d'Information, France + * Copyright (c) 2017, IntoPIX SA * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -68,6 +69,8 @@ Encode a packet of a tile to a destination buffer @param p_data_written FIXME DOC @param len Length of the destination buffer @param cstr_info Codestream information structure +@param p_t2_mode If == THRESH_CALC In Threshold calculation ,If == FINAL_PASS Final pass +@param p_manager the user event manager @return */ static OPJ_BOOL opj_t2_encode_packet(OPJ_UINT32 tileno, @@ -77,7 +80,9 @@ static OPJ_BOOL opj_t2_encode_packet(OPJ_UINT32 tileno, OPJ_BYTE *dest, OPJ_UINT32 * p_data_written, OPJ_UINT32 len, - opj_codestream_info_t *cstr_info); + opj_codestream_info_t *cstr_info, + J2K_T2_MODE p_t2_mode, + opj_event_mgr_t *p_manager); /** Decode a packet of a tile from a source buffer @@ -219,10 +224,12 @@ OPJ_BOOL opj_t2_encode_packets(opj_t2_t* p_t2, OPJ_UINT32 * p_data_written, OPJ_UINT32 p_max_len, opj_codestream_info_t *cstr_info, + opj_tcd_marker_info_t* p_marker_info, OPJ_UINT32 p_tp_num, OPJ_INT32 p_tp_pos, OPJ_UINT32 p_pino, - J2K_T2_MODE p_t2_mode) + J2K_T2_MODE p_t2_mode, + opj_event_mgr_t *p_manager) { OPJ_BYTE *l_current_data = p_dest; OPJ_UINT32 l_nb_bytes = 0; @@ -238,7 +245,7 @@ OPJ_BOOL opj_t2_encode_packets(opj_t2_t* p_t2, l_image->numcomps : 1; OPJ_UINT32 l_nb_pocs = l_tcp->numpocs + 1; - l_pi = opj_pi_initialise_encode(l_image, l_cp, p_tile_no, p_t2_mode); + l_pi = opj_pi_initialise_encode(l_image, l_cp, p_tile_no, p_t2_mode, p_manager); if (!l_pi) { return OPJ_FALSE; } @@ -268,7 +275,10 @@ OPJ_BOOL opj_t2_encode_packets(opj_t2_t* p_t2, l_nb_bytes = 0; if (! opj_t2_encode_packet(p_tile_no, p_tile, l_tcp, l_current_pi, - l_current_data, &l_nb_bytes, p_max_len, cstr_info)) { + l_current_data, &l_nb_bytes, + p_max_len, cstr_info, + p_t2_mode, + p_manager)) { opj_pi_destroy(l_pi, l_nb_pocs); return OPJ_FALSE; } @@ -301,12 +311,27 @@ OPJ_BOOL opj_t2_encode_packets(opj_t2_t* p_t2, opj_pi_destroy(l_pi, l_nb_pocs); return OPJ_FALSE; } + + if (p_marker_info && p_marker_info->need_PLT) { + /* One time use intended */ + assert(p_marker_info->packet_count == 0); + assert(p_marker_info->p_packet_size == NULL); + + p_marker_info->p_packet_size = (OPJ_UINT32*) opj_malloc( + opj_get_encoding_packet_count(l_image, l_cp, p_tile_no) * sizeof(OPJ_UINT32)); + if (p_marker_info->p_packet_size == NULL) { + opj_pi_destroy(l_pi, l_nb_pocs); + return OPJ_FALSE; + } + } + while (opj_pi_next(l_current_pi)) { if (l_current_pi->layno < p_maxlayers) { l_nb_bytes = 0; if (! opj_t2_encode_packet(p_tile_no, p_tile, l_tcp, l_current_pi, - l_current_data, &l_nb_bytes, p_max_len, cstr_info)) { + l_current_data, &l_nb_bytes, p_max_len, + cstr_info, p_t2_mode, p_manager)) { opj_pi_destroy(l_pi, l_nb_pocs); return OPJ_FALSE; } @@ -316,6 +341,11 @@ OPJ_BOOL opj_t2_encode_packets(opj_t2_t* p_t2, * p_data_written += l_nb_bytes; + if (p_marker_info && p_marker_info->need_PLT) { + p_marker_info->p_packet_size[p_marker_info->packet_count] = l_nb_bytes; + p_marker_info->packet_count ++; + } + /* INDEX >> */ if (cstr_info) { if (cstr_info->index_write) { @@ -360,7 +390,8 @@ static void opj_null_jas_fprintf(FILE* file, const char * format, ...) #define JAS_FPRINTF opj_null_jas_fprintf #endif -OPJ_BOOL opj_t2_decode_packets(opj_t2_t *p_t2, +OPJ_BOOL opj_t2_decode_packets(opj_tcd_t* tcd, + opj_t2_t *p_t2, OPJ_UINT32 p_tile_no, opj_tcd_tile_t *p_tile, OPJ_BYTE *p_src, @@ -394,7 +425,7 @@ OPJ_BOOL opj_t2_decode_packets(opj_t2_t *p_t2, #endif /* create a packet iterator */ - l_pi = opj_pi_create_decode(l_image, l_cp, p_tile_no); + l_pi = opj_pi_create_decode(l_image, l_cp, p_tile_no, p_manager); if (!l_pi) { return OPJ_FALSE; } @@ -425,14 +456,53 @@ OPJ_BOOL opj_t2_decode_packets(opj_t2_t *p_t2, memset(first_pass_failed, OPJ_TRUE, l_image->numcomps * sizeof(OPJ_BOOL)); while (opj_pi_next(l_current_pi)) { + OPJ_BOOL skip_packet = OPJ_FALSE; JAS_FPRINTF(stderr, "packet offset=00000166 prg=%d cmptno=%02d rlvlno=%02d prcno=%03d lyrno=%02d\n\n", l_current_pi->poc.prg1, l_current_pi->compno, l_current_pi->resno, l_current_pi->precno, l_current_pi->layno); - if (l_tcp->num_layers_to_decode > l_current_pi->layno - && l_current_pi->resno < - p_tile->comps[l_current_pi->compno].minimum_num_resolutions) { + /* If the packet layer is greater or equal than the maximum */ + /* number of layers, skip the packet */ + if (l_current_pi->layno >= l_tcp->num_layers_to_decode) { + skip_packet = OPJ_TRUE; + } + /* If the packet resolution number is greater than the minimum */ + /* number of resolution allowed, skip the packet */ + else if (l_current_pi->resno >= + p_tile->comps[l_current_pi->compno].minimum_num_resolutions) { + skip_packet = OPJ_TRUE; + } else { + /* If no precincts of any band intersects the area of interest, */ + /* skip the packet */ + OPJ_UINT32 bandno; + opj_tcd_tilecomp_t *tilec = &p_tile->comps[l_current_pi->compno]; + opj_tcd_resolution_t *res = &tilec->resolutions[l_current_pi->resno]; + + skip_packet = OPJ_TRUE; + for (bandno = 0; bandno < res->numbands; ++bandno) { + opj_tcd_band_t* band = &res->bands[bandno]; + opj_tcd_precinct_t* prec = &band->precincts[l_current_pi->precno]; + + if (opj_tcd_is_subband_area_of_interest(tcd, + l_current_pi->compno, + l_current_pi->resno, + band->bandno, + (OPJ_UINT32)prec->x0, + (OPJ_UINT32)prec->y0, + (OPJ_UINT32)prec->x1, + (OPJ_UINT32)prec->y1)) { + skip_packet = OPJ_FALSE; + break; + } + } + /* + printf("packet cmptno=%02d rlvlno=%02d prcno=%03d lyrno=%02d -> %s\n", + l_current_pi->compno, l_current_pi->resno, + l_current_pi->precno, l_current_pi->layno, skip_packet ? "skipped" : "kept"); + */ + } + if (!skip_packet) { l_nb_bytes_read = 0; first_pass_failed[l_current_pi->compno] = OPJ_FALSE; @@ -596,7 +666,9 @@ static OPJ_BOOL opj_t2_encode_packet(OPJ_UINT32 tileno, OPJ_BYTE *dest, OPJ_UINT32 * p_data_written, OPJ_UINT32 length, - opj_codestream_info_t *cstr_info) + opj_codestream_info_t *cstr_info, + J2K_T2_MODE p_t2_mode, + opj_event_mgr_t *p_manager) { OPJ_UINT32 bandno, cblkno; OPJ_BYTE* c = dest; @@ -614,10 +686,31 @@ static OPJ_BOOL opj_t2_encode_packet(OPJ_UINT32 tileno, opj_tcd_resolution_t *res = &tilec->resolutions[resno]; opj_bio_t *bio = 00; /* BIO component */ +#ifdef ENABLE_EMPTY_PACKET_OPTIMIZATION OPJ_BOOL packet_empty = OPJ_TRUE; +#else + OPJ_BOOL packet_empty = OPJ_FALSE; +#endif + +#ifdef DEBUG_VERBOSE + if (p_t2_mode == FINAL_PASS) { + fprintf(stderr, + "encode packet compono=%d, resno=%d, precno=%d, layno=%d\n", + compno, resno, precno, layno); + } +#endif /* */ if (tcp->csty & J2K_CP_CSTY_SOP) { + if (length < 6) { + if (p_t2_mode == FINAL_PASS) { + opj_event_msg(p_manager, EVT_ERROR, + "opj_t2_encode_packet(): only %u bytes remaining in " + "output buffer. %u needed.\n", + length, 6); + } + return OPJ_FALSE; + } c[0] = 255; c[1] = 145; c[2] = 0; @@ -645,6 +738,15 @@ static OPJ_BOOL opj_t2_encode_packet(OPJ_UINT32 tileno, continue; } + /* Avoid out of bounds access of https://github.com/uclouvain/openjpeg/issues/1294 */ + /* but likely not a proper fix. */ + if (precno >= res->pw * res->ph) { + opj_event_msg(p_manager, EVT_ERROR, + "opj_t2_encode_packet(): accessing precno=%u >= %u\n", + precno, res->pw * res->ph); + return OPJ_FALSE; + } + prc = &band->precincts[precno]; opj_tgt_reset(prc->incltree); opj_tgt_reset(prc->imsbtree); @@ -666,6 +768,11 @@ static OPJ_BOOL opj_t2_encode_packet(OPJ_UINT32 tileno, } opj_bio_init_enc(bio, c, length); +#ifdef ENABLE_EMPTY_PACKET_OPTIMIZATION + /* WARNING: this code branch is disabled, since it has been reported that */ + /* such packets cause decoding issues with cinema J2K hardware */ + /* decoders: https://groups.google.com/forum/#!topic/openjpeg/M7M_fLX_Bco */ + /* Check if the packet is empty */ /* Note: we could also skip that step and always write a packet header */ band = res->bands; @@ -693,10 +800,9 @@ static OPJ_BOOL opj_t2_encode_packet(OPJ_UINT32 tileno, break; } } - +#endif opj_bio_write(bio, packet_empty ? 0 : 1, 1); /* Empty header bit */ - /* Writing Packet header */ band = res->bands; for (bandno = 0; !packet_empty && @@ -708,6 +814,15 @@ static OPJ_BOOL opj_t2_encode_packet(OPJ_UINT32 tileno, continue; } + /* Avoid out of bounds access of https://github.com/uclouvain/openjpeg/issues/1297 */ + /* but likely not a proper fix. */ + if (precno >= res->pw * res->ph) { + opj_event_msg(p_manager, EVT_ERROR, + "opj_t2_encode_packet(): accessing precno=%u >= %u\n", + precno, res->pw * res->ph); + return OPJ_FALSE; + } + prc = &band->precincts[precno]; l_nb_blocks = prc->cw * prc->ch; cblk = prc->cblks.enc; @@ -806,6 +921,15 @@ static OPJ_BOOL opj_t2_encode_packet(OPJ_UINT32 tileno, /* */ if (tcp->csty & J2K_CP_CSTY_EPH) { + if (length < 2) { + if (p_t2_mode == FINAL_PASS) { + opj_event_msg(p_manager, EVT_ERROR, + "opj_t2_encode_packet(): only %u bytes remaining in " + "output buffer. %u needed.\n", + length, 2); + } + return OPJ_FALSE; + } c[0] = 255; c[1] = 146; c += 2; @@ -845,6 +969,12 @@ static OPJ_BOOL opj_t2_encode_packet(OPJ_UINT32 tileno, } if (layer->len > length) { + if (p_t2_mode == FINAL_PASS) { + opj_event_msg(p_manager, EVT_ERROR, + "opj_t2_encode_packet(): only %u bytes remaining in " + "output buffer. %u needed.\n", + length, layer->len); + } return OPJ_FALSE; } @@ -993,7 +1123,7 @@ static OPJ_BOOL opj_t2_read_packet_header(opj_t2_t* p_t2, /* When the marker PPT/PPM is used the packet header are store in PPT/PPM marker - This part deal with this caracteristic + This part deal with this characteristic step 1: Read packet header in the saved structure step 2: Return to codestream for decoding */ @@ -1098,6 +1228,7 @@ static OPJ_BOOL opj_t2_read_packet_header(opj_t2_t* p_t2, ++i; } + l_cblk->Mb = (OPJ_UINT32)l_band->numbps; l_cblk->numbps = (OPJ_UINT32)l_band->numbps + 1 - i; l_cblk->numlenbits = 3; } @@ -1127,34 +1258,63 @@ static OPJ_BOOL opj_t2_read_packet_header(opj_t2_t* p_t2, } n = (OPJ_INT32)l_cblk->numnewpasses; - do { - OPJ_UINT32 bit_number; - l_cblk->segs[l_segno].numnewpasses = (OPJ_UINT32)opj_int_min((OPJ_INT32)( - l_cblk->segs[l_segno].maxpasses - l_cblk->segs[l_segno].numpasses), n); - bit_number = l_cblk->numlenbits + opj_uint_floorlog2( - l_cblk->segs[l_segno].numnewpasses); - if (bit_number > 32) { - opj_event_msg(p_manager, EVT_ERROR, - "Invalid bit number %d in opj_t2_read_packet_header()\n", - bit_number); - opj_bio_destroy(l_bio); - return OPJ_FALSE; - } - l_cblk->segs[l_segno].newlen = opj_bio_read(l_bio, bit_number); - JAS_FPRINTF(stderr, "included=%d numnewpasses=%d increment=%d len=%d \n", - l_included, l_cblk->segs[l_segno].numnewpasses, l_increment, - l_cblk->segs[l_segno].newlen); + if ((p_tcp->tccps[p_pi->compno].cblksty & J2K_CCP_CBLKSTY_HT) != 0) + do { + OPJ_UINT32 bit_number; + l_cblk->segs[l_segno].numnewpasses = l_segno == 0 ? 1 : (OPJ_UINT32)n; + bit_number = l_cblk->numlenbits + opj_uint_floorlog2( + l_cblk->segs[l_segno].numnewpasses); + if (bit_number > 32) { + opj_event_msg(p_manager, EVT_ERROR, + "Invalid bit number %d in opj_t2_read_packet_header()\n", + bit_number); + opj_bio_destroy(l_bio); + return OPJ_FALSE; + } + l_cblk->segs[l_segno].newlen = opj_bio_read(l_bio, bit_number); + JAS_FPRINTF(stderr, "included=%d numnewpasses=%d increment=%d len=%d \n", + l_included, l_cblk->segs[l_segno].numnewpasses, l_increment, + l_cblk->segs[l_segno].newlen); - n -= (OPJ_INT32)l_cblk->segs[l_segno].numnewpasses; - if (n > 0) { - ++l_segno; + n -= (OPJ_INT32)l_cblk->segs[l_segno].numnewpasses; + if (n > 0) { + ++l_segno; - if (! opj_t2_init_seg(l_cblk, l_segno, p_tcp->tccps[p_pi->compno].cblksty, 0)) { + if (! opj_t2_init_seg(l_cblk, l_segno, p_tcp->tccps[p_pi->compno].cblksty, 0)) { + opj_bio_destroy(l_bio); + return OPJ_FALSE; + } + } + } while (n > 0); + else + do { + OPJ_UINT32 bit_number; + l_cblk->segs[l_segno].numnewpasses = (OPJ_UINT32)opj_int_min((OPJ_INT32)( + l_cblk->segs[l_segno].maxpasses - l_cblk->segs[l_segno].numpasses), n); + bit_number = l_cblk->numlenbits + opj_uint_floorlog2( + l_cblk->segs[l_segno].numnewpasses); + if (bit_number > 32) { + opj_event_msg(p_manager, EVT_ERROR, + "Invalid bit number %d in opj_t2_read_packet_header()\n", + bit_number); opj_bio_destroy(l_bio); return OPJ_FALSE; } - } - } while (n > 0); + l_cblk->segs[l_segno].newlen = opj_bio_read(l_bio, bit_number); + JAS_FPRINTF(stderr, "included=%d numnewpasses=%d increment=%d len=%d \n", + l_included, l_cblk->segs[l_segno].numnewpasses, l_increment, + l_cblk->segs[l_segno].newlen); + + n -= (OPJ_INT32)l_cblk->segs[l_segno].numnewpasses; + if (n > 0) { + ++l_segno; + + if (! opj_t2_init_seg(l_cblk, l_segno, p_tcp->tccps[p_pi->compno].cblksty, 0)) { + opj_bio_destroy(l_bio); + return OPJ_FALSE; + } + } + } while (n > 0); ++l_cblk; } @@ -1217,6 +1377,7 @@ static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2, opj_tcd_cblk_dec_t* l_cblk = 00; opj_tcd_resolution_t* l_res = &p_tile->comps[p_pi->compno].resolutions[p_pi->resno]; + OPJ_BOOL partial_buffer = OPJ_FALSE; OPJ_ARG_NOT_USED(p_t2); OPJ_ARG_NOT_USED(pack_info); @@ -1236,6 +1397,12 @@ static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2, for (cblkno = 0; cblkno < l_nb_code_blocks; ++cblkno) { opj_tcd_seg_t *l_seg = 00; + // if we have a partial data stream, set numchunks to zero + // since we have no data to actually decode. + if (partial_buffer) { + l_cblk->numchunks = 0; + } + if (!l_cblk->numnewpasses) { /* nothing to do */ ++l_cblk; @@ -1258,12 +1425,32 @@ static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2, /* Check possible overflow (on l_current_data only, assumes input args already checked) then size */ if ((((OPJ_SIZE_T)l_current_data + (OPJ_SIZE_T)l_seg->newlen) < (OPJ_SIZE_T)l_current_data) || - (l_current_data + l_seg->newlen > p_src_data + p_max_length)) { - opj_event_msg(p_manager, EVT_ERROR, - "read: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", - l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, - p_pi->compno); - return OPJ_FALSE; + (l_current_data + l_seg->newlen > p_src_data + p_max_length) || + (partial_buffer)) { + if (p_t2->cp->strict) { + opj_event_msg(p_manager, EVT_ERROR, + "read: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", + l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, + p_pi->compno); + return OPJ_FALSE; + } else { + opj_event_msg(p_manager, EVT_WARNING, + "read: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", + l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, + p_pi->compno); + // skip this codeblock since it is a partial read + partial_buffer = OPJ_TRUE; + l_cblk->numchunks = 0; + + l_seg->numpasses += l_seg->numnewpasses; + l_cblk->numnewpasses -= l_seg->numnewpasses; + if (l_cblk->numnewpasses > 0) { + ++l_seg; + ++l_cblk->numsegs; + break; + } + continue; + } } #ifdef USE_JPWL @@ -1287,25 +1474,26 @@ static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2, #endif /* USE_JPWL */ - if (l_seg->numchunks == l_seg->numchunksalloc) { - OPJ_UINT32 l_numchunksalloc = l_seg->numchunksalloc * 2 + 1; + if (l_cblk->numchunks == l_cblk->numchunksalloc) { + OPJ_UINT32 l_numchunksalloc = l_cblk->numchunksalloc * 2 + 1; opj_tcd_seg_data_chunk_t* l_chunks = - (opj_tcd_seg_data_chunk_t*)opj_realloc(l_seg->chunks, + (opj_tcd_seg_data_chunk_t*)opj_realloc(l_cblk->chunks, l_numchunksalloc * sizeof(opj_tcd_seg_data_chunk_t)); if (l_chunks == NULL) { opj_event_msg(p_manager, EVT_ERROR, "cannot allocate opj_tcd_seg_data_chunk_t* array"); return OPJ_FALSE; } - l_seg->chunks = l_chunks; - l_seg->numchunksalloc = l_numchunksalloc; + l_cblk->chunks = l_chunks; + l_cblk->numchunksalloc = l_numchunksalloc; } - l_seg->chunks[l_seg->numchunks].data = l_current_data; - l_seg->chunks[l_seg->numchunks].len = l_seg->newlen; - l_seg->numchunks ++; + l_cblk->chunks[l_cblk->numchunks].data = l_current_data; + l_cblk->chunks[l_cblk->numchunks].len = l_seg->newlen; + l_cblk->numchunks ++; l_current_data += l_seg->newlen; + l_seg->len += l_seg->newlen; l_seg->numpasses += l_seg->numnewpasses; l_cblk->numnewpasses -= l_seg->numnewpasses; @@ -1324,8 +1512,12 @@ static OPJ_BOOL opj_t2_read_packet_data(opj_t2_t* p_t2, ++l_band; } - *(p_data_read) = (OPJ_UINT32)(l_current_data - p_src_data); - + // return the number of bytes read + if (partial_buffer) { + *(p_data_read) = p_max_length; + } else { + *(p_data_read) = (OPJ_UINT32)(l_current_data - p_src_data); + } return OPJ_TRUE; } @@ -1387,11 +1579,18 @@ static OPJ_BOOL opj_t2_skip_packet_data(opj_t2_t* p_t2, /* Check possible overflow then size */ if (((*p_data_read + l_seg->newlen) < (*p_data_read)) || ((*p_data_read + l_seg->newlen) > p_max_length)) { - opj_event_msg(p_manager, EVT_ERROR, - "skip: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", - l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, - p_pi->compno); - return OPJ_FALSE; + if (p_t2->cp->strict) { + opj_event_msg(p_manager, EVT_ERROR, + "skip: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", + l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, + p_pi->compno); + return OPJ_FALSE; + } else { + opj_event_msg(p_manager, EVT_WARNING, + "skip: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n", + l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, + p_pi->compno); + } } #ifdef USE_JPWL