4 * Copyright (c) 2002-2011, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium
5 * Copyright (c) 2002-2011, Professor Benoit Macq
6 * Copyright (c) 2010-2011, Kaori Hagihara
7 * Copyright (c) 2011, Lucian Corlaciu, GSoC
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
35 #include "jpip_parser.h"
36 #include "channel_manager.h"
37 #include "imgreg_manager.h"
40 #include "fcgi_stdio.h"
41 #define logstream FCGI_stdout
43 #define FCGI_stdout stdout
44 #define FCGI_stderr stderr
45 #define logstream stderr
49 bool identify_target( query_param_t query_param, targetlist_param_t *targetlist, target_param_t **target)
51 if( query_param.tid[0] !='\0' && strcmp( query_param.tid, "0") != 0 ){
52 if( query_param.cid[0] != '\0'){
53 fprintf( FCGI_stdout, "Reason: Target can not be specified both through tid and cid\r\n");
54 fprintf( FCGI_stdout, "Status: 400\r\n");
57 if( ( *target = search_targetBytid( query_param.tid, targetlist)))
61 if( query_param.target[0] !='\0')
62 if( !( *target = search_target( query_param.target, targetlist)))
63 if(!( *target = gene_target( targetlist, query_param.target)))
67 fprintf( FCGI_stdout, "JPIP-tid: %s\r\n", (*target)->tid);
71 fprintf( FCGI_stdout, "Reason: target not found\r\n");
72 fprintf( FCGI_stdout, "Status: 400\r\n");
77 bool associate_channel( query_param_t query_param,
78 sessionlist_param_t *sessionlist,
79 session_param_t **cursession,
80 channel_param_t **curchannel)
82 if( search_session_and_channel( query_param.cid, sessionlist, cursession, curchannel)){
84 if( !query_param.cnew)
85 set_channel_variable_param( query_param, *curchannel);
88 fprintf( FCGI_stderr, "Error: process canceled\n");
94 bool open_channel( query_param_t query_param,
95 sessionlist_param_t *sessionlist,
96 target_param_t *target,
97 session_param_t **cursession,
98 channel_param_t **curchannel)
100 cachemodel_param_t *cachemodel = NULL;
104 *cursession = gene_session( sessionlist);
105 if( !( cachemodel = search_cachemodel( target, (*cursession)->cachemodellist)))
106 if( !(cachemodel = gene_cachemodel( (*cursession)->cachemodellist, target, query_param.return_type==JPPstream)))
111 cachemodel = (*curchannel)->cachemodel;
113 *curchannel = gene_channel( query_param, cachemodel, (*cursession)->channellist);
114 if( *curchannel == NULL)
120 bool close_channel( query_param_t query_param,
121 sessionlist_param_t *sessionlist,
122 session_param_t **cursession,
123 channel_param_t **curchannel)
125 if( query_param.cclose[0][0] =='*'){
127 fprintf( logstream, "local log: close all\n");
129 // all channels associatd with the session will be closed
130 if( !delete_session( cursession, sessionlist))
134 // check if all entry belonging to the same session
136 while( query_param.cclose[i][0] !='\0'){
138 // In case of the first entry of close cid
139 if( *cursession == NULL){
140 if( !search_session_and_channel( query_param.cclose[i], sessionlist, cursession, curchannel))
143 else // second or more entry of close cid
144 if( !(*curchannel=search_channel( query_param.cclose[i], (*cursession)->channellist))){
145 fprintf( FCGI_stdout, "Reason: Cclose id %s is from another session\r\n", query_param.cclose[i]);
152 while( query_param.cclose[i][0] !='\0'){
154 *curchannel = search_channel( query_param.cclose[i], (*cursession)->channellist);
155 delete_channel( curchannel, (*cursession)->channellist);
159 if( (*cursession)->channellist->first == NULL || (*cursession)->channellist->last == NULL)
160 // In case of empty session
161 delete_session( cursession, sessionlist);
168 * enqueue tiles or precincts into the message queue
170 * @param[in] query_param structured query
171 * @param[in] msgqueue message queue pointer
173 void enqueue_imagedata( query_param_t query_param, msgqueue_param_t *msgqueue);
176 * enqueue metadata bins into the message queue
178 * @param[in] query_param structured query
179 * @param[in] metadatalist pointer to metadata bin list
180 * @param[in,out] msgqueue message queue pointer
182 void enqueue_metabins( query_param_t query_param, metadatalist_param_t *metadatalist, msgqueue_param_t *msgqueue);
185 bool gene_JPIPstream( query_param_t query_param,
186 target_param_t *target,
187 session_param_t *cursession,
188 channel_param_t *curchannel,
189 msgqueue_param_t **msgqueue)
191 index_param_t *codeidx;
192 cachemodel_param_t *cachemodel;
194 if( !cursession || !curchannel){ // stateless
197 if( !(cachemodel = gene_cachemodel( NULL, target, query_param.return_type==JPPstream)))
199 *msgqueue = gene_msgqueue( true, cachemodel);
202 cachemodel = curchannel->cachemodel;
203 target = cachemodel->target;
204 *msgqueue = gene_msgqueue( false, cachemodel);
207 codeidx = target->codeidx;
209 if( cachemodel->jppstream)
210 fprintf( FCGI_stdout, "Content-type: image/jpp-stream\r\n");
212 fprintf( FCGI_stdout, "Content-type: image/jpt-stream\r\n");
214 if( query_param.layers != -1){
215 if( query_param.layers > codeidx->COD.numOflayers){
216 fprintf( FCGI_stdout, "JPIP-layers: %d\r\n", codeidx->COD.numOflayers);
217 query_param.layers = codeidx->COD.numOflayers;
222 if( query_param.box_type[0][0] != 0 && query_param.len != 0)
223 enqueue_metabins( query_param, codeidx->metadatalist, *msgqueue);
226 if( query_param.fx > 0 && query_param.fy > 0){
227 if( !cachemodel->mhead_model && query_param.len != 0)
228 enqueue_mainheader( *msgqueue);
229 enqueue_imagedata( query_param, *msgqueue);
236 * enqueue precinct data-bins into the queue
238 * @param[in] xmin min x coordinate in the tile at the decomposition level
239 * @param[in] xmax max x coordinate in the tile at the decomposition level
240 * @param[in] ymin min y coordinate in the tile at the decomposition level
241 * @param[in] ymax max y coordinate in the tile at the decomposition level
242 * @param[in] tile_id tile index
243 * @param[in] level decomposition level
244 * @param[in] lastcomp last component number
245 * @param[in] comps pointer to the array that stores the requested components
246 * @param[in] layers number of quality layers
247 * @param[in] msgqueue message queue
250 void enqueue_precincts( int xmin, int xmax, int ymin, int ymax, int tile_id, int level, int lastcomp, bool *comps, int layers, msgqueue_param_t *msgqueue);
253 * enqueue all precincts inside a tile into the queue
255 * @param[in] tile_id tile index
256 * @param[in] level decomposition level
257 * @param[in] lastcomp last component number
258 * @param[in] comps pointer to the array that stores the requested components
259 * @param[in] layers number of quality layers
260 * @param[in] msgqueue message queue
263 void enqueue_allprecincts( int tile_id, int level, int lastcomp, bool *comps, int layers, msgqueue_param_t *msgqueue);
265 void enqueue_imagedata( query_param_t query_param, msgqueue_param_t *msgqueue)
267 index_param_t *codeidx;
268 imgreg_param_t imgreg;
269 range_param_t tile_Xrange, tile_Yrange;
271 int xmin, xmax, ymin, ymax;
274 codeidx = msgqueue->cachemodel->target->codeidx;
276 if( !(msgqueue->cachemodel->jppstream) && get_nmax( codeidx->tilepart) == 1) // normally not the case
279 numOfreslev = codeidx->COD.numOfdecomp+1;
281 imgreg = map_viewin2imgreg( query_param.fx, query_param.fy,
282 query_param.rx, query_param.ry, query_param.rw, query_param.rh,
283 codeidx->SIZ.XOsiz, codeidx->SIZ.YOsiz, codeidx->SIZ.Xsiz, codeidx->SIZ.Ysiz,
286 if( query_param.len == 0)
289 for( u=0, tile_id=0; u<codeidx->SIZ.YTnum; u++){
290 tile_Yrange = get_tile_Yrange( codeidx->SIZ, tile_id, imgreg.level);
292 for( v=0; v<codeidx->SIZ.XTnum; v++, tile_id++){
293 tile_Xrange = get_tile_Xrange( codeidx->SIZ, tile_id, imgreg.level);
295 if( tile_Xrange.minvalue < tile_Xrange.maxvalue && tile_Yrange.minvalue < tile_Yrange.maxvalue){
296 if( tile_Xrange.maxvalue <= imgreg.xosiz + imgreg.ox ||
297 tile_Xrange.minvalue >= imgreg.xosiz + imgreg.ox + imgreg.sx ||
298 tile_Yrange.maxvalue <= imgreg.yosiz + imgreg.oy ||
299 tile_Yrange.minvalue >= imgreg.yosiz + imgreg.oy + imgreg.sy) {
300 //printf("Tile completely excluded from view-window %d\n", tile_id);
301 // Tile completely excluded from view-window
303 else if( tile_Xrange.minvalue >= imgreg.xosiz + imgreg.ox &&
304 tile_Xrange.maxvalue <= imgreg.xosiz + imgreg.ox + imgreg.sx &&
305 tile_Yrange.minvalue >= imgreg.yosiz + imgreg.oy &&
306 tile_Yrange.maxvalue <= imgreg.yosiz + imgreg.oy + imgreg.sy) {
307 // Tile completely contained within view-window
309 //printf("Tile completely contained within view-window %d\n", tile_id);
310 if( msgqueue->cachemodel->jppstream){
311 enqueue_tileheader( tile_id, msgqueue);
312 enqueue_allprecincts( tile_id, imgreg.level, query_param.lastcomp, query_param.comps, query_param.layers, msgqueue);
315 enqueue_tile( tile_id, imgreg.level, msgqueue);
318 // Tile partially overlaps view-window
320 //printf("Tile partially overlaps view-window %d\n", tile_id);
321 if( msgqueue->cachemodel->jppstream){
322 enqueue_tileheader( tile_id, msgqueue);
324 xmin = tile_Xrange.minvalue >= imgreg.xosiz + imgreg.ox ? 0 : imgreg.xosiz + imgreg.ox - tile_Xrange.minvalue;
325 xmax = tile_Xrange.maxvalue <= imgreg.xosiz + imgreg.ox + imgreg.sx ? tile_Xrange.maxvalue - tile_Xrange.minvalue -1 : imgreg.xosiz + imgreg.ox + imgreg.sx - tile_Xrange.minvalue -1;
326 ymin = tile_Yrange.minvalue >= imgreg.yosiz + imgreg.oy ? 0 : imgreg.yosiz + imgreg.oy - tile_Yrange.minvalue;
327 ymax = tile_Yrange.maxvalue <= imgreg.yosiz + imgreg.oy + imgreg.sy ? tile_Yrange.maxvalue - tile_Yrange.minvalue -1 : imgreg.yosiz + imgreg.oy + imgreg.sy - tile_Yrange.minvalue -1;
328 enqueue_precincts( xmin, xmax, ymin, ymax, tile_id, imgreg.level, query_param.lastcomp, query_param.comps, query_param.layers, msgqueue);
331 enqueue_tile( tile_id, imgreg.level, msgqueue);
339 void enqueue_precincts( int xmin, int xmax, int ymin, int ymax, int tile_id, int level, int lastcomp, bool *comps, int layers, msgqueue_param_t *msgqueue)
341 index_param_t *codeidx;
342 int c, u, v, res_lev, dec_lev;
344 Byte4_t XTsiz, YTsiz;
345 Byte4_t XPsiz, YPsiz;
346 Byte4_t xminP, xmaxP, yminP, ymaxP;
348 codeidx = msgqueue->cachemodel->target->codeidx;
350 for( c=0; c<codeidx->SIZ.Csiz; c++)
351 if( lastcomp == -1 /*all*/ || ( c<=lastcomp && comps[c])){
353 for( res_lev=0, dec_lev=codeidx->COD.numOfdecomp; dec_lev>=level; res_lev++, dec_lev--){
355 XTsiz = get_tile_XSiz( codeidx->SIZ, tile_id, dec_lev);
356 YTsiz = get_tile_YSiz( codeidx->SIZ, tile_id, dec_lev);
358 XPsiz = ( codeidx->COD.Scod & 0x01) ? codeidx->COD.XPsiz[ res_lev] : XTsiz;
359 YPsiz = ( codeidx->COD.Scod & 0x01) ? codeidx->COD.YPsiz[ res_lev] : YTsiz;
361 for( u=0; u<ceil((double)YTsiz/(double)YPsiz); u++){
363 ymaxP = (u+1)*YPsiz-1;
367 for( v=0; v<ceil((double)XTsiz/(double)XPsiz); v++, seq_id++){
369 xmaxP = (v+1)*XPsiz-1;
373 if( xmaxP < xmin || xminP > xmax || ymaxP < ymin || yminP > ymax){
374 // Precinct completely excluded from view-window
376 else if( xminP >= xmin && xmaxP <= xmax && yminP >= ymin && ymaxP <= ymax){
377 // Precinct completely contained within view-window
379 enqueue_precinct( seq_id, tile_id, c, (dec_lev>level)?-1:layers, msgqueue);
382 // Precinct partially overlaps view-window
384 enqueue_precinct( seq_id, tile_id, c, (dec_lev>level)?-1:layers, msgqueue);
392 void enqueue_allprecincts( int tile_id, int level, int lastcomp, bool *comps, int layers, msgqueue_param_t *msgqueue)
394 index_param_t *codeidx;
395 int c, i, res_lev, dec_lev;
397 Byte4_t XTsiz, YTsiz;
398 Byte4_t XPsiz, YPsiz;
400 codeidx = msgqueue->cachemodel->target->codeidx;
402 for( c=0; c<codeidx->SIZ.Csiz; c++)
403 if( lastcomp == -1 /*all*/ || ( c<=lastcomp && comps[c])){
405 for( res_lev=0, dec_lev=codeidx->COD.numOfdecomp; dec_lev>=level; res_lev++, dec_lev--){
407 XTsiz = get_tile_XSiz( codeidx->SIZ, tile_id, dec_lev);
408 YTsiz = get_tile_YSiz( codeidx->SIZ, tile_id, dec_lev);
410 XPsiz = ( codeidx->COD.Scod & 0x01) ? codeidx->COD.XPsiz[ res_lev] : XTsiz;
411 YPsiz = ( codeidx->COD.Scod & 0x01) ? codeidx->COD.YPsiz[ res_lev] : YTsiz;
413 for( i=0; i<ceil((double)YTsiz/(double)YPsiz)*ceil((double)XTsiz/(double)XPsiz); i++, seq_id++)
414 enqueue_precinct( seq_id, tile_id, c, (dec_lev>level)?-1:layers, msgqueue);
419 void enqueue_metabins( query_param_t query_param, metadatalist_param_t *metadatalist, msgqueue_param_t *msgqueue)
422 for( i=0; query_param.box_type[i][0]!=0 && i<MAX_NUMOFBOX; i++){
423 if( query_param.box_type[i][0] == '*'){
427 int idx = search_metadataidx( query_param.box_type[i], metadatalist);
430 enqueue_metadata( idx, msgqueue);