blob: eb7a5d0dd238af5e3b4365d7728a9bc75190058f [file] [log] [blame]
/*
* Copyright (c) 2001-2002, David Janssens
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "t2.h"
#include "tcd.h"
#include "bio.h"
#include "j2k.h"
#include "pi.h"
#include "tgt.h"
#include "int.h"
#include <memory.h>
#include <stdlib.h>
#include <stdio.h>
#include <setjmp.h>
extern jmp_buf j2k_error;
void t2_putcommacode(int n)
{
while (--n>=0) {
bio_write(1, 1);
}
bio_write(0, 1);
}
int t2_getcommacode() {
int n;
for (n=0; bio_read(1); n++) {}
return n;
}
void t2_putnumpasses(int n)
{
if (n==1) {
bio_write(0, 1);
} else if (n==2) {
bio_write(2, 2);
} else if (n<=5) {
bio_write(0xc|(n-3), 4);
} else if (n<=36) {
bio_write(0x1e0|(n-6), 9);
} else if (n<=164) {
bio_write(0xff80|(n-37), 16);
}
}
int t2_getnumpasses()
{
int n;
if (!bio_read(1)) return 1;
if (!bio_read(1)) return 2;
if ((n=bio_read(2))!=3) return 3+n;
if ((n=bio_read(5))!=31) return 6+n;
return 37+bio_read(7);
}
int t2_encode_packet(tcd_tile_t *tile, j2k_tcp_t *tcp, int compno, int resno, int precno, int layno, unsigned char *dest, int len) {
int bandno, cblkno;
tcd_tilecomp_t *tilec=&tile->comps[compno];
tcd_resolution_t *res=&tilec->resolutions[resno];
unsigned char *c=dest;
if (!layno) {
for (bandno=0; bandno<res->numbands; bandno++) {
tcd_band_t *band=&res->bands[bandno];
tcd_precinct_t *prc=&band->precincts[precno];
tgt_reset(prc->incltree);
tgt_reset(prc->imsbtree);
for (cblkno=0; cblkno<prc->cw*prc->ch; cblkno++) {
tcd_cblk_t *cblk=&prc->cblks[cblkno];
cblk->numpasses=0;
tgt_setvalue(prc->imsbtree, cblkno, band->numbps-cblk->numbps);
}
}
}
bio_init_enc(c, len);
bio_write(1, 1);
for (bandno=0; bandno<res->numbands; bandno++) {
tcd_band_t *band=&res->bands[bandno];
tcd_precinct_t *prc=&band->precincts[precno];
for (cblkno=0; cblkno<prc->cw*prc->ch; cblkno++) {
tcd_cblk_t *cblk=&prc->cblks[cblkno];
tcd_layer_t *layer=&cblk->layers[layno];
if (!cblk->numpasses && layer->numpasses) {
tgt_setvalue(prc->incltree, cblkno, layno);
}
}
for (cblkno=0; cblkno<prc->cw*prc->ch; cblkno++) {
tcd_cblk_t *cblk=&prc->cblks[cblkno];
tcd_layer_t *layer=&cblk->layers[layno];
int increment;
if (!cblk->numpasses) {
tgt_encode(prc->incltree, cblkno, layno+1);
} else {
bio_write(layer->numpasses!=0, 1);
}
if (!layer->numpasses) {
continue;
}
if (!cblk->numpasses) {
cblk->numlenbits=3;
tgt_encode(prc->imsbtree, cblkno, 999);
}
t2_putnumpasses(layer->numpasses);
increment=int_max(0, int_floorlog2(layer->len)+1-(cblk->numlenbits+int_floorlog2(layer->numpasses)));
t2_putcommacode(increment);
cblk->numlenbits+=increment;
bio_write(layer->len, cblk->numlenbits+int_floorlog2(layer->numpasses));
}
}
bio_flush();
c+=bio_numbytes();
for (bandno=0; bandno<res->numbands; bandno++) {
tcd_band_t *band=&res->bands[bandno];
tcd_precinct_t *prc=&band->precincts[precno];
for (cblkno=0; cblkno<prc->cw*prc->ch; cblkno++) {
tcd_cblk_t *cblk=&prc->cblks[cblkno];
tcd_layer_t *layer=&cblk->layers[layno];
if (!layer->numpasses) continue;
if (c+layer->len>dest+len) {
longjmp(j2k_error, 1);
}
memcpy(c, layer->data, layer->len);
cblk->numpasses+=layer->numpasses;
c+=layer->len;
}
}
return c-dest;
}
void t2_init_seg(tcd_seg_t *seg, int cblksty) {
seg->numpasses=0;
seg->len=0;
seg->maxpasses=cblksty&J2K_CCP_CBLKSTY_TERMALL?1:100;
}
int t2_decode_packet(unsigned char *src, int len, tcd_tile_t *tile, j2k_tcp_t *tcp, int compno, int resno, int precno, int layno) {
int bandno, cblkno;
tcd_tilecomp_t *tilec=&tile->comps[compno];
tcd_resolution_t *res=&tilec->resolutions[resno];
unsigned char *c=src;
int present;
if (layno==0) {
for (bandno=0; bandno<res->numbands; bandno++) {
tcd_band_t *band=&res->bands[bandno];
tcd_precinct_t *prc=&band->precincts[precno];
tgt_reset(prc->incltree);
tgt_reset(prc->imsbtree);
for (cblkno=0; cblkno<prc->cw*prc->ch; cblkno++) {
tcd_cblk_t *cblk=&prc->cblks[cblkno];
cblk->numsegs=0;
}
}
}
if (tcp->csty&J2K_CP_CSTY_SOP) {
c+=6;
}
bio_init_dec(c, src+len-c);
present=bio_read(1);
if (!present) {
bio_inalign();
c+=bio_numbytes();
return c-src;
}
for (bandno=0; bandno<res->numbands; bandno++) {
tcd_band_t *band=&res->bands[bandno];
tcd_precinct_t *prc=&band->precincts[precno];
for (cblkno=0; cblkno<prc->cw*prc->ch; cblkno++) {
int included, increment, n;
tcd_cblk_t *cblk=&prc->cblks[cblkno];
tcd_seg_t *seg;
if (!cblk->numsegs) {
included=tgt_decode(prc->incltree, cblkno, layno+1);
} else {
included=bio_read(1);
}
if (!included) {
cblk->numnewpasses=0;
continue;
}
if (!cblk->numsegs) {
int i, numimsbs;
for (i=0; !tgt_decode(prc->imsbtree, cblkno, i); i++) {}
numimsbs=i-1;
cblk->numbps=band->numbps-numimsbs;
cblk->numlenbits=3;
}
cblk->numnewpasses=t2_getnumpasses();
increment=t2_getcommacode();
cblk->numlenbits+=increment;
if (!cblk->numsegs) {
seg=&cblk->segs[0];
t2_init_seg(seg, tcp->tccps[compno].cblksty);
} else {
seg=&cblk->segs[cblk->numsegs-1];
if (seg->numpasses==seg->maxpasses) {
t2_init_seg(++seg, tcp->tccps[compno].cblksty);
}
}
n=cblk->numnewpasses;
do {
seg->numnewpasses=int_min(seg->maxpasses-seg->numpasses, n);
seg->newlen=bio_read(cblk->numlenbits+int_floorlog2(seg->numnewpasses));
n-=seg->numnewpasses;
if (n>0) {
t2_init_seg(++seg, tcp->tccps[compno].cblksty);
}
} while (n>0);
}
}
bio_inalign();
c+=bio_numbytes();
if (tcp->csty&J2K_CP_CSTY_EPH) {
c+=2;
}
for (bandno=0; bandno<res->numbands; bandno++) {
tcd_band_t *band=&res->bands[bandno];
tcd_precinct_t *prc=&band->precincts[precno];
for (cblkno=0; cblkno<prc->cw*prc->ch; cblkno++) {
tcd_cblk_t *cblk=&prc->cblks[cblkno];
tcd_seg_t *seg;
if (!cblk->numnewpasses) continue;
if (!cblk->numsegs) {
seg=&cblk->segs[cblk->numsegs++];
cblk->len=0;
} else {
seg=&cblk->segs[cblk->numsegs-1];
if (seg->numpasses==seg->maxpasses) {
seg++;
cblk->numsegs++;
}
}
do {
if (c+seg->newlen>src+len) longjmp(j2k_error, 1);
memcpy(cblk->data+cblk->len, c, seg->newlen);
if (seg->numpasses==0) {
seg->data=cblk->data+cblk->len;
}
c+=seg->newlen;
cblk->len+=seg->newlen;
seg->len+=seg->newlen;
seg->numpasses+=seg->numnewpasses;
cblk->numnewpasses-=seg->numnewpasses;
if (cblk->numnewpasses>0) {
seg++;
cblk->numsegs++;
}
} while (cblk->numnewpasses>0);
}
}
return c-src;
}
int t2_encode_packets(j2k_image_t *img, j2k_cp_t *cp, int tileno, tcd_tile_t *tile, int maxlayers, unsigned char *dest, int len) {
unsigned char *c=dest;
pi_iterator_t *pi;
pi=pi_create(img, cp, tileno);
while (pi_next(pi)) {
if (pi->layno<maxlayers) {
//fprintf(stderr, "compno=%d, resno=%d, precno=%d, layno=%d\n", pi->compno, pi->resno, pi->precno, pi->layno);
c+=t2_encode_packet(tile, &cp->tcps[tileno], pi->compno, pi->resno, pi->precno, pi->layno, c, dest+len-c);
}
}
pi_destroy(pi);
return c-dest;
}
int t2_decode_packets(unsigned char *src, int len, j2k_image_t *img, j2k_cp_t *cp, int tileno, tcd_tile_t *tile) {
unsigned char *c=src;
pi_iterator_t *pi;
pi=pi_create(img, cp, tileno);
while (pi_next(pi)) {
//fprintf(stderr, "compno=%d, resno=%d, precno=%d, layno=%d\n", pi->compno, pi->resno, pi->precno, pi->layno);
c+=t2_decode_packet(c, src+len-c, tile, &cp->tcps[tileno], pi->compno, pi->resno, pi->precno, pi->layno);
}
pi_destroy(pi);
return c-src;
}