Logo
  • Main Page
  • Related Pages
  • Modules
  • Classes
  • Files

mmsgifloader.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2005-2007 Stefan Schwarzer, Jens Schneider,             *
00003  *                           Matthias Hardt, Guido Madaus                  *
00004  *                                                                         *
00005  *   Copyright (C) 2007-2008 BerLinux Solutions GbR                        *
00006  *                           Stefan Schwarzer & Guido Madaus               *
00007  *                                                                         *
00008  *   Copyright (C) 2009-2013 BerLinux Solutions GmbH                       *
00009  *                                                                         *
00010  *   Authors:                                                              *
00011  *      Stefan Schwarzer   <stefan.schwarzer@diskohq.org>,                 *
00012  *      Matthias Hardt     <matthias.hardt@diskohq.org>,                   *
00013  *      Jens Schneider     <jens.schneider@diskohq.org>,                   *
00014  *      Guido Madaus       <guido.madaus@diskohq.org>,                     *
00015  *      Patrick Helterhoff <patrick.helterhoff@diskohq.org>,               *
00016  *      René Bählkow       <rene.baehlkow@diskohq.org>                     *
00017  *                                                                         *
00018  *   This library is free software; you can redistribute it and/or         *
00019  *   modify it under the terms of the GNU Lesser General Public            *
00020  *   License version 2.1 as published by the Free Software Foundation.     *
00021  *                                                                         *
00022  *   This library is distributed in the hope that it will be useful,       *
00023  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00024  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00025  *   Lesser General Public License for more details.                       *
00026  *                                                                         *
00027  *   You should have received a copy of the GNU Lesser General Public      *
00028  *   License along with this library; if not, write to the                 *
00029  *   Free Software Foundation, Inc.,                                       *
00030  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA            *
00031  **************************************************************************/
00032 
00033 #include "mmsgui/mmsgifloader.h"
00034 #include "mmsgui/fb/mmsfbsurface.h"
00035 #include <cstring>
00036 #include <cstdlib>
00037 
00038 extern "C" {
00039 #include <sys/time.h>
00040 #include <time.h>
00041 }
00042 
00043 //#define GIFTRACE
00044 
00045 MMSGIFLoader::MMSGIFLoader(MMSIM_DESC      *_desc,
00046                            MMSFBLayer      *_layer) :
00047     desc(_desc),
00048     layer(_layer),
00049     myfile(NULL) {
00050 
00051     this->desc->loading = true;
00052 
00053     pthread_cond_init(&this->cond, NULL);
00054     pthread_mutex_init(&this->mutex, NULL);
00055 }
00056 
00057 bool MMSGIFLoader::loadHeader() {
00058     unsigned char   buffer[1024];
00059     size_t          count = 0;
00060 
00061     this->myfile = new MMSFile(this->desc->imagefile);
00062     if (!this->myfile) return false;
00063 
00064     /* read header */
00065     if (!this->myfile->readBuffer((void*)buffer, &count, 1, 6)) {
00066         /* cannot read file */
00067         return false;
00068     }
00069 
00070     /* check header */
00071     memset(&this->gif_header, 0, sizeof(this->gif_header));
00072     if (count < 6) {
00073         /* it is not an GIF file */
00074         return false;
00075     }
00076     memcpy(gif_header.signature, &(buffer[0]), 3);
00077     memcpy(gif_header.version, &(buffer[3]), 3);
00078     if (memcmp(gif_header.signature, "GIF", 3)!=0) {
00079         /* it is not an GIF file */
00080         return false;
00081     }
00082 
00083 #ifdef GIFTRACE
00084     DEBUGOUT("FILE=%s\n", this->desc->imagefile.c_str());
00085     DEBUGOUT("HEADER\nSIGNATURE='%s'\nVERSION='%s'\n\n", this->gif_header.signature, this->gif_header.version);
00086 #endif
00087 
00088     /* read Logical Screen Descriptor */
00089     if (!this->myfile->readBuffer((void*)buffer, &count, 1, 7)) {
00090         /* cannot read file */
00091         return false;
00092     }
00093 
00094     /* put it in structure */
00095     memset(&this->gif_lsd, 0, sizeof(this->gif_lsd));
00096     this->gif_lsd.width = *((unsigned short*)&buffer[0]);
00097     this->gif_lsd.height = *((unsigned short*)&buffer[2]);
00098     this->gif_lsd.flags = buffer[4];
00099     this->gif_lsd.bgcolor = buffer[5];
00100     this->gif_lsd.ratio = buffer[6];
00101     this->gif_lsd.global_color_table = ((this->gif_lsd.flags & 0x80) == 0x80);
00102 
00103 #ifdef GIFTRACE
00104     DEBUGOUT("LOGICAL SCREEN DESCRIPTOR\nWIDTH='%u'\nHEIGHT='%u'\nFLAGS='%x'\nBGCOLOR='0x%02x'\nRATIO='%u'\nGCT=%s\n\n", gif_lsd.width, gif_lsd.height,
00105                     this->gif_lsd.flags, this->gif_lsd.bgcolor, this->gif_lsd.ratio,
00106                     (this->gif_lsd.global_color_table)?"yes":"no");
00107 #endif
00108 
00109     if (gif_lsd.global_color_table) {
00110         /* read the global color table */
00111         memset(&this->gif_gct, 0, sizeof(this->gif_gct));
00112         int y = (this->gif_lsd.flags & 0x07) + 1;
00113         this->gif_gct.size = 2;
00114         while (y-->1) this->gif_gct.size*=2;
00115         if (!this->myfile->readBuffer((void*)this->gif_gct.table, &count, 1, 3 * this->gif_gct.size)) {
00116             /* cannot read file */
00117             return false;
00118         }
00119 
00120         if (count < size_t(3 * this->gif_gct.size)) {
00121             /* bad format */
00122             return false;
00123         }
00124 
00125 #ifdef GIFTRACE
00126         DEBUGOUT("GLOBAL COLOR TABLE\nSIZE='%d'\n\n", this->gif_gct.size);
00127 #endif
00128     }
00129 
00130     return true;
00131 }
00132 
00133 bool MMSGIFLoader::loadBlocks() {
00134 
00135     unsigned char   buffer[1024];
00136     size_t          count = 0;
00137     MMS_GIF_GCE     gif_gce;
00138     MMS_GIF_GCE     gif_gce_old;
00139     bool            loop_forever = false;
00140 
00141     memset(&gif_gce, 0, sizeof(gif_gce));
00142     memset(&gif_gce_old, 0, sizeof(gif_gce_old));
00143 
00144 //int hh=0;
00145 
00146     /* through each block */
00147     while (1) {
00148         /* read block identifier */
00149         if (!this->myfile->readBuffer((void*)buffer, &count, 1, 1)) {
00150             /* cannot read file */
00151             return false;
00152         }
00153 
00154 
00155 //hh++;
00156 //DEBUGOUT("nc=%02x\n", buffer[0]);
00157 //if (i>20) break;
00158 //if (hh>2) break;
00159 
00160         switch (buffer[0]) {
00161             case 0x21:
00162                 /* extension block */
00163                 /* read extension block identifier */
00164                 if (!this->myfile->readBuffer((void*)buffer, &count, 1, 1)) {
00165                     /* cannot read file */
00166                     return false;
00167                 }
00168 
00169 //DEBUGOUT("nc=nc=%02x\n", buffer[0]);
00170 
00171                 switch (buffer[0]) {
00172                     case 0xff:
00173                         /* application extension block */
00174                         /* we do not need it - jump over */
00175                         if (!this->myfile->readBuffer((void*)buffer, &count, 1, 12)) {
00176                             /* cannot read file */
00177                             return false;
00178                         }
00179 
00180                         /* jump over data buffer */
00181                         while (1) {
00182                             if (!this->myfile->readBuffer((void*)buffer, &count, 1, 1)) {
00183                                 /* cannot read file */
00184                                 return false;
00185                             }
00186                             if (buffer[0]) {
00187                                 if (!this->myfile->readBuffer((void*)buffer, &count, 1, buffer[0])) {
00188                                     /* cannot read file */
00189                                     return false;
00190                                 }
00191                                 continue;
00192                             }
00193                             break;
00194                         }
00195 
00196 #ifdef GIFTRACE
00197                         DEBUGOUT("APPLICATION EXTENSION, skipped\n\n");
00198 #endif
00199 
00200                         /* if application extension is specified, we think that we should never stop the animation */
00201                         loop_forever = true;
00202 
00203                         break;
00204 
00205                     case 0xf9:
00206                         /* graphic control extension block */
00207                         if (!this->myfile->readBuffer((void*)buffer, &count, 1, 6)) {
00208                             /* cannot read file */
00209                             return false;
00210                         }
00211                         memcpy(&gif_gce_old, &gif_gce, sizeof(gif_gce));
00212                         memset(&gif_gce, 0, sizeof(gif_gce));
00213                         gif_gce.flags = buffer[1];
00214                         gif_gce.delaytime = *((unsigned short*)&buffer[2]);
00215                         gif_gce.transcolor = buffer[4];
00216                         gif_gce.transparent_color = ((gif_gce.flags & 0x01) == 0x01);
00217                         gif_gce.disposal = (gif_gce.flags >> 2) & 0x07;
00218 
00219 #ifdef GIFTRACE
00220                         DEBUGOUT("GRAPHIC CONTROL EXTENSION\nFLAGS='%x',DELAYTIME='%d',TRANSCOLOR='0x%02x'\n\n",
00221                                         gif_gce.flags, gif_gce.delaytime, (gif_gce.transparent_color)?gif_gce.transcolor:-1);
00222 #endif
00223 
00224                         break;
00225 
00226                     case 0x01:
00227                         /* plain text extension block */
00228                         /* we do not need it - jump over */
00229                         if (!this->myfile->readBuffer((void*)buffer, &count, 1, 13)) {
00230                             /* cannot read file */
00231                             return false;
00232                         }
00233 
00234                         /* jump over data buffer */
00235                         while (1) {
00236                             if (!this->myfile->readBuffer((void*)buffer, &count, 1, 1)) {
00237                                 /* cannot read file */
00238                                 return false;
00239                             }
00240                             if (buffer[0]) {
00241                                 if (!this->myfile->readBuffer((void*)buffer, &count, 1, buffer[0])) {
00242                                     /* cannot read file */
00243                                     return false;
00244                                 }
00245                                 continue;
00246                             }
00247                             break;
00248                         }
00249 
00250 //TODO
00251 #ifdef GIFTRACE
00252                         DEBUGOUT("PLAIN TEXT EXTENSION, skipped\n\n");
00253 #endif
00254 
00255                         break;
00256 
00257                     case 0xfe:
00258                         /* comment extension block */
00259 
00260                         /* jump over data buffer */
00261                         while (1) {
00262                             if (!this->myfile->readBuffer((void*)buffer, &count, 1, 1)) {
00263                                 /* cannot read file */
00264                                 return false;
00265                             }
00266                             if (buffer[0]) {
00267                                 if (!this->myfile->readBuffer((void*)buffer, &count, 1, buffer[0])) {
00268                                     /* cannot read file */
00269                                     return false;
00270                                 }
00271                                 continue;
00272                             }
00273                             break;
00274                         }
00275 
00276 #ifdef GIFTRACE
00277                         DEBUGOUT("COMMENT EXTENSION, skipped\n\n");
00278 #endif
00279 
00280                         break;
00281                 }
00282                 break;
00283 
00284             case 0x2c: {
00285                 // image descriptor
00286                 if (!this->myfile->readBuffer((void*)buffer, &count, 1, 9)) {
00287                     // cannot read file
00288                     return false;
00289                 }
00290 
00291                 // create the surface
00292                 MMSFBSurface *newsuf;
00293                 if (!this->layer->createSurface(&newsuf, gif_lsd.width, gif_lsd.height)) {
00294                     // cannot create surface
00295                     return false;
00296                 }
00297 
00298                 // get pixelformat of the surface
00299                 MMSFBSurfacePixelFormat pixelformat;
00300                 if (!newsuf->getPixelFormat(&pixelformat)) {
00301                     // cannot detect the pixelformat
00302                     delete newsuf;
00303                     return false;
00304                 }
00305 
00306                 // get the size of a pixel
00307                 int pixel_size;
00308                 switch (pixelformat) {
00309                 case MMSFB_PF_ARGB:
00310                     pixel_size = 4;
00311                     break;
00312                 case MMSFB_PF_ARGB4444:
00313                     pixel_size = 2;
00314                     break;
00315                 default:
00316                     // unsupported pixelformat
00317                     printf("GIF Loader currently does not support the %s pixelformat!\n",
00318                             getMMSFBPixelFormatString(pixelformat).c_str());
00319                     delete newsuf;
00320                     return false;
00321                 }
00322 
00323                 // get image infos
00324                 MMS_GIF_ID gif_id;
00325                 MMS_GIF_CT gif_lct;
00326                 MMS_GIF_CT *my_color_table;
00327                 memset(&gif_id, 0, sizeof(gif_id));
00328                 gif_id.x = *((unsigned short*)&buffer[0]);
00329                 gif_id.y = *((unsigned short*)&buffer[2]);
00330                 gif_id.w = *((unsigned short*)&buffer[4]);
00331                 gif_id.h = *((unsigned short*)&buffer[6]);
00332                 gif_id.flags = buffer[8];
00333                 gif_id.local_color_table = ((gif_id.flags & 0x80) == 0x80);
00334                 gif_id.interlaced = ((gif_id.flags & 0x40) == 0x40);
00335                 unsigned int line_size = gif_id.w * pixel_size;
00336                 unsigned int image_size = line_size * gif_id.h;
00337                 char interlace_pass = 0;
00338 
00339 #ifdef GIFTRACE
00340                 DEBUGOUT("IMAGE DESCRIPTOR\nX='%d',Y='%d',W='%d',H='%d',FLAGS='%x',LCT=%s,INTERLACED=%s\n\n",
00341                                 gif_id.x, gif_id.y, gif_id.w, gif_id.h, gif_id.flags,
00342                                 (gif_id.local_color_table)?"yes":"no", (gif_id.interlaced)?"yes":"no");
00343 #endif
00344 
00345                 if (gif_id.local_color_table) {
00346                     // read the local color table
00347                     memset(&gif_lct, 0, sizeof(gif_lct));
00348                     int y = (gif_id.flags & 0x07) + 1;
00349                     gif_lct.size = 2;
00350                     while (y-->1) gif_lct.size*=2;
00351                     if (!this->myfile->readBuffer((void*)gif_lct.table, &count, 1, 3 * gif_lct.size)) {
00352                         // cannot read file
00353                         delete newsuf;
00354                         return false;
00355                     }
00356 
00357                     if (count < (size_t)(3 * gif_lct.size)) {
00358                         // bad format
00359                         delete newsuf;
00360                         return false;
00361                     }
00362 
00363 #ifdef GIFTRACE
00364                     DEBUGOUT("LOCAL COLOR TABLE\nSIZE='%d'\n\n", gif_lct.size);
00365 #endif
00366 
00367                     my_color_table = &gif_lct;
00368                 }
00369                 else {
00370                     // use global color table
00371                     my_color_table = &(this->gif_gct);
00372                 }
00373 
00374                 // here some values needed for decoding...
00375                 if (!this->myfile->readBuffer((void*)buffer, &count, 1, 1)) {
00376                     // cannot read file
00377                     delete newsuf;
00378                     return false;
00379                 }
00380                 int initial_code_size = buffer[0];
00381                 int code_size = buffer[0];
00382                 int clr_code = 1 << code_size;
00383                 int end_code = clr_code + 1;
00384                 int max_code = clr_code << 1;
00385                 int next_code = clr_code + 2;
00386                 code_size++;
00387 
00388                 unsigned char data_table[128*1024];
00389                 unsigned int index_table[4*1024+1];
00390                 memset(data_table, 0, sizeof(data_table));
00391                 memset(index_table, 0, sizeof(index_table));
00392                 for (int t = 0; t < clr_code + 3; t++)
00393                     data_table[t]=index_table[t]=t;
00394                 bool end_of_stream = false;
00395 
00396                 // prepare surface
00397                 int ci;
00398                 if (this->desc->sufcount <= 0) {
00399                     /* first surface */
00400                     if (this->gif_lsd.global_color_table) {
00401                         if ((gif_gce.transparent_color) && (this->gif_lsd.bgcolor == gif_gce.transcolor)) {
00402                             /* clear surface */
00403                             newsuf->clear();
00404                         }
00405                         else {
00406                             /* fill with background color */
00407                             ci = this->gif_lsd.bgcolor*3;
00408                             newsuf->clear(gif_gct.table[ci], gif_gct.table[ci+1], gif_gct.table[ci+2], 0xff);
00409                         }
00410                     }
00411                     else {
00412                         /* clear surface */
00413                         newsuf->clear();
00414                     }
00415                 }
00416                 else {
00417                     // second or following surfaces
00418                     switch (gif_gce_old.disposal) {
00419                         case 0: // No disposal specified
00420                         case 1: // Do not dispose
00421                             newsuf->blit(desc->suf[desc->sufcount-1].surface, NULL, 0, 0);
00422                             break;
00423                         case 2: // Restore to background
00424                             ci = this->gif_lsd.bgcolor*3;
00425                             if ((gif_gce_old.transparent_color) && (this->gif_lsd.bgcolor == gif_gce_old.transcolor)) {
00426                                 // use the very first image as background
00427                                 newsuf->blit(desc->suf[0].surface, NULL, 0, 0);
00428                             }
00429                             else {
00430                                 // fill with background color
00431                                 newsuf->setColor(gif_gct.table[ci], gif_gct.table[ci+1], gif_gct.table[ci+2], 0xff);
00432                                 newsuf->fillRectangle(gif_id.x, gif_id.y, gif_id.w, gif_id.h);
00433                             }
00434                             break;
00435                         case 3: // Restore to previous
00436                             if (desc->sufcount >= 2) {
00437                                 newsuf->blit(desc->suf[desc->sufcount-2].surface, NULL, 0, 0);
00438                             }
00439                             break;
00440                     }
00441                 }
00442 
00443                 // get direct access to the surface
00444                 unsigned char *sufbuf, *sufbuf_start, *sufbuf_end;
00445                 int pitch;
00446                 newsuf->lock(MMSFB_LOCK_WRITE, (void**)&sufbuf, &pitch);
00447                 sufbuf+= gif_id.x * pixel_size + gif_id.y * pitch;
00448                 sufbuf_start = sufbuf;
00449                 sufbuf_end = sufbuf_start + gif_lsd.height * pitch;
00450 
00451                 unsigned int outlen = 0;
00452                 int oddbits = 0;
00453                 bool first = true;
00454 
00455                 while (1) {
00456 
00457                     // get the block length
00458                     unsigned char len;
00459                     if (!this->myfile->readBuffer((void*)&len, &count, 1, 1)) {
00460                         // cannot read file
00461                         newsuf->unlock();
00462                         delete newsuf;
00463                         return false;
00464                     }
00465 
00466                     // the first two bytes are reserved for the bit from the buffer before
00467                     int bits = 2*8;
00468                     int bitlen = bits + (((int)len) << 3);
00469                     if (oddbits > 0)
00470                         bits-=oddbits;
00471 
00472                     if (!len) {
00473                         // the block terminator was found
00474                         break;
00475                     }
00476 
00477                     // read the block data
00478                     // the first two bytes are reserved for the bit from the buffer before
00479                     if (!this->myfile->readBuffer((void*)&buffer[2], &count, 1, len)) {
00480                         // cannot read file
00481                         newsuf->unlock();
00482                         delete newsuf;
00483                         return false;
00484                     }
00485 
00486                     if (count < len) {
00487                         // bad format
00488                         newsuf->unlock();
00489                         delete newsuf;
00490                         return false;
00491                     }
00492 
00493 #ifdef GIFTRACE
00494                     DEBUGOUT("pixel indexes=\n");
00495 #endif
00496 
00497                     // read all pixel indexes from buffer
00498                     do {
00499                         // read the next bit code from buffer
00500                         int code = 0;
00501                         for (int i = 0; i < code_size; i++, bits++)
00502                             code = code | ((buffer[bits >> 3] & (1 << (bits & 0x07))) != 0) << i;
00503                         if (code == clr_code) {
00504                             // clear all values and tables *********************************
00505                             // code_size:   the code size in bits which will used at start *
00506                             // clr_code:    the code which indicates this reset            *
00507                             // end_code:    the code which indicates the end of the stream *
00508                             // max_code:    the maximum code                               *
00509                             // next_code:   the first free code                            *
00510                             // data_table:  this table contains data for decompression     *
00511                             // index_table: this table contains index values to data_table *
00512                             //**************************************************************
00513                             code_size  = initial_code_size;
00514                             clr_code = 1 << code_size;
00515                             end_code = clr_code + 1;
00516                             max_code = clr_code << 1;
00517                             next_code = clr_code + 2;
00518                             code_size++;
00519                             memset(data_table, 0, sizeof(data_table));
00520                             memset(index_table, 0, sizeof(index_table));
00521                             for (int t = 0; t < clr_code + 3; t++)
00522                                 data_table[t]=index_table[t]=t;
00523                             first = true;
00524                             continue;
00525                         }
00526 
00527                         if (code == end_code) {
00528                             // end of stream reached
00529 #ifdef GIFTRACE
00530                             DEBUGOUT("\nend of stream\n");
00531 #endif
00532                             end_of_stream = true;
00533                             break;
00534                         }
00535 
00536                         // saves old code which is written to the output stream
00537                         unsigned char oc[8192];
00538                         int oclen;
00539 
00540                         if (first) {
00541                             // first loop
00542                             first = false;
00543 
00544                             *oc = data_table[index_table[code]];
00545                             oclen = 1;
00546                         }
00547                         else {
00548                             // second or following loops
00549                             // is code in table?
00550                             if (code < next_code) {
00551                                 // yes, add to table (oc + first pixel of new code)
00552                                 memcpy(&data_table[index_table[next_code]], oc, oclen);
00553                                 data_table[index_table[next_code]+oclen] = data_table[index_table[code]];
00554                                 index_table[next_code+1] = index_table[next_code]+oclen+1;
00555                                 next_code++;
00556 
00557                                 // take table data for code
00558                                 oclen = index_table[code+1] - index_table[code];
00559                                 memcpy(oc, &data_table[index_table[code]], oclen);
00560                             }
00561                             else {
00562                                 // no, add to table (oc + first pixel of oc)
00563                                 memcpy(&data_table[index_table[next_code]], oc, oclen);
00564                                 data_table[index_table[next_code]+oclen] = *oc;
00565                                 index_table[next_code+1] = index_table[next_code]+oclen+1;
00566                                 next_code++;
00567 
00568                                 // take table data for new entry
00569                                 oclen = index_table[next_code] - index_table[next_code-1];
00570                                 memcpy(oc, &data_table[index_table[next_code-1]], oclen);
00571                             }
00572 
00573                         }
00574 
00575                         // output...
00576                         if (!gif_id.interlaced) {
00577                             // gif is not interlaced
00578                             for (int x = 0; x < oclen; x++) {
00579                                 if ((gif_gce.transparent_color) && (oc[x] == gif_gce.transcolor)) {
00580                                     // use full transparent pixel
00581                                     outlen+=pixel_size;
00582                                     sufbuf+=pixel_size;
00583 
00584 #ifdef GIFTRACE
00585                                     DEBUGOUT (",--");
00586 #endif
00587                                 }
00588                                 else {
00589                                     // create pixel from palette
00590                                     int ci = oc[x]*3;
00591 
00592                                     switch (pixelformat) {
00593                                     case MMSFB_PF_ARGB:
00594                                         sufbuf[0] = my_color_table->table[ci+2];
00595                                         sufbuf[1] = my_color_table->table[ci+1];
00596                                         sufbuf[2] = my_color_table->table[ci];
00597                                         sufbuf[3] = 0xff;
00598                                         break;
00599                                     case MMSFB_PF_ARGB4444:
00600                                         sufbuf[0] =   (my_color_table->table[ci+2] >> 4)
00601                                                     | (my_color_table->table[ci+1] & 0xf0);
00602                                         sufbuf[1] =   (my_color_table->table[ci] >> 4)
00603                                                     | 0xf0;
00604                                         break;
00605                                     default:
00606                                         break;
00607                                     }
00608 
00609                                     outlen+=pixel_size;
00610                                     sufbuf+=pixel_size;
00611 
00612 #ifdef GIFTRACE
00613                                     DEBUGOUT (",%02x", oc[x]);
00614 #endif
00615                                 }
00616 
00617                                 if (outlen % line_size == 0)
00618                                     sufbuf+=pitch - line_size;
00619                             }
00620                         }
00621                         else {
00622                             // interlaced gif
00623                             for (int x = 0; x < oclen; x++) {
00624                                 if ((gif_gce.transparent_color) && (oc[x] == gif_gce.transcolor)) {
00625                                     // use full transparent pixel
00626                                     outlen+=pixel_size;
00627                                     sufbuf+=pixel_size;
00628 
00629 #ifdef GIFTRACE
00630                                     DEBUGOUT (",--");
00631 #endif
00632                                 }
00633                                 else {
00634                                     // create pixel from palette
00635                                     int ci = oc[x]*3;
00636 
00637                                     switch (pixelformat) {
00638                                     case MMSFB_PF_ARGB:
00639                                         sufbuf[0] = my_color_table->table[ci+2];
00640                                         sufbuf[1] = my_color_table->table[ci+1];
00641                                         sufbuf[2] = my_color_table->table[ci];
00642                                         sufbuf[3] = 0xff;
00643                                         break;
00644                                     case MMSFB_PF_ARGB4444:
00645                                         sufbuf[0] =   (my_color_table->table[ci+2] >> 4)
00646                                                     | (my_color_table->table[ci+1] & 0xf0);
00647                                         sufbuf[1] =   (my_color_table->table[ci] >> 4)
00648                                                     | 0xf0;
00649                                         break;
00650                                     default:
00651                                         break;
00652                                     }
00653 
00654                                     outlen+=pixel_size;
00655                                     sufbuf+=pixel_size;
00656 
00657 #ifdef GIFTRACE
00658                                     DEBUGOUT (",%02x", oc[x]);
00659 #endif
00660                                 }
00661 
00662 
00663                                 if (outlen % line_size == 0) {
00664                                     sufbuf+=pitch - line_size;
00665 
00666                                     switch (interlace_pass) {
00667                                         case 0:
00668                                             sufbuf+=pitch * 7;
00669                                             if (sufbuf >= sufbuf_end) {
00670                                                 sufbuf=sufbuf_start + (pitch << 2);
00671                                                 interlace_pass++;
00672                                             }
00673                                             break;
00674                                         case 1:
00675                                             sufbuf+=pitch * 7;
00676                                             if (sufbuf >= sufbuf_end) {
00677                                                 sufbuf=sufbuf_start + (pitch << 1);
00678                                                 interlace_pass++;
00679                                             }
00680                                             break;
00681                                         case 2:
00682                                             sufbuf+=pitch * 3;
00683                                             if (sufbuf >= sufbuf_end) {
00684                                                 sufbuf=sufbuf_start + pitch;
00685                                                 interlace_pass++;
00686                                             }
00687                                             break;
00688                                         case 3:
00689                                             sufbuf+=pitch;
00690                                             break;
00691                                     }
00692                                 }
00693 
00694                             }
00695                         }
00696 
00697                         // is next_code outside of 0..max_code range?
00698                         if (next_code >= max_code) {
00699                             if (code_size < 12) {
00700                                 // yes, increase code_size by 1 and double max code
00701                                 max_code = max_code << 1;
00702                                 code_size++;
00703                             }
00704                         }
00705 
00706                     } while (bits <= bitlen - code_size);
00707 
00708                     if (end_of_stream)
00709                         break;
00710 
00711                     oddbits = bitlen - bits;
00712                     if (oddbits > 0) {
00713                         // save the last bits because the amount is less than the code_size and a next GIF block will come
00714                         // two bytes because code size for GIF is not higher than 12
00715                         if (oddbits > 8) {
00716                             buffer[0] = buffer[bits >> 3];
00717                             buffer[1] = buffer[(bits >> 3) + 1];
00718                         }
00719                         else
00720                             buffer[1] = buffer[bits >> 3];
00721                     }
00722 
00723 #ifdef GIFTRACE
00724                     DEBUGOUT("\n\n");
00725 #endif
00726                 }
00727 
00728                 // stream okay?, check the available data with the given image size
00729                 if ((!end_of_stream) || (outlen != image_size)) {
00730                     // bad format
00731 #ifdef GIFTRACE
00732                     DEBUGOUT("bad format, outlen=%d, needed len=%d\n", outlen, image_size);
00733 #endif
00734                     newsuf->unlock();
00735                     delete newsuf;
00736                     return false;
00737                 }
00738 
00739                 newsuf->unlock();
00740 
00741                 // fill the communication structure
00742                 if (desc->sufcount < MMSIM_MAX_DESC_SUF) {
00743                     // mark the next end of the array
00744                     desc->suf[desc->sufcount+1].delaytime = MMSIM_DESC_SUF_LOADING;
00745 
00746                     // fill the surface pointer
00747                     desc->suf[desc->sufcount].surface = newsuf;
00748 
00749                     // the lowest delaytime is 100 milliseconds
00750                     if (gif_gce.delaytime > 10)
00751                         desc->suf[desc->sufcount].delaytime = 10 * (unsigned int)gif_gce.delaytime;
00752                     else
00753                         desc->suf[desc->sufcount].delaytime = 100;
00754 
00755                     desc->sufcount++;
00756                     if(desc->sufcount == 1) {
00757                         pthread_cond_signal(&this->cond);
00758                         pthread_mutex_unlock(&this->mutex);
00759                     }
00760                 }
00761                 else {
00762                     // no free index
00763 #ifdef GIFTRACE
00764                     DEBUGOUT("no free index\n");
00765 #endif
00766                     delete newsuf;
00767                 }
00768             }
00769             break;
00770 
00771             case 0x3b:
00772                 // normal end of GIF stream
00773 
00774 #ifdef GIFTRACE
00775                 DEBUGOUT("TRAILER, end of the GIF stream\n\n");
00776 #endif
00777 
00778                 if ((!loop_forever)&&(desc->sufcount>0))
00779                     // set delaytime to 0 if the animation should stop at the last image
00780                     desc->suf[desc->sufcount-1].delaytime = 0;
00781 
00782                 return true;
00783 
00784                 break;
00785         }
00786 
00787     }
00788 
00789     return true;
00790 
00791 }
00792 
00793 void MMSGIFLoader::threadMain() {
00794     pthread_mutex_lock(&this->mutex);
00795 
00796     /* load some header informations */
00797     if (loadHeader()) {
00798         /* load the separated blocks */
00799         if(!loadBlocks()) {
00800             pthread_cond_signal(&this->cond);
00801             pthread_mutex_unlock(&this->mutex);
00802         }
00803     }
00804 
00805     if (this->myfile)
00806         delete this->myfile;
00807 
00808     /* mark end of list */
00809     this->desc->suf[this->desc->sufcount].delaytime = MMSIM_DESC_SUF_END;
00810 
00811     /* stop loading */
00812     this->desc->loading = false;
00813 
00814     pthread_cond_destroy(&this->cond);
00815     pthread_mutex_destroy(&this->mutex);
00816     pthread_exit(NULL);
00817 }
00818 
00819 /**
00820  * This method returns when at least the first image
00821  * of a GIF file is loaded.
00822  */
00823 void MMSGIFLoader::block() {
00824     struct timeval  tsGet;
00825     struct timespec ts;
00826     gettimeofday(&tsGet, NULL);
00827     //clock_gettime(CLOCK_REALTIME, &ts);
00828     ts.tv_sec = tsGet.tv_sec + 5;
00829     ts.tv_nsec = tsGet.tv_usec * 1000;
00830     pthread_mutex_lock(&this->mutex);
00831     while(this->desc->loading && this->desc->sufcount <= 0)
00832         pthread_cond_timedwait(&this->cond, &this->mutex, &ts);
00833     pthread_mutex_unlock(&this->mutex);
00834 }
00835 
00836 bool isGIF(string file) {
00837     MMSFile         *myfile;
00838     unsigned char   *gif_header;
00839     size_t          count = 0;
00840 
00841     myfile = new MMSFile(file);
00842     if (!myfile) return false;
00843 
00844     if (!myfile->readBufferEx((void**)&gif_header, &count, 1, 3)) {
00845         /* cannot read file */
00846         delete myfile;
00847         return false;
00848     }
00849     delete myfile;
00850 
00851     /* check header */
00852     if (count < 3) {
00853         /* it is not an GIF file */
00854         free(gif_header);
00855         return false;
00856     }
00857     if (memcmp(gif_header, "GIF", 3)!=0) {
00858         /* it is not an GIF file */
00859         free(gif_header);
00860         return false;
00861     }
00862 
00863     free(gif_header);
00864     return true;
00865 }
00866 

Generated by doxygen