Пример #1
0
int _jxr_r_TILE_DC(jxr_image_t image, struct rbitstream*str,
                   unsigned tx, unsigned ty)
{
    unsigned mx, my;
    unsigned mb_height;
    unsigned mb_width;
    unsigned char s0, s1, s2, s3;
    DEBUG("START TILE_DC at tile=[%u %u] bitpos=%zu\n", tx, ty, _jxr_rbitstream_bitpos(str));

    /* TILE_STARTCODE == 1 */
    s0 = _jxr_rbitstream_uint8(str); /* 0x00 */
    s1 = _jxr_rbitstream_uint8(str); /* 0x00 */
    s2 = _jxr_rbitstream_uint8(str); /* 0x01 */
    s3 = _jxr_rbitstream_uint8(str); /* reserved */
    DEBUG(" TILE_STARTCODE == %02x %02x %02x (reserved: %02x)\n", s0, s1, s2, s3);

    _jxr_r_TILE_HEADER_DC(image, str, 0 /* alpha */, tx, ty);
    if (ALPHACHANNEL_FLAG(image))
        _jxr_r_TILE_HEADER_DC(image->alpha, str, 1, tx, ty);


    /* Now form and write out all the compressed data for the
    tile. This involves scanning the macroblocks, and the
    blocks within the macroblocks, generating bits as we go. */

    mb_height = EXTENDED_HEIGHT_BLOCKS(image);
    mb_width = EXTENDED_WIDTH_BLOCKS(image);

    if (TILING_FLAG(image)) {
        mb_height = image->tile_row_height[ty];
        mb_width = image->tile_column_width[tx];
    }

    for (my = 0 ; my < mb_height ; my += 1) {
        _jxr_r_rotate_mb_strip(image);
        image->cur_my = my;
        for (mx = 0 ; mx < mb_width ; mx += 1) {
            _jxr_r_MB_DC(image, str, 0, tx, ty, mx, my);
            if (image->bands_present == 3 /* DCONLY */)
                _jxr_complete_cur_dclp(image, tx, mx, my);
            if (ALPHACHANNEL_FLAG(image)) {
                _jxr_r_MB_DC(image->alpha, str, 1, tx, ty, mx, my);
                if (image->alpha->bands_present == 3 /* DCONLY */)
                    _jxr_complete_cur_dclp(image->alpha, tx, mx, my);
            }
        }
        
        if (ALPHACHANNEL_FLAG(image))
            backup_dc_strip(image->alpha, tx, ty, my);

        backup_dc_strip(image, tx, ty, my);
    }

    _jxr_rbitstream_syncbyte(str);
    DEBUG("END TILE_DC\n");

    return 0;
}
Пример #2
0
void _jxr_w_TILE_HP_FLEX(jxr_image_t image, struct wbitstream*str,
                         unsigned tx, unsigned ty)
{
    DEBUG("START TILE_HP_FLEX at tile=[%u %u] bitpos=%zu\n", tx, ty, _jxr_wbitstream_bitpos(str));

    uint8_t bands_present = image->bands_present_of_primary;

    struct wbitstream strFP;
    FILE*fdFP = fopen("fp.tmp", "wb");
    _jxr_wbitstream_initialize(&strFP, fdFP);

    if (bands_present < 2 /* HIGHPASS */) {
        /* TILE_STARTCODE == 1 */
        DEBUG(" HP_TILE_STARTCODE at bitpos=%zu\n", _jxr_wbitstream_bitpos(str));
        _jxr_wbitstream_uint8(str, 0x00);
        _jxr_wbitstream_uint8(str, 0x00);
        _jxr_wbitstream_uint8(str, 0x01);
        _jxr_wbitstream_uint8(str, 0x00); /* ARBITRARY_BYTE */

        _jxr_w_TILE_HEADER_HIGHPASS(image, str, 0, tx, ty);
        if (ALPHACHANNEL_FLAG(image)) {
                _jxr_w_TILE_HEADER_HIGHPASS(image->alpha, str, 1, tx, ty);
        }
    }

    if (bands_present == 0 /* ALL */) {
        /* TILE_STARTCODE == 1 */
        DEBUG(" FLEX_TILE_STARTCODE at bitpos=%zu\n", _jxr_wbitstream_bitpos(&strFP));
        _jxr_wbitstream_uint8(&strFP, 0x00);
        _jxr_wbitstream_uint8(&strFP, 0x00);
        _jxr_wbitstream_uint8(&strFP, 0x01);
        _jxr_wbitstream_uint8(&strFP, 0x00); /* ARBITRARY_BYTE */

        if (TRIM_FLEXBITS_FLAG(image)) {
            _jxr_wbitstream_uint4(&strFP, image->trim_flexbits);
        }
    }

    /* Now form and write out all the compressed data for the
    tile. This involves scanning the macroblocks, and the
    blocks within the macroblocks, generating bits as we go. */

    unsigned mb_height = EXTENDED_HEIGHT_BLOCKS(image);
    unsigned mb_width = EXTENDED_WIDTH_BLOCKS(image);

    if (TILING_FLAG(image)) {
        mb_height = image->tile_row_height[ty];
        mb_width = image->tile_column_width[tx];
    }

    DEBUG(" TILE_HP_FLEX at [%d %d] is %u x %u MBs\n", tx, ty, mb_width, mb_height);
    unsigned mx, my;
    for (my = 0 ; my < mb_height ; my += 1) {

        _jxr_wflush_mb_strip(image, tx, ty, my, 0);

        for (mx = 0 ; mx < mb_width ; mx += 1) {

            if (bands_present<2 /* HIGHPASS */) {
                if (image->num_hp_qps>1 && !image->hp_use_lp_qp) {
                    unsigned qp_index = _jxr_select_hp_index(image, tx,ty,mx,my);
                    DEBUG(" DECODE_QP_INDEX(%d) --> %u\n", image->num_hp_qps, qp_index);
                    _jxr_w_ENCODE_QP_INDEX(image, str, tx, ty, mx, my, image->num_hp_qps, qp_index);
                }

                _jxr_w_MB_CBP(image, str, 0 /* IsCurrPlaneAlphaFlag = FALSE */, tx, ty, mx, my);
                if (bands_present == 0 /* ALL */) {
                    _jxr_w_MB_HP(image, str, 0 /* IsCurrPlaneAlphaFlag = FALSE */, tx, ty, mx, my, &strFP);
                }
                else {
                    _jxr_w_MB_HP(image, str, 0 /* IsCurrPlaneAlphaFlag = FALSE */, tx, ty, mx, my, 0);
                }

                if (ALPHACHANNEL_FLAG(image)) {
                    _jxr_w_MB_CBP(image->alpha, str, 1 /* IsCurrPlaneAlphaFlag = TRUE */, tx, ty, mx, my);
                    if (bands_present == 0 /* ALL */) {
                        _jxr_w_MB_HP(image->alpha, str, 1 /* IsCurrPlaneAlphaFlag = TRUE */, tx, ty, mx, my, &strFP);
                    }
                    else {
                        _jxr_w_MB_HP(image->alpha, str, 1 /* IsCurrPlaneAlphaFlag = TRUE */, tx, ty, mx, my, 0);
                    }
                }
            }
        }
    }

    unsigned tile_idx = ty * image->tile_columns + tx;

    _jxr_wbitstream_syncbyte(str);
    _jxr_wbitstream_flush(str);
    image->tile_index_table[tile_idx * (4 - bands_present) + 2] = str->write_count;

    _jxr_wbitstream_syncbyte(&strFP);
    _jxr_wbitstream_flush(&strFP);
    fclose(fdFP);
    if (bands_present == 0 /* ALL */) {
        struct rbitstream strFPRead;
        FILE*fdFPRead = fopen("fp.tmp", "rb");
        _jxr_rbitstream_initialize(&strFPRead, fdFPRead);

        size_t idx;
        for (idx = 0; idx < strFP.write_count; idx++) {
            _jxr_wbitstream_uint8(str, _jxr_rbitstream_uint8(&strFPRead));
        }
        fclose(fdFPRead);
        _jxr_wbitstream_flush(str);
        image->tile_index_table[tile_idx * (4 - bands_present) + 3] = str->write_count;
    }
    /* delete file associated with CodedTiles */
    remove("fp.tmp");

    _jxr_wbitstream_flush(str);
    DEBUG("END TILE_HP_FLEX\n");
}
int _jxr_r_TILE_FLEXBITS(jxr_image_t image, struct rbitstream*str,
                         unsigned tx, unsigned ty)
{
    DEBUG("START TILE_FLEXBITS at tile=[%u %u] bitpos=%zu\n", tx, ty, _jxr_rbitstream_bitpos(str));

    /* TILE_STARTCODE == 1 */
    unsigned char s0, s1, s2, s3;
    s0 = _jxr_rbitstream_uint8(str); /* 0x00 */
    s1 = _jxr_rbitstream_uint8(str); /* 0x00 */
    s2 = _jxr_rbitstream_uint8(str); /* 0x01 */
    s3 = _jxr_rbitstream_uint8(str); /* reserved */
    DEBUG(" TILE_STARTCODE == %02x %02x %02x (reserved: %02x)\n", s0, s1, s2, s3);
    if (s0 != 0x00 || s1 != 0x00 || s2 != 0x01) {
        DEBUG(" TILE_FLEXBITS ERROR: Invalid marker.\n");
        return JXR_EC_ERROR;
    }

    image->trim_flexbits = 0;
    if (TRIM_FLEXBITS_FLAG(image)) {
        image->trim_flexbits =_jxr_rbitstream_uint4(str);
        DEBUG(" TRIM_FLEXBITS = %u\n", image->trim_flexbits);
    }

    int use_num_channels = image->num_channels;
    if (image->use_clr_fmt == 1/*YUV420*/ || image->use_clr_fmt == 2/*YUV422*/)
        use_num_channels = 1;

    /* Now form and write out all the compressed data for the
    tile. This involves scanning the macroblocks, and the
    blocks within the macroblocks, generating bits as we go. */

    unsigned mb_height = EXTENDED_HEIGHT_BLOCKS(image);
    unsigned mb_width = EXTENDED_WIDTH_BLOCKS(image);

    if (TILING_FLAG(image)) {
        mb_height = image->tile_row_height[ty];
        mb_width = image->tile_column_width[tx];
    }

    int mx, my;
    int plane_idx, num_planes = ((ALPHACHANNEL_FLAG(image)) ? 2 : 1);
    for (my = 0 ; my < (int) mb_height ; my += 1) {
        _jxr_r_rotate_mb_strip(image);
        if (ALPHACHANNEL_FLAG(image)) {
            image->alpha->cur_my = my;
            recover_dclphp_strip(image->alpha, tx, ty, my);
        }
        image->cur_my = my;
        recover_dclphp_strip(image, tx, ty, my);

        for (mx = 0 ; mx < (int) mb_width ; mx += 1) 
        for (plane_idx = 0; plane_idx < num_planes; plane_idx ++) {
            jxr_image_t plane = (plane_idx == 0 ? image : image->alpha);
            int channels = (plane_idx == 0 ? use_num_channels : 1);
            int rc = _jxr_r_MB_FLEXBITS(plane, str, 0, tx, ty, mx, my);
            if (rc < 0) {
                DEBUG("r_MB_FLEXBITS returned ERROR rc=%d\n", rc);
                return rc;
            }

            /* Now the HP values are complete, so run the propagation
            process. This involves recovering some bits of data saved
            by the HP tile. */
            int mbhp_pred_mode = MACROBLK_CUR(plane,0,tx,mx).mbhp_pred_mode;
            int idx;
            for (idx = 0 ; idx < channels ; idx += 1) {
                DEBUG(" MB_FLEXBITS: propagate HP predictions in MB_FLEXBITS\n");
                _jxr_propagate_hp_predictions(plane, idx, tx, mx, mbhp_pred_mode);
            }
        }
        if (ALPHACHANNEL_FLAG(image))
            backup_hp_strip(image->alpha, tx, ty, my);
        backup_hp_strip(image, tx, ty, my);
    }

    _jxr_rbitstream_syncbyte(str);
    DEBUG("END TILE_FLEXBITS bitpos=%zu\n", _jxr_rbitstream_bitpos(str));
    return 0;
}
int _jxr_r_TILE_HP(jxr_image_t image, struct rbitstream*str,
                   unsigned tx, unsigned ty)
{
    DEBUG("START TILE_HIGHPASS at tile=[%u %u] bitpos=%zu\n", tx, ty, _jxr_rbitstream_bitpos(str));

    /* TILE_STARTCODE == 1 */
    unsigned char s0, s1, s2, s3;
    s0 = _jxr_rbitstream_uint8(str); /* 0x00 */
    s1 = _jxr_rbitstream_uint8(str); /* 0x00 */
    s2 = _jxr_rbitstream_uint8(str); /* 0x01 */
    s3 = _jxr_rbitstream_uint8(str); /* reserved */
    DEBUG(" TILE_STARTCODE == %02x %02x %02x (reserved: %02x)\n", s0, s1, s2, s3);
    if (s0 != 0x00 || s1 != 0x00 || s2 != 0x01) {
        DEBUG(" TILE_HIGHPASS ERROR: Invalid marker.\n");
        return JXR_EC_ERROR;
    }

    _jxr_r_TILE_HEADER_HIGHPASS(image, str, 0 /* alpha */, tx, ty);
    if (ALPHACHANNEL_FLAG(image))
        _jxr_r_TILE_HEADER_HIGHPASS(image->alpha, str, 1, tx, ty);

    /* Now form and write out all the compressed data for the
    tile. This involves scanning the macroblocks, and the
    blocks within the macroblocks, generating bits as we go. */

    unsigned mb_height = EXTENDED_HEIGHT_BLOCKS(image);
    unsigned mb_width = EXTENDED_WIDTH_BLOCKS(image);

    if (TILING_FLAG(image)) {
        mb_height = image->tile_row_height[ty];
        mb_width = image->tile_column_width[tx];
    }

    unsigned mx, my;
    unsigned plane_idx, num_planes = ((ALPHACHANNEL_FLAG(image)) ? 2 : 1);
    for (my = 0 ; my < mb_height ; my += 1) {
        _jxr_r_rotate_mb_strip(image);

        if (ALPHACHANNEL_FLAG(image)) {
            image->alpha->cur_my = my;
            recover_dclp_strip(image->alpha, tx, ty, my);
        }
        image->cur_my = my;
        recover_dclp_strip(image, tx, ty, my);

        for (mx = 0 ; mx < mb_width ; mx += 1) 
        for (plane_idx = 0; plane_idx < num_planes; plane_idx ++) {
            /* The qp_index_hp table goes only into channel 0 */
            int qp_index_hp = 0;
            jxr_image_t plane = (plane_idx == 0 ? image : image->alpha);
            if (plane->num_hp_qps>1) {
                if (!plane->hp_use_lp_qp)
                    qp_index_hp = _jxr_DECODE_QP_INDEX(str, plane->num_hp_qps);
                else
                    qp_index_hp = MACROBLK_CUR_LP_QUANT(plane,0,tx,mx);
            }
            DEBUG(" HP_QP_INDEX for MBx=%d is %d\n", mx, qp_index_hp);
            int ch;
            for (ch = 0 ; ch < plane->num_channels ; ch += 1) {
                MACROBLK_CUR_HP_QUANT(plane,ch,tx,mx) = plane->hp_quant_ch[ch][qp_index_hp];
                DEBUG(" HP_QUANT for MBx=%d ch=%d is %d\n", mx, ch, MACROBLK_CUR_HP_QUANT(plane,ch,tx,mx));
            }

            int rc = _jxr_r_MB_CBP(plane, str, 0, tx, ty, mx, my);
            if (rc < 0) {
                DEBUG("r_MB_CBP returned ERROR rc=%d\n", rc);
                return rc;
            }
            rc = _jxr_r_MB_HP(plane, str, 0, tx, ty, mx, my);
            if (rc < 0) {
                DEBUG("r_MB_HP returned ERROR rc=%d\n", rc);
                return rc;
            }
        }
        if (ALPHACHANNEL_FLAG(image))
            backup_hp_strip(image->alpha, tx, ty, my);
        backup_hp_strip(image, tx, ty, my);
    }

    _jxr_rbitstream_syncbyte(str);
    DEBUG("END TILE_HIGHPASS\n");
    return 0;
}
Пример #5
0
/*
* Process a single spatial time. The tx/ty is the coordintes of the
* tile in units of tiles. tx=0 for the first time, tx=1 for the
* second, and so forth.
*/
int _jxr_r_TILE_SPATIAL(jxr_image_t image, struct rbitstream*str,
                        unsigned tx, unsigned ty)
{
    int rc = 0;
    DEBUG("START TILE_SPATIAL at tile=[%u %u] bitpos=%zu\n", tx, ty, _jxr_rbitstream_bitpos(str));

    /* TILE_STARTCODE == 1 */
    unsigned char s0, s1, s2, s3;
    s0 = _jxr_rbitstream_uint8(str); /* 0x00 */
    s1 = _jxr_rbitstream_uint8(str); /* 0x00 */
    s2 = _jxr_rbitstream_uint8(str); /* 0x01 */
    s3 = _jxr_rbitstream_uint8(str); /* reserved */
    DEBUG(" TILE_STARTCODE == %02x %02x %02x (reserved: %02x)\n", s0, s1, s2, s3);

    image->trim_flexbits = 0;
    if (TRIM_FLEXBITS_FLAG(image)) {
        image->trim_flexbits =_jxr_rbitstream_uint4(str);
        DEBUG(" TRIM_FLEXBITS = %u\n", image->trim_flexbits);
    }

    /* Read the tile header (which includes sub-headers for
    all the major passes). */

    _jxr_r_TILE_HEADER_DC(image, str, 0, tx, ty);
    if (image->bands_present != 3 /* DCONLY */) {
        _jxr_r_TILE_HEADER_LOWPASS(image, str, 0, tx, ty);

        if (image->bands_present != 2 /* NO_HIGHPASS */) {
            _jxr_r_TILE_HEADER_HIGHPASS(image, str, 0, tx, ty);
        }
    }

    /* If the alpha channel is present, then run another set of
    headers for the alpha channel. */
    if (ALPHACHANNEL_FLAG(image)) {
        _jxr_r_TILE_HEADER_DC(image->alpha, str, 1, tx, ty);
        if (image->bands_present != 3 /* DCONLY */) {
            _jxr_r_TILE_HEADER_LOWPASS(image->alpha, str, 1, tx, ty);

            if (image->bands_present != 2 /* NO_HIGHPASS */) {
                _jxr_r_TILE_HEADER_HIGHPASS(image->alpha, str, 1, tx, ty);
            }
        }
    }


    /* Now form and write out all the compressed data for the
    tile. This involves scanning the macroblocks, and the
    blocks within the macroblocks, generating bits as we go. */

    unsigned mb_height = EXTENDED_HEIGHT_BLOCKS(image);
    unsigned mb_width = EXTENDED_WIDTH_BLOCKS(image);

    if (TILING_FLAG(image)) {
        mb_height = image->tile_row_height[ty];
        mb_width = image->tile_column_width[tx];
    }

    unsigned mx, my, plane_idx;
    for (my = 0 ; my < mb_height ; my += 1) {
        if (ALPHACHANNEL_FLAG(image))
            _jxr_rflush_mb_strip(image->alpha, tx, ty, my);
        _jxr_rflush_mb_strip(image, tx, ty, my);

        for (mx = 0 ; mx < mb_width ; mx += 1) {
        for(plane_idx = 0U; plane_idx < (ALPHACHANNEL_FLAG(image) ? 2U : 1U); plane_idx ++){
            int ch;

            /* There is one LP_QP_INDEX per macroblock (if any)
            and that value applies to all the channels.
            Same for HP_QP_INDEX. There is no DC_QP_INDEX
            because DC QP values are per-tile, not per MB. */
            int qp_index_lp = 0;
            int qp_index_hp = 0;
            jxr_image_t plane = (plane_idx == 0 ? image : image->alpha);

            if (plane->bands_present!=3) {
                if (plane->num_lp_qps>1 && !plane->lp_use_dc_qp) {
                    qp_index_lp = _jxr_DECODE_QP_INDEX(str, plane->num_lp_qps);
                    DEBUG(" DECODE_QP_INDEX(%d) --> %u (LP)\n", plane->num_lp_qps, qp_index_lp);
                }
                qp_index_hp = 0;
                if (plane->bands_present!=2 && plane->num_hp_qps>1) {
                    if (!plane->hp_use_lp_qp) {
                        qp_index_hp = _jxr_DECODE_QP_INDEX(str, plane->num_hp_qps);
                        DEBUG(" DECODE_QP_INDEX(%d) --> %u (HP)\n", plane->num_hp_qps, qp_index_hp);
                    }
                    else {
                        qp_index_hp = qp_index_lp;
                    }
                }
            }
            for (ch = 0 ; ch < plane->num_channels ; ch += 1) {
                /* Save the LP Quant *INDEX* here. Prediction needs it. */
                MACROBLK_CUR_LP_QUANT(plane,ch,tx,mx) = qp_index_lp;
                DEBUG(" LP_QUANT INDEX for tx=%u ty=%u ch=%u MBx=%d is %d\n", tx, ty, ch, mx,
                    MACROBLK_CUR_LP_QUANT(plane,ch,tx,mx));
                MACROBLK_CUR_HP_QUANT(plane,ch,tx,mx) = plane->hp_quant_ch[ch][qp_index_hp];
                DEBUG(" HP_QUANT VALUE for tx=%u ty=%u ch=%u MBx=%d is %d\n", tx, ty, ch, mx,
                    MACROBLK_CUR_HP_QUANT(plane,ch,tx,mx));
            }

            _jxr_r_MB_DC(plane, str, plane_idx, tx, ty, mx, my);
            if (plane->bands_present != 3 /* DCONLY */) {
                _jxr_r_MB_LP(plane, str, plane_idx, tx, ty, mx, my);
                _jxr_complete_cur_dclp(plane, tx, mx, my);
                if (plane->bands_present != 2 /* NOHIGHPASS */) {
                    rc = _jxr_r_MB_CBP(plane, str, plane_idx, tx, ty, mx, my);
                    if (rc < 0) {
                        DEBUG("r_MB_CBP returned ERROR rc=%d\n", rc);
                        return rc;
                    }
                    rc = _jxr_r_MB_HP(plane, str, plane_idx, tx, ty, mx, my);
                    if (rc < 0) {
                        DEBUG("r_MB_HP returned ERROR rc=%d\n", rc);
                        return rc;
                    }
                }
            } else {
                _jxr_complete_cur_dclp(plane, tx, mx, my);
            }
        }
    }
    }

    /* Flush the remaining strips to output. */
    if (tx+1 == image->tile_columns && ty+1 == image->tile_rows) {
        DEBUG(" Cleanup flush after last tile (tx=%d, ty=%d)\n", tx, ty);
        if (ALPHACHANNEL_FLAG(image))
            _jxr_rflush_mb_strip(image->alpha, tx, ty, mb_height);
        _jxr_rflush_mb_strip(image, tx, ty, mb_height);

        if (ALPHACHANNEL_FLAG(image))
            _jxr_rflush_mb_strip(image->alpha, tx, ty, mb_height+1);
        _jxr_rflush_mb_strip(image, tx, ty, mb_height+1);

        if (ALPHACHANNEL_FLAG(image))
            _jxr_rflush_mb_strip(image->alpha, tx, ty, mb_height+2);
        _jxr_rflush_mb_strip(image, tx, ty, mb_height+2);

        if (ALPHACHANNEL_FLAG(image))
            _jxr_rflush_mb_strip(image->alpha, tx, ty, mb_height+3);
        _jxr_rflush_mb_strip(image, tx, ty, mb_height+3);
    }
    _jxr_rbitstream_syncbyte(str);
    DEBUG("END TILE_SPATIAL\n");
    return 0;
}
/*
** Added by thor April 2nd 2010: Process one stripe at a time.
*/
int _jxr_r_TILE_SPATIAL_stripe(jxr_image_t image, struct rbitstream*str,
			       unsigned tx, unsigned ty)
{
  int rc = 0;

  if (image->spatial_buffered_flag == 0) {
    /* Header is not yet parsed off. Do now.
     */
    DEBUG("START TILE_SPATIAL at tile=[%u %u] bitpos=%zu\n", tx, ty, _jxr_rbitstream_bitpos(str));
    
    if(INDEXTABLE_PRESENT_FLAG(image)) {
      _jxr_rbitstream_seek(str, image->tile_index_table[image->tile_columns * ty + tx]);
    }
    /* TILE_STARTCODE == 1 */
    unsigned char s0, s1, s2, s3;
    s0 = _jxr_rbitstream_uint8(str); /* 0x00 */
    s1 = _jxr_rbitstream_uint8(str); /* 0x00 */
    s2 = _jxr_rbitstream_uint8(str); /* 0x01 */
    s3 = _jxr_rbitstream_uint8(str); /* reserved */
    DEBUG(" TILE_STARTCODE == %02x %02x %02x (reserved: %02x)\n", s0, s1, s2, s3);
    if (s0 != 0x00 || s1 != 0x00 || s2 != 0x01) {
      DEBUG(" TILE_LOWPASS ERROR: Invalid marker.\n");
      return JXR_EC_ERROR;
      /* FIX THOR: Invalid TILE_STARTCODE detected */
    }
    
    image->trim_flexbits = 0;
    if (TRIM_FLEXBITS_FLAG(image)) {
      image->trim_flexbits =_jxr_rbitstream_uint4(str);
      DEBUG(" TRIM_FLEXBITS = %u\n", image->trim_flexbits);
    }
    
    /* Read the tile header (which includes sub-headers for
       all the major passes). */
    
    _jxr_r_TILE_HEADER_DC(image, str, 0, tx, ty);
    if (image->bands_present != 3 /* DCONLY */) {
      _jxr_r_TILE_HEADER_LOWPASS(image, str, 0, tx, ty);
      
      if (image->bands_present != 2 /* NO_HIGHPASS */) {
	_jxr_r_TILE_HEADER_HIGHPASS(image, str, 0, tx, ty);
      }
    }

    /* If the alpha channel is present, then run another set of
    headers for the alpha channel. */
    if (ALPHACHANNEL_FLAG(image)) {
      _jxr_r_TILE_HEADER_DC(image->alpha, str, 1, tx, ty);
      if (image->bands_present != 3 /* DCONLY */) {
	_jxr_r_TILE_HEADER_LOWPASS(image->alpha, str, 1, tx, ty);
	
	if (image->bands_present != 2 /* NO_HIGHPASS */) {
	  _jxr_r_TILE_HEADER_HIGHPASS(image->alpha, str, 1, tx, ty);
	}
      }
    }


    /* Now form and write out all the compressed data for the
    tile. This involves scanning the macroblocks, and the
    blocks within the macroblocks, generating bits as we go. */
    {
      unsigned mb_height = EXTENDED_HEIGHT_BLOCKS(image);
      unsigned mb_width = EXTENDED_WIDTH_BLOCKS(image);
      
      if (TILING_FLAG(image)) {
        mb_height = image->tile_row_height[ty];
        mb_width = image->tile_column_width[tx];
      }
      
      image->spatial_mb_height = mb_height;
      image->spatial_mb_width  = mb_width;
    }
    /*
    ** Done with the header. Initialize for the loop below.
    */
    image->spatial_buffered_flag = 1;
    image->stripe_my             = 0;
    image->cleanup_state         = 0;
    image->output_sent           = 0;
    // runs into the following.
  }

  switch(image->cleanup_state) {
  case 0:
    do {
      unsigned mx, plane_idx, my = image->stripe_my;
      unsigned mb_width = image->spatial_mb_width;
      /*
	for (my = 0 ; my < mb_height ; my += 1) {
      */
      if (ALPHACHANNEL_FLAG(image))
	_jxr_rflush_mb_strip(image->alpha, tx, ty, my);
      _jxr_rflush_mb_strip(image, tx, ty, my);
      
      for (mx = 0 ; mx < mb_width ; mx += 1) {
	for(plane_idx = 0U; plane_idx < (ALPHACHANNEL_FLAG(image) ? 2U : 1U); plane_idx ++){
	  int ch;
	  
	  /* There is one LP_QP_INDEX per macroblock (if any)
	     and that value applies to all the channels.
	     Same for HP_QP_INDEX. There is no DC_QP_INDEX
	     because DC QP values are per-tile, not per MB. */
	  int qp_index_lp = 0;
	  int qp_index_hp = 0;
	  jxr_image_t plane = (plane_idx == 0 ? image : image->alpha);
	  
	  if (plane->bands_present!=3) {
	    if (plane->num_lp_qps>1 && !plane->lp_use_dc_qp) {
	      qp_index_lp = _jxr_DECODE_QP_INDEX(str, plane->num_lp_qps);
	      DEBUG(" DECODE_QP_INDEX(%d) --> %u (LP)\n", plane->num_lp_qps, qp_index_lp);
	    }
	    qp_index_hp = 0;
	    if (plane->bands_present!=2 && plane->num_hp_qps>1) {
	      if (!plane->hp_use_lp_qp) {
		qp_index_hp = _jxr_DECODE_QP_INDEX(str, plane->num_hp_qps);
		DEBUG(" DECODE_QP_INDEX(%d) --> %u (HP)\n", plane->num_hp_qps, qp_index_hp);
	      }
	      else {
		qp_index_hp = qp_index_lp;
	      }
	    }
	  }
	  for (ch = 0 ; ch < plane->num_channels ; ch += 1) {
	    /* Save the LP Quant *INDEX* here. Prediction needs it. */
	    MACROBLK_CUR_LP_QUANT(plane,ch,tx,mx) = qp_index_lp;
	    DEBUG(" LP_QUANT INDEX for tx=%u ty=%u ch=%u MBx=%d is %d\n", tx, ty, ch, mx,
		  MACROBLK_CUR_LP_QUANT(plane,ch,tx,mx));
	    MACROBLK_CUR_HP_QUANT(plane,ch,tx,mx) = plane->hp_quant_ch[ch][qp_index_hp];
	    DEBUG(" HP_QUANT VALUE for tx=%u ty=%u ch=%u MBx=%d is %d\n", tx, ty, ch, mx,
		  MACROBLK_CUR_HP_QUANT(plane,ch,tx,mx));
	  }
	  
	  _jxr_r_MB_DC(plane, str, plane_idx, tx, ty, mx, my);
	  if (plane->bands_present != 3 /* DCONLY */) {
	    _jxr_r_MB_LP(plane, str, plane_idx, tx, ty, mx, my);
	    _jxr_complete_cur_dclp(plane, tx, mx, my);
	    if (plane->bands_present != 2 /* NOHIGHPASS */) {
	      rc = _jxr_r_MB_CBP(plane, str, plane_idx, tx, ty, mx, my);
	      if (rc < 0) {
		DEBUG("r_MB_CBP returned ERROR rc=%d\n", rc);
		return rc;
	      }
	      rc = _jxr_r_MB_HP(plane, str, plane_idx, tx, ty, mx, my);
	      if (rc < 0) {
		DEBUG("r_MB_HP returned ERROR rc=%d\n", rc);
		return rc;
	      }
	    }
	  } else {
	    _jxr_complete_cur_dclp(plane, tx, mx, my);
	  }
	}
      }
      /*
      ** Advance to the next MB row.
      */
      image->stripe_my++;
      /*
      ** The flush happens only as part of the last tile, so continue iterating
      ** until that tile is hit.
      */
    } while (image->stripe_my < image->spatial_mb_height && image->output_sent == 0);

    /*
    ** End of tile reached? If so, get the sycn marker
    */
    if (image->stripe_my == image->spatial_mb_height)
      _jxr_rbitstream_syncbyte(str);

    /*
    ** If this is an intermediate tile and not the right edge, continue with the next tile.
    */
    if (tx+1 != image->tile_columns) {
      image->spatial_buffered_flag = 0;
      image->stripe_my             = 0;
      return 1;
    }
    /*
    ** Otherwise, a stripe is complete, go to the user.
    */
    if (image->stripe_my < image->spatial_mb_height && image->output_sent) {
      image->output_sent = 0;
      return 0; /* not yet done with this strip, but return to the user. */
    }
    assert(image->stripe_my == image->spatial_mb_height);
    /*
    ** Done with this tile, go to the next. We're done in case this is not the last tile,
    ** otherwise iterate on until we get to the last one.
    */
    if (tx+1 == image->tile_columns && ty+1 == image->tile_rows) {
      // Last tile row. Continue with cleanup.
      image->cleanup_state = 1;
    } else {
      image->spatial_buffered_flag = 0;
      image->stripe_my             = 0;
      return JXR_EC_DONE;
    }
    if (image->output_sent)
      return 0;
    // runs into the following
  case 1:
    /* Flush the remaining strips to output. */
    if (tx+1 == image->tile_columns && ty+1 == image->tile_rows) {
      DEBUG(" Cleanup flush after last tile (tx=%d, ty=%d)\n", tx, ty);
      if (ALPHACHANNEL_FLAG(image))
	_jxr_rflush_mb_strip(image->alpha, tx, ty, image->spatial_mb_height);
      _jxr_rflush_mb_strip(image, tx, ty, image->spatial_mb_height);
      image->cleanup_state++;
      if (image->output_sent) {
	image->output_sent = 0;
	return 0;
      }
    } else {
      return 1;
    }
    // runs into the following
  case 2:
    if (tx+1 == image->tile_columns && ty+1 == image->tile_rows) {
      if (ALPHACHANNEL_FLAG(image))
	_jxr_rflush_mb_strip(image->alpha, tx, ty, image->spatial_mb_height+1);
      _jxr_rflush_mb_strip(image, tx, ty, image->spatial_mb_height+1);
      image->cleanup_state++;
      if (image->output_sent) {
	image->output_sent = 0;
	return 0;
      }
    } else {
      return 1;
    }
    // runs into the following
  case 3:
    if (tx+1 == image->tile_columns && ty+1 == image->tile_rows) {
      if (ALPHACHANNEL_FLAG(image))
	_jxr_rflush_mb_strip(image->alpha, tx, ty, image->spatial_mb_height+2);
      _jxr_rflush_mb_strip(image, tx, ty, image->spatial_mb_height+2);
      image->cleanup_state++;
      if (image->output_sent) {
	image->output_sent = 0;
	return 0;
      }
    } else {
      return 1;
    }
    // runs into the following
  case 4:
    if (tx+1 == image->tile_columns && ty+1 == image->tile_rows) {
      if (ALPHACHANNEL_FLAG(image))
	_jxr_rflush_mb_strip(image->alpha, tx, ty, image->spatial_mb_height+3);
      _jxr_rflush_mb_strip(image, tx, ty, image->spatial_mb_height+3);
      image->cleanup_state++;
       if (image->output_sent) {
	image->output_sent = 0;
	return 0;
      }
    } else {
      return 1;
    }
    // runs into the following
  default:
    image->spatial_buffered_flag = 0;
    image->stripe_my             = 0;
    return JXR_EC_DONE;
  }
}