[trunk] Import (ugly) patch from sumatrapdf team. This feels like a hack rather than...
[openjpeg.git] / src / lib / openjp2 / j2k.c
index dccab6de81112a80e7ca81c033ce6b2a2a702464..aa4f1d1dbcf35b9f79b34c5b02abcc24e9f9e29e 100644 (file)
 
 #include "opj_includes.h"
 
+#define CINEMA_24_CS 1302083   /*Codestream length for 24fps*/
+#define CINEMA_48_CS 651041            /*Codestream length for 48fps*/
+#define COMP_24_CS 1041666             /*Maximum size per color component for 2K & 4K @ 24fps*/
+#define COMP_48_CS 520833              /*Maximum size per color component for 2K @ 48fps*/
+
 /** @defgroup J2K J2K - JPEG-2000 codestream reader/writer */
 /*@{*/
 
@@ -1040,13 +1045,24 @@ static OPJ_BOOL opj_j2k_read_cbd (      opj_j2k_t *p_j2k,
                                                                 opj_event_mgr_t * p_manager);
 
 /**
- * Writes the image components.
+ * Writes COC marker for each component.
+ *
+ * @param       p_stream                the stream to write data to.
+ * @param       p_j2k                   J2K codec.
+ * @param       p_manager               the user event manager.
+*/
+static OPJ_BOOL opj_j2k_write_all_coc( opj_j2k_t *p_j2k,
+                                                                        opj_stream_private_t *p_stream,
+                                                                        opj_event_mgr_t * p_manager );
+
+/**
+ * Writes QCC marker for each component.
  *
  * @param       p_stream                the stream to write data to.
  * @param       p_j2k                   J2K codec.
  * @param       p_manager               the user event manager.
 */
-static OPJ_BOOL opj_j2k_write_image_components( opj_j2k_t *p_j2k,
+static OPJ_BOOL opj_j2k_write_all_qcc( opj_j2k_t *p_j2k,
                                                                         opj_stream_private_t *p_stream,
                                                                         opj_event_mgr_t * p_manager );
 
@@ -1131,6 +1147,12 @@ static OPJ_FLOAT32 opj_j2k_get_tp_stride (opj_tcp_t * p_tcp);
 
 static OPJ_FLOAT32 opj_j2k_get_default_stride (opj_tcp_t * p_tcp);
 
+static int opj_j2k_initialise_4K_poc(opj_poc_t *POC, int numres);
+
+static void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *image, opj_event_mgr_t *p_manager);
+
+static OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_CINEMA_MODE cinema_mode, opj_event_mgr_t *p_manager);
+
 /*@}*/
 
 /*@}*/
@@ -1932,6 +1954,23 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k,
                 return OPJ_FALSE;
         }
 
+        /* testcase 4035.pdf.SIGSEGV.d8b.3375 */
+        if (l_image->x0 > l_image->x1 || l_image->y0 > l_image->y1) {
+                opj_event_msg(p_manager, EVT_ERROR, "Error with SIZ marker: negative image size (%d x %d)\n", l_image->x1 - l_image->x0, l_image->y1 - l_image->y0);
+                return OPJ_FALSE;
+        }
+        /* testcase 2539.pdf.SIGFPE.706.1712 (also 3622.pdf.SIGFPE.706.2916 and 4008.pdf.SIGFPE.706.3345 and maybe more) */
+        if (!(l_cp->tdx * l_cp->tdy)) {
+                opj_event_msg(p_manager, EVT_ERROR, "Error with SIZ marker: invalid tile size (tdx: %d, tdy: %d)\n", l_cp->tdx, l_cp->tdy);
+                return OPJ_FALSE;
+        }
+
+        /* testcase 1610.pdf.SIGSEGV.59c.681 */
+        if (((OPJ_UINT64)l_image->x1) * ((OPJ_UINT64)l_image->y1) != (l_image->x1 * l_image->y1)) {
+                opj_event_msg(p_manager, EVT_ERROR, "Prevent buffer overflow (x1: %d, y1: %d)", l_image->x1, l_image->y1);
+                return OPJ_FALSE;
+        }
+
 #ifdef USE_JPWL
         if (l_cp->correct) {
                 /* if JPWL is on, we check whether TX errors have damaged
@@ -1998,6 +2037,13 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k,
                 opj_read_bytes(p_header_data,&tmp,1);   /* YRsiz_i */
                 ++p_header_data;
                 l_img_comp->dy = (OPJ_INT32)tmp; /* should be between 1 and 255 */
+                if( l_img_comp->dx < 1 || l_img_comp->dx > 255 ||
+                    l_img_comp->dy < 1 || l_img_comp->dy > 255 ) {
+                    opj_event_msg(p_manager, EVT_ERROR,
+                                  "Invalid values for comp = %d : dx=%u dy=%u\n (should be between 1 and 255 according the JPEG2000 norm)",
+                                  i, l_img_comp->dx, l_img_comp->dy);
+                    return OPJ_FALSE;
+                }
 
 #ifdef USE_JPWL
                 if (l_cp->correct) {
@@ -2034,6 +2080,14 @@ static OPJ_BOOL opj_j2k_read_siz(opj_j2k_t *p_j2k,
         /* Compute the number of tiles */
         l_cp->tw = opj_int_ceildiv(l_image->x1 - l_cp->tx0, l_cp->tdx);
         l_cp->th = opj_int_ceildiv(l_image->y1 - l_cp->ty0, l_cp->tdy);
+
+        /* Check that the number of tiles is valid */
+        if (l_cp->tw == 0 || l_cp->th == 0 || l_cp->tw > 65535 / l_cp->th) {
+            opj_event_msg(  p_manager, EVT_ERROR, 
+                            "Invalid number of tiles : %u x %u (maximum fixed by jpeg2000 norm is 65535 tiles)\n",
+                            l_cp->tw, l_cp->th);
+            return OPJ_FALSE;
+        }
         l_nb_tiles = l_cp->tw * l_cp->th;
 
         /* Define the tiles which will be decoded */
@@ -2677,7 +2731,8 @@ OPJ_BOOL opj_j2k_write_qcc(     opj_j2k_t *p_j2k,
         assert(p_manager != 00);
         assert(p_stream != 00);
 
-        l_qcc_size = 6 + opj_j2k_get_SQcd_SQcc_size(p_j2k,p_j2k->m_current_tile_number,p_comp_no);
+        l_qcc_size = 5 + opj_j2k_get_SQcd_SQcc_size(p_j2k,p_j2k->m_current_tile_number,p_comp_no);
+        l_qcc_size += p_j2k->m_private_image->numcomps <= 256 ? 0:1;
         l_remaining_size = l_qcc_size;
 
         if (l_qcc_size > p_j2k->m_specific_param.m_encoder.m_header_tile_data_size) {
@@ -3860,6 +3915,12 @@ OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k,
         opj_read_bytes(p_header_data,&(p_j2k->m_current_tile_number),2);                /* Isot */
         p_header_data+=2;
 
+        /* testcase 2.pdf.SIGFPE.706.1112 */
+        if (p_j2k->m_current_tile_number >= l_cp->tw * l_cp->th) {
+                opj_event_msg(p_manager, EVT_ERROR, "Invalid tile number %d\n", p_j2k->m_current_tile_number);
+                return OPJ_FALSE;
+        }
+
         l_tcp = &l_cp->tcps[p_j2k->m_current_tile_number];
         l_tile_x = p_j2k->m_current_tile_number % l_cp->tw;
         l_tile_y = p_j2k->m_current_tile_number / l_cp->tw;
@@ -3949,20 +4010,19 @@ OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k,
                 if (l_num_parts != 0) { /* Number of tile-part header is provided by this tile-part header */
                         /* Useful to manage the case of textGBR.jp2 file because two values of TNSot are allowed: the correct numbers of
                          * tile-parts for that tile and zero (A.4.2 of 15444-1 : 2002). */
-                        if (l_tcp->m_nb_tile_parts) {
-                                if (l_current_part >= l_tcp->m_nb_tile_parts){
-                                        opj_event_msg(p_manager, EVT_ERROR, "In SOT marker, TPSot (%d) is not valid regards to the current "
-                                                        "number of tile-part (%d), giving up\n", l_current_part, l_tcp->m_nb_tile_parts );
-                                        p_j2k->m_specific_param.m_decoder.m_last_tile_part = 1;
-                                        return OPJ_FALSE;
-                                }
+                        if (l_num_parts < l_tcp->m_nb_tile_parts) {
+                                l_num_parts = l_tcp->m_nb_tile_parts;
+                        }
+                        if (l_current_part >= l_num_parts) {
+                                /* testcase 451.pdf.SIGSEGV.ce9.3723 */
+                                l_num_parts = l_current_part + 1;
                         }
                         l_tcp->m_nb_tile_parts = l_num_parts;
                 }
 
                 /* If know the number of tile part header we will check if we didn't read the last*/
                 if (l_tcp->m_nb_tile_parts) {
-                        if (l_tcp->m_nb_tile_parts == (l_current_part + 1)) {
+                        if (l_tcp->m_nb_tile_parts == l_current_part) {
                                 p_j2k->m_specific_param.m_decoder.m_can_decode = 1; /* Process the last tile-part header*/
                         }
                 }
@@ -4031,7 +4091,7 @@ OPJ_BOOL opj_j2k_read_sot ( opj_j2k_t *p_j2k,
 
                                         if ( l_current_part >= p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].current_nb_tps ){
                                                 opj_tp_index_t *new_tp_index;
-                                                p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].current_nb_tps += 10;
+                                                p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].current_nb_tps = l_current_part + 1;
                                                 new_tp_index = (opj_tp_index_t *) opj_realloc(
                                                                 p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index,
                                                                 p_j2k->cstr_index->tile_index[p_j2k->m_current_tile_number].current_nb_tps * sizeof(opj_tp_index_t));
@@ -4421,6 +4481,14 @@ static OPJ_BOOL opj_j2k_read_rgn (opj_j2k_t *p_j2k,
         };
 #endif /* USE_JPWL */
 
+        /* testcase 3635.pdf.asan.77.2930 */
+        if (l_comp_room >= l_nb_comp) {
+                opj_event_msg(p_manager, EVT_ERROR,
+                        "JPWL: bad component number in RGN (%d when there are only %d)\n",
+                        l_comp_room, l_nb_comp);
+                return OPJ_FALSE;
+        }
+
         opj_read_bytes(p_header_data,(OPJ_UINT32 *) (&(l_tcp->tccps[l_comp_no].roishift)),1);   /* SPrgn */
         ++p_header_data;
 
@@ -4712,7 +4780,7 @@ OPJ_BOOL opj_j2k_write_mct_data_group(  opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
-OPJ_BOOL opj_j2k_write_image_components(opj_j2k_t *p_j2k,
+OPJ_BOOL opj_j2k_write_all_coc(opj_j2k_t *p_j2k,
                                                                         struct opj_stream_private *p_stream,
                                                                         struct opj_event_mgr * p_manager )
 {
@@ -4723,12 +4791,29 @@ OPJ_BOOL opj_j2k_write_image_components(opj_j2k_t *p_j2k,
         assert(p_manager != 00);
         assert(p_stream != 00);
 
-        for (compno = 1; compno < p_j2k->m_private_image->numcomps; ++compno)
+        for (compno = 0; compno < p_j2k->m_private_image->numcomps; ++compno)
         {
                 if (! opj_j2k_write_coc(p_j2k,compno,p_stream, p_manager)) {
                         return OPJ_FALSE;
                 }
+        }
+
+        return OPJ_TRUE;
+}
+
+OPJ_BOOL opj_j2k_write_all_qcc(opj_j2k_t *p_j2k,
+                                                                        struct opj_stream_private *p_stream,
+                                                                        struct opj_event_mgr * p_manager )
+{
+        OPJ_UINT32 compno;
+
+        /* preconditions */
+        assert(p_j2k != 00);
+        assert(p_manager != 00);
+        assert(p_stream != 00);
 
+        for (compno = 0; compno < p_j2k->m_private_image->numcomps; ++compno)
+        {
                 if (! opj_j2k_write_qcc(p_j2k,compno,p_stream, p_manager)) {
                         return OPJ_FALSE;
                 }
@@ -4737,6 +4822,7 @@ OPJ_BOOL opj_j2k_write_image_components(opj_j2k_t *p_j2k,
         return OPJ_TRUE;
 }
 
+
 OPJ_BOOL opj_j2k_write_regions( opj_j2k_t *p_j2k,
                                                         struct opj_stream_private *p_stream,
                                                         struct opj_event_mgr * p_manager )
@@ -5734,6 +5820,256 @@ opj_j2k_t* opj_j2k_create_compress(void)
         return l_j2k;
 }
 
+int opj_j2k_initialise_4K_poc(opj_poc_t *POC, int numres){
+    POC[0].tile  = 1;
+    POC[0].resno0  = 0;
+    POC[0].compno0 = 0;
+    POC[0].layno1  = 1;
+    POC[0].resno1  = numres-1;
+    POC[0].compno1 = 3;
+    POC[0].prg1 = OPJ_CPRL;
+    POC[1].tile  = 1;
+    POC[1].resno0  = numres-1;
+    POC[1].compno0 = 0;
+    POC[1].layno1  = 1;
+    POC[1].resno1  = numres;
+    POC[1].compno1 = 3;
+    POC[1].prg1 = OPJ_CPRL;
+    return 2;
+}
+
+void opj_j2k_set_cinema_parameters(opj_cparameters_t *parameters, opj_image_t *image, opj_event_mgr_t *p_manager)
+{
+    /* Configure cinema parameters */
+    float max_rate = 0;
+    float temp_rate = 0;
+    int i;
+
+    /* profile (Rsiz) */
+    switch (parameters->cp_cinema){
+    case OPJ_CINEMA2K_24:
+    case OPJ_CINEMA2K_48:
+        parameters->cp_rsiz = OPJ_CINEMA2K;
+        break;
+    case OPJ_CINEMA4K_24:
+        parameters->cp_rsiz = OPJ_CINEMA4K;
+        break;
+    }
+
+    /* No tiling */
+    parameters->tile_size_on = OPJ_FALSE;
+    parameters->cp_tdx=1;
+    parameters->cp_tdy=1;
+
+    /* One tile part for each component */
+    parameters->tp_flag = 'C';
+    parameters->tp_on = 1;
+
+    /* Tile and Image shall be at (0,0) */
+    parameters->cp_tx0 = 0;
+    parameters->cp_ty0 = 0;
+    parameters->image_offset_x0 = 0;
+    parameters->image_offset_y0 = 0;
+
+    /* Codeblock size= 32*32 */
+    parameters->cblockw_init = 32;
+    parameters->cblockh_init = 32;
+
+    /* Codeblock style: no mode switch enabled */
+    parameters->mode = 0;
+
+    /* No ROI */
+    parameters->roi_compno = -1;
+
+    /* No subsampling */
+    parameters->subsampling_dx = 1;
+    parameters->subsampling_dy = 1;
+
+    /* 9-7 transform */
+    parameters->irreversible = 1;
+
+    /* Number of layers */
+    if (parameters->tcp_numlayers > 1){
+        opj_event_msg(p_manager, EVT_WARNING,
+                "JPEG 2000 Profile-3 and 4 (2k/4k dc profile) requires:\n"
+                "1 single quality layer"
+                "-> Number of layers forced to 1 (rather than %d)\n",
+                parameters->tcp_numlayers);
+        parameters->tcp_numlayers = 1;
+    }
+
+    /* Resolution levels */
+    switch (parameters->cp_cinema){
+    case OPJ_CINEMA2K_24:
+    case OPJ_CINEMA2K_48:
+        if(parameters->numresolution > 6){
+            opj_event_msg(p_manager, EVT_WARNING,
+                    "JPEG 2000 Profile-3 (2k dc profile) requires:\n"
+                    "Number of decomposition levels <= 5\n"
+                    "-> Number of decomposition levels forced to 5 (rather than %d)\n",
+                    parameters->numresolution+1);
+            parameters->numresolution = 6;
+        }
+        break;
+    case OPJ_CINEMA4K_24:
+        if(parameters->numresolution < 2){
+            opj_event_msg(p_manager, EVT_WARNING,
+                    "JPEG 2000 Profile-4 (4k dc profile) requires:\n"
+                    "Number of decomposition levels >= 1 && <= 6\n"
+                    "-> Number of decomposition levels forced to 1 (rather than %d)\n",
+                    parameters->numresolution+1);
+            parameters->numresolution = 1;
+        }else if(parameters->numresolution > 7){
+            opj_event_msg(p_manager, EVT_WARNING,
+                    "JPEG 2000 Profile-4 (4k dc profile) requires:\n"
+                    "Number of decomposition levels >= 1 && <= 6\n"
+                    "-> Number of decomposition levels forced to 6 (rather than %d)\n",
+                    parameters->numresolution+1);
+            parameters->numresolution = 7;
+        }
+        break;
+    default :
+        break;
+    }
+
+    /* Precincts */
+    parameters->csty |= 0x01;
+    parameters->res_spec = parameters->numresolution-1;
+    for (i = 0; i<parameters->res_spec; i++) {
+        parameters->prcw_init[i] = 256;
+        parameters->prch_init[i] = 256;
+    }
+
+    /* The progression order shall be CPRL */
+    parameters->prog_order = OPJ_CPRL;
+
+    /* Progression order changes for 4K, disallowed for 2K */
+    if (parameters->cp_cinema == OPJ_CINEMA4K_24) {
+        parameters->numpocs = opj_j2k_initialise_4K_poc(parameters->POC,parameters->numresolution);
+    } else {
+        parameters->numpocs = 0;
+    }
+
+    /* Limited bit-rate */
+    parameters->cp_disto_alloc = 1;
+    switch (parameters->cp_cinema){
+    case OPJ_CINEMA2K_24:
+    case OPJ_CINEMA4K_24:
+        max_rate = ((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/
+                (CINEMA_24_CS * 8 * image->comps[0].dx * image->comps[0].dy);
+        if (parameters->tcp_rates[0] == 0){
+            parameters->tcp_rates[0] = max_rate;
+        }else{
+            temp_rate =((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/
+                    (parameters->tcp_rates[0] * 8 * image->comps[0].dx * image->comps[0].dy);
+            if (temp_rate > CINEMA_24_CS ){
+                opj_event_msg(p_manager, EVT_WARNING,
+                        "JPEG 2000 Profile-3 and 4 (2k/4k dc profile) requires:\n"
+                        "Maximum 1302083 compressed bytes @ 24fps\n"
+                        "-> Specified rate (%3.1f) exceeds this limit. Rate will be forced to %3.1f.\n",
+                        parameters->tcp_rates[0], max_rate);
+                parameters->tcp_rates[0]= max_rate;
+            }else{
+                opj_event_msg(p_manager, EVT_WARNING,
+                        "JPEG 2000 Profile-3 and 4 (2k/4k dc profile):\n"
+                        "INFO : Specified rate (%3.1f) is below the 2k/4k limit @ 24fps.\n",
+                        parameters->tcp_rates[0]);
+            }
+        }
+        parameters->max_comp_size = COMP_24_CS;
+        break;
+    case OPJ_CINEMA2K_48:
+        max_rate = ((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/
+                (CINEMA_48_CS * 8 * image->comps[0].dx * image->comps[0].dy);
+        if (parameters->tcp_rates[0] == 0){
+            parameters->tcp_rates[0] = max_rate;
+        }else{
+            temp_rate =((float) (image->numcomps * image->comps[0].w * image->comps[0].h * image->comps[0].prec))/
+                    (parameters->tcp_rates[0] * 8 * image->comps[0].dx * image->comps[0].dy);
+            if (temp_rate > CINEMA_48_CS ){
+                opj_event_msg(p_manager, EVT_WARNING,
+                        "JPEG 2000 Profile-3 (2k dc profile) requires:\n"
+                        "Maximum 651041 compressed bytes @ 48fps\n"
+                        "-> Specified rate (%3.1f) exceeds this limit. Rate will be forced to %3.1f.\n",
+                        parameters->tcp_rates[0], max_rate);
+                parameters->tcp_rates[0]= max_rate;
+            }else{
+                opj_event_msg(p_manager, EVT_WARNING,
+                        "JPEG 2000 Profile-3 (2k dc profile):\n"
+                        "INFO : Specified rate (%3.1f) is below the 2k limit @ 48 fps.\n",
+                        parameters->tcp_rates[0]);
+            }
+        }
+        parameters->max_comp_size = COMP_48_CS;
+        break;
+    default:
+        break;
+    }
+}
+
+OPJ_BOOL opj_j2k_is_cinema_compliant(opj_image_t *image, OPJ_CINEMA_MODE cinema_mode, opj_event_mgr_t *p_manager)
+{
+    OPJ_UINT32 i;
+
+    /* Number of components */
+    if (image->numcomps != 3){
+        opj_event_msg(p_manager, EVT_WARNING,
+                "JPEG 2000 Profile-3 (2k dc profile) requires:\n"
+                "3 components"
+                "-> Number of components of input image (%d) is not compliant\n"
+                "-> Non-profile-3 codestream will be generated\n",
+                image->numcomps);
+        return OPJ_FALSE;
+    }
+
+    /* Bitdepth */
+    for (i = 0; i < image->numcomps; i++) {
+        if ((image->comps[i].bpp != 12) | (image->comps[i].sgnd)){
+            char signed_str[] = "signed";
+            char unsigned_str[] = "unsigned";
+            char *tmp_str = image->comps[i].sgnd?signed_str:unsigned_str;
+            opj_event_msg(p_manager, EVT_WARNING,
+                    "JPEG 2000 Profile-3 (2k dc profile) requires:\n"
+                    "Precision of each component shall be 12 bits unsigned"
+                    "-> At least component %d of input image (%d bits, %s) is not compliant\n"
+                    "-> Non-profile-3 codestream will be generated\n",
+                    i,image->comps[i].bpp, tmp_str);
+            return OPJ_FALSE;
+        }
+    }
+
+    /* Image size */
+    switch (cinema_mode){
+    case OPJ_CINEMA2K_24:
+    case OPJ_CINEMA2K_48:
+        if (((image->comps[0].w > 2048) | (image->comps[0].h > 1080))){
+            opj_event_msg(p_manager, EVT_WARNING,
+                    "JPEG 2000 Profile-3 (2k dc profile) requires:\n"
+                    "width <= 2048 and height <= 1080\n"
+                    "-> Input image size %d x %d is not compliant\n"
+                    "-> Non-profile-3 codestream will be generated\n",
+                    image->comps[0].w,image->comps[0].h);
+            return OPJ_FALSE;
+        }
+        break;
+    case OPJ_CINEMA4K_24:
+        if (((image->comps[0].w > 4096) | (image->comps[0].h > 2160))){
+            opj_event_msg(p_manager, EVT_WARNING,
+                    "JPEG 2000 Profile-4 (4k dc profile) requires:\n"
+                    "width <= 4096 and height <= 2160\n"
+                    "-> Image size %d x %d is not compliant\n"
+                    "-> Non-profile-4 codestream will be generated\n",
+                    image->comps[0].w,image->comps[0].h);
+            return OPJ_FALSE;
+        }
+        break;
+    default :
+        break;
+    }
+
+    return OPJ_TRUE;
+}
+
 void opj_j2k_setup_encoder(     opj_j2k_t *p_j2k,
                                                     opj_cparameters_t *parameters,
                                                     opj_image_t *image,
@@ -5753,6 +6089,14 @@ void opj_j2k_setup_encoder(     opj_j2k_t *p_j2k,
         cp->tw = 1;
         cp->th = 1;
 
+        /* set cinema parameters if required */
+        if (parameters->cp_cinema){
+            opj_j2k_set_cinema_parameters(parameters,image,p_manager);
+            if (!opj_j2k_is_cinema_compliant(image,parameters->cp_cinema,p_manager)) {
+                parameters->cp_rsiz = OPJ_STD_RSIZ;
+            }
+        }
+
         /*
         copy user encoding parameters
         */
@@ -5764,7 +6108,7 @@ void opj_j2k_setup_encoder(     opj_j2k_t *p_j2k,
         cp->m_specific_param.m_enc.m_fixed_quality = parameters->cp_fixed_quality;
 
         /* mod fixed_quality */
-        if (parameters->cp_matrice) {
+        if (parameters->cp_fixed_alloc && parameters->cp_matrice) {
                 size_t array_size = parameters->tcp_numlayers * parameters->numresolution * 3 * sizeof(OPJ_INT32);
                 cp->m_specific_param.m_enc.m_matrice = (OPJ_INT32 *) opj_malloc(array_size);
                 memcpy(cp->m_specific_param.m_enc.m_matrice, parameters->cp_matrice, array_size);
@@ -5976,16 +6320,6 @@ void opj_j2k_setup_encoder(     opj_j2k_t *p_j2k,
                                 tccp->roishift = 0;
                         }
 
-                        if(parameters->cp_cinema) {
-                                /*Precinct size for lowest frequency subband=128*/
-                                tccp->prcw[0] = 7;
-                                tccp->prch[0] = 7;
-                                /*Precinct size at all other resolutions = 256*/
-                                for (j = 1; j < tccp->numresolutions; j++) {
-                                        tccp->prcw[j] = 8;
-                                        tccp->prch[j] = 8;
-                                }
-                        }else{
                                 if (parameters->csty & J2K_CCP_CSTY_PRT) {
                                         OPJ_INT32 p = 0, it_res;
                                         for (it_res = tccp->numresolutions - 1; it_res >= 0; it_res--) {
@@ -6034,7 +6368,6 @@ void opj_j2k_setup_encoder(     opj_j2k_t *p_j2k,
                                                 tccp->prch[j] = 15;
                                         }
                                 }
-                        }
 
                         opj_dwt_calc_explicit_stepsizes(tccp, image->comps[i].prec);
                 }
@@ -7018,6 +7351,12 @@ OPJ_BOOL opj_j2k_read_tile_header(      opj_j2k_t * p_j2k,
 
                 /* Try to read until the Start Of Data is detected */
                 while (l_current_marker != J2K_MS_SOD) {
+                    
+                    if(opj_stream_get_number_byte_left(p_stream) == 0)
+                    {
+                        p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_NEOC;
+                        break;
+                    }
 
                         /* Try to read 2 bytes (the marker size) from stream and copy them into the buffer */
                         if (opj_stream_read_data(p_stream,p_j2k->m_specific_param.m_decoder.m_header_data,2,p_manager) != 2) {
@@ -7028,6 +7367,12 @@ OPJ_BOOL opj_j2k_read_tile_header(      opj_j2k_t * p_j2k,
                         /* Read 2 bytes from the buffer as the marker size */
                         opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_marker_size,2);
 
+                        /* cf. https://code.google.com/p/openjpeg/issues/detail?id=226 */
+                        if (l_current_marker == 0x8080 && opj_stream_get_number_byte_left(p_stream) == 0) {
+                                p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_NEOC;
+                                break;
+                        }
+
                         /* Why this condition? FIXME */
                         if (p_j2k->m_specific_param.m_decoder.m_state & J2K_STATE_TPH){
                                 p_j2k->m_specific_param.m_decoder.m_sot_length -= (l_marker_size + 2);
@@ -7112,6 +7457,9 @@ OPJ_BOOL opj_j2k_read_tile_header(      opj_j2k_t * p_j2k,
                                 opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_current_marker,2);
                         }
                 }
+                if(opj_stream_get_number_byte_left(p_stream) == 0
+                    && p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_NEOC)
+                    break;
 
                 /* If we didn't skip data before, we need to read the SOD marker*/
                 if (! p_j2k->m_specific_param.m_decoder.m_skip_data) {
@@ -7245,6 +7593,11 @@ OPJ_BOOL opj_j2k_decode_tile (  opj_j2k_t * p_j2k,
         p_j2k->m_specific_param.m_decoder.m_can_decode = 0;
         p_j2k->m_specific_param.m_decoder.m_state &= (~ (0x0080));/* FIXME J2K_DEC_STATE_DATA);*/
 
+        if(opj_stream_get_number_byte_left(p_stream) == 0 
+            && p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_NEOC){
+            return OPJ_TRUE;
+        }
+
         if (p_j2k->m_specific_param.m_decoder.m_state != 0x0100){ /*FIXME J2K_DEC_STATE_EOC)*/
                 if (opj_stream_read_data(p_stream,l_data,2,p_manager) != 2) {
                         opj_event_msg(p_manager, EVT_ERROR, "Stream too short\n");
@@ -7260,6 +7613,11 @@ OPJ_BOOL opj_j2k_decode_tile (  opj_j2k_t * p_j2k,
                 else if (l_current_marker != J2K_MS_SOT)
                 {
                         opj_event_msg(p_manager, EVT_ERROR, "Stream too short, expected SOT\n");
+                        
+                        if(opj_stream_get_number_byte_left(p_stream) == 0) {
+                            p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_NEOC;
+                            return OPJ_TRUE;
+                        }
                         return OPJ_FALSE;
                 }
         }
@@ -8676,6 +9034,7 @@ OPJ_BOOL opj_j2k_decode_tiles ( opj_j2k_t *p_j2k,
         OPJ_INT32 l_tile_x0,l_tile_y0,l_tile_x1,l_tile_y1;
         OPJ_UINT32 l_nb_comps;
         OPJ_BYTE * l_current_data;
+        OPJ_UINT32 nr_tiles = 0;
 
         l_current_data = (OPJ_BYTE*)opj_malloc(1000);
         if (! l_current_data) {
@@ -8724,7 +9083,12 @@ OPJ_BOOL opj_j2k_decode_tiles ( opj_j2k_t *p_j2k,
                         return OPJ_FALSE;
                 }
                 opj_event_msg(p_manager, EVT_INFO, "Image data has been updated with tile %d.\n\n", l_current_tile_no + 1);
-
+                
+                if(opj_stream_get_number_byte_left(p_stream) == 0  
+                    && p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_NEOC)
+                    break;
+                if(++nr_tiles ==  p_j2k->m_cp.th * p_j2k->m_cp.tw) 
+                    break;
         }
 
         opj_free(l_current_data);
@@ -9366,7 +9730,10 @@ void opj_j2k_setup_header_writing (opj_j2k_t *p_j2k)
         opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_qcd );
 
         if (p_j2k->m_cp.m_specific_param.m_enc.m_cinema) {
-                opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_image_components );
+                /* No need for COC or QCC, QCD and COD are used
+                opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_all_coc );
+                opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_all_qcc );
+                */
                 opj_procedure_list_add_procedure(p_j2k->m_procedure_list,(opj_procedure)opj_j2k_write_tlm );
 
                 if (p_j2k->m_cp.m_specific_param.m_enc.m_cinema == OPJ_CINEMA4K_24) {
@@ -9401,7 +9768,7 @@ OPJ_BOOL opj_j2k_write_first_tile_part (opj_j2k_t *p_j2k,
                                                                         opj_stream_private_t *p_stream,
                                                                         struct opj_event_mgr * p_manager )
 {
-        OPJ_UINT32 compno;
+//        OPJ_UINT32 compno;
         OPJ_UINT32 l_nb_bytes_written = 0;
         OPJ_UINT32 l_current_nb_bytes_written;
         OPJ_BYTE * l_begin_data = 00;
@@ -9432,19 +9799,19 @@ OPJ_BOOL opj_j2k_write_first_tile_part (opj_j2k_t *p_j2k,
         p_total_data_size -= l_current_nb_bytes_written;
 
         if (l_cp->m_specific_param.m_enc.m_cinema == 0) {
-                for (compno = 1; compno < p_j2k->m_private_image->numcomps; compno++) {
-                        l_current_nb_bytes_written = 0;
-                        opj_j2k_write_coc_in_memory(p_j2k,compno,p_data,&l_current_nb_bytes_written,p_manager);
-                        l_nb_bytes_written += l_current_nb_bytes_written;
-                        p_data += l_current_nb_bytes_written;
-                        p_total_data_size -= l_current_nb_bytes_written;
-
-                        l_current_nb_bytes_written = 0;
-                        opj_j2k_write_qcc_in_memory(p_j2k,compno,p_data,&l_current_nb_bytes_written,p_manager);
-                        l_nb_bytes_written += l_current_nb_bytes_written;
-                        p_data += l_current_nb_bytes_written;
-                        p_total_data_size -= l_current_nb_bytes_written;
-                }
+//                for (compno = 1; compno < p_j2k->m_private_image->numcomps; compno++) {
+//                        l_current_nb_bytes_written = 0;
+//                        opj_j2k_write_coc_in_memory(p_j2k,compno,p_data,&l_current_nb_bytes_written,p_manager);
+//                        l_nb_bytes_written += l_current_nb_bytes_written;
+//                        p_data += l_current_nb_bytes_written;
+//                        p_total_data_size -= l_current_nb_bytes_written;
+
+//                        l_current_nb_bytes_written = 0;
+//                        opj_j2k_write_qcc_in_memory(p_j2k,compno,p_data,&l_current_nb_bytes_written,p_manager);
+//                        l_nb_bytes_written += l_current_nb_bytes_written;
+//                        p_data += l_current_nb_bytes_written;
+//                        p_total_data_size -= l_current_nb_bytes_written;
+//                }
 
                 if (l_cp->tcps[p_j2k->m_current_tile_number].numpocs) {
                         l_current_nb_bytes_written = 0;
@@ -9500,6 +9867,8 @@ OPJ_BOOL opj_j2k_write_all_tile_parts(  opj_j2k_t *p_j2k,
         /*Get number of tile parts*/
         tot_num_tp = opj_j2k_get_num_tp(l_cp,0,p_j2k->m_current_tile_number);
 
+        /* start writing remaining tile parts */
+        ++p_j2k->m_specific_param.m_encoder.m_current_tile_part_number;
         for (tilepartno = 1; tilepartno < tot_num_tp ; ++tilepartno) {
                 p_j2k->m_specific_param.m_encoder.m_current_poc_tile_part_number = tilepartno;
                 l_current_nb_bytes_written = 0;
@@ -9513,7 +9882,7 @@ OPJ_BOOL opj_j2k_write_all_tile_parts(  opj_j2k_t *p_j2k,
                 l_nb_bytes_written += l_current_nb_bytes_written;
                 p_data += l_current_nb_bytes_written;
                 p_total_data_size -= l_current_nb_bytes_written;
-                l_part_tile_size += l_nb_bytes_written;
+                l_part_tile_size += l_current_nb_bytes_written;
 
                 l_current_nb_bytes_written = 0;
                 if (! opj_j2k_write_sod(p_j2k,l_tcd,p_data,&l_current_nb_bytes_written,p_total_data_size,p_stream,p_manager)) {
@@ -9523,7 +9892,7 @@ OPJ_BOOL opj_j2k_write_all_tile_parts(  opj_j2k_t *p_j2k,
                 p_data += l_current_nb_bytes_written;
                 l_nb_bytes_written += l_current_nb_bytes_written;
                 p_total_data_size -= l_current_nb_bytes_written;
-                l_part_tile_size += l_nb_bytes_written;
+                l_part_tile_size += l_current_nb_bytes_written;
 
                 /* Writing Psot in SOT marker */
                 opj_write_bytes(l_begin_data + 6,l_part_tile_size,4);                                   /* PSOT */