• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavcodec/flicvideo.c

Go to the documentation of this file.
00001 /*
00002  * FLI/FLC Animation Video Decoder
00003  * Copyright (C) 2003, 2004 the ffmpeg project
00004  *
00005  * This file is part of FFmpeg.
00006  *
00007  * FFmpeg is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * FFmpeg is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with FFmpeg; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00038 #include <stdio.h>
00039 #include <stdlib.h>
00040 #include <string.h>
00041 
00042 #include "libavutil/intreadwrite.h"
00043 #include "avcodec.h"
00044 
00045 #define FLI_256_COLOR 4
00046 #define FLI_DELTA     7
00047 #define FLI_COLOR     11
00048 #define FLI_LC        12
00049 #define FLI_BLACK     13
00050 #define FLI_BRUN      15
00051 #define FLI_COPY      16
00052 #define FLI_MINI      18
00053 #define FLI_DTA_BRUN  25
00054 #define FLI_DTA_COPY  26
00055 #define FLI_DTA_LC    27
00056 
00057 #define FLI_TYPE_CODE     (0xAF11)
00058 #define FLC_FLX_TYPE_CODE (0xAF12)
00059 #define FLC_DTA_TYPE_CODE (0xAF44) /* Marks an "Extended FLC" comes from Dave's Targa Animator (DTA) */
00060 #define FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE (0xAF13)
00061 
00062 #define CHECK_PIXEL_PTR(n) \
00063     if (pixel_ptr + n > pixel_limit) { \
00064         av_log (s->avctx, AV_LOG_INFO, "Problem: pixel_ptr >= pixel_limit (%d >= %d)\n", \
00065         pixel_ptr + n, pixel_limit); \
00066         return -1; \
00067     } \
00068 
00069 typedef struct FlicDecodeContext {
00070     AVCodecContext *avctx;
00071     AVFrame frame;
00072 
00073     unsigned int palette[256];
00074     int new_palette;
00075     int fli_type;  /* either 0xAF11 or 0xAF12, affects palette resolution */
00076 } FlicDecodeContext;
00077 
00078 static av_cold int flic_decode_init(AVCodecContext *avctx)
00079 {
00080     FlicDecodeContext *s = avctx->priv_data;
00081     unsigned char *fli_header = (unsigned char *)avctx->extradata;
00082     int depth;
00083 
00084     s->avctx = avctx;
00085 
00086     s->fli_type = AV_RL16(&fli_header[4]); /* Might be overridden if a Magic Carpet FLC */
00087 
00088     depth = 0;
00089     if (s->avctx->extradata_size == 12) {
00090         /* special case for magic carpet FLIs */
00091         s->fli_type = FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE;
00092         depth = 8;
00093     } else if (s->avctx->extradata_size != 128) {
00094         av_log(avctx, AV_LOG_ERROR, "Expected extradata of 12 or 128 bytes\n");
00095         return -1;
00096     } else {
00097         depth = AV_RL16(&fli_header[12]);
00098     }
00099 
00100     if (depth == 0) {
00101         depth = 8; /* Some FLC generators set depth to zero, when they mean 8Bpp. Fix up here */
00102     }
00103 
00104     if ((s->fli_type == FLC_FLX_TYPE_CODE) && (depth == 16)) {
00105         depth = 15; /* Original Autodesk FLX's say the depth is 16Bpp when it is really 15Bpp */
00106     }
00107 
00108     switch (depth) {
00109         case 8  : avctx->pix_fmt = PIX_FMT_PAL8; break;
00110         case 15 : avctx->pix_fmt = PIX_FMT_RGB555; break;
00111         case 16 : avctx->pix_fmt = PIX_FMT_RGB565; break;
00112         case 24 : avctx->pix_fmt = PIX_FMT_BGR24; /* Supposedly BGR, but havent any files to test with */
00113                   av_log(avctx, AV_LOG_ERROR, "24Bpp FLC/FLX is unsupported due to no test files.\n");
00114                   return -1;
00115                   break;
00116         default :
00117                   av_log(avctx, AV_LOG_ERROR, "Unknown FLC/FLX depth of %d Bpp is unsupported.\n",depth);
00118                   return -1;
00119     }
00120 
00121     s->frame.data[0] = NULL;
00122     s->new_palette = 0;
00123 
00124     return 0;
00125 }
00126 
00127 static int flic_decode_frame_8BPP(AVCodecContext *avctx,
00128                                   void *data, int *data_size,
00129                                   const uint8_t *buf, int buf_size)
00130 {
00131     FlicDecodeContext *s = avctx->priv_data;
00132 
00133     int stream_ptr = 0;
00134     int stream_ptr_after_color_chunk;
00135     int pixel_ptr;
00136     int palette_ptr;
00137     unsigned char palette_idx1;
00138     unsigned char palette_idx2;
00139 
00140     unsigned int frame_size;
00141     int num_chunks;
00142 
00143     unsigned int chunk_size;
00144     int chunk_type;
00145 
00146     int i, j;
00147 
00148     int color_packets;
00149     int color_changes;
00150     int color_shift;
00151     unsigned char r, g, b;
00152 
00153     int lines;
00154     int compressed_lines;
00155     int starting_line;
00156     signed short line_packets;
00157     int y_ptr;
00158     int byte_run;
00159     int pixel_skip;
00160     int pixel_countdown;
00161     unsigned char *pixels;
00162     unsigned int pixel_limit;
00163 
00164     s->frame.reference = 1;
00165     s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
00166     if (avctx->reget_buffer(avctx, &s->frame) < 0) {
00167         av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
00168         return -1;
00169     }
00170 
00171     pixels = s->frame.data[0];
00172     pixel_limit = s->avctx->height * s->frame.linesize[0];
00173 
00174     frame_size = AV_RL32(&buf[stream_ptr]);
00175     stream_ptr += 6;  /* skip the magic number */
00176     num_chunks = AV_RL16(&buf[stream_ptr]);
00177     stream_ptr += 10;  /* skip padding */
00178 
00179     frame_size -= 16;
00180 
00181     /* iterate through the chunks */
00182     while ((frame_size > 0) && (num_chunks > 0)) {
00183         chunk_size = AV_RL32(&buf[stream_ptr]);
00184         stream_ptr += 4;
00185         chunk_type = AV_RL16(&buf[stream_ptr]);
00186         stream_ptr += 2;
00187 
00188         switch (chunk_type) {
00189         case FLI_256_COLOR:
00190         case FLI_COLOR:
00191             stream_ptr_after_color_chunk = stream_ptr + chunk_size - 6;
00192 
00193             /* check special case: If this file is from the Magic Carpet
00194              * game and uses 6-bit colors even though it reports 256-color
00195              * chunks in a 0xAF12-type file (fli_type is set to 0xAF13 during
00196              * initialization) */
00197             if ((chunk_type == FLI_256_COLOR) && (s->fli_type != FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE))
00198                 color_shift = 0;
00199             else
00200                 color_shift = 2;
00201             /* set up the palette */
00202             color_packets = AV_RL16(&buf[stream_ptr]);
00203             stream_ptr += 2;
00204             palette_ptr = 0;
00205             for (i = 0; i < color_packets; i++) {
00206                 /* first byte is how many colors to skip */
00207                 palette_ptr += buf[stream_ptr++];
00208 
00209                 /* next byte indicates how many entries to change */
00210                 color_changes = buf[stream_ptr++];
00211 
00212                 /* if there are 0 color changes, there are actually 256 */
00213                 if (color_changes == 0)
00214                     color_changes = 256;
00215 
00216                 for (j = 0; j < color_changes; j++) {
00217                     unsigned int entry;
00218 
00219                     /* wrap around, for good measure */
00220                     if ((unsigned)palette_ptr >= 256)
00221                         palette_ptr = 0;
00222 
00223                     r = buf[stream_ptr++] << color_shift;
00224                     g = buf[stream_ptr++] << color_shift;
00225                     b = buf[stream_ptr++] << color_shift;
00226                     entry = (r << 16) | (g << 8) | b;
00227                     if (s->palette[palette_ptr] != entry)
00228                         s->new_palette = 1;
00229                     s->palette[palette_ptr++] = entry;
00230                 }
00231             }
00232 
00233             /* color chunks sometimes have weird 16-bit alignment issues;
00234              * therefore, take the hardline approach and set the stream_ptr
00235              * to the value calculated w.r.t. the size specified by the color
00236              * chunk header */
00237             stream_ptr = stream_ptr_after_color_chunk;
00238 
00239             break;
00240 
00241         case FLI_DELTA:
00242             y_ptr = 0;
00243             compressed_lines = AV_RL16(&buf[stream_ptr]);
00244             stream_ptr += 2;
00245             while (compressed_lines > 0) {
00246                 line_packets = AV_RL16(&buf[stream_ptr]);
00247                 stream_ptr += 2;
00248                 if ((line_packets & 0xC000) == 0xC000) {
00249                     // line skip opcode
00250                     line_packets = -line_packets;
00251                     y_ptr += line_packets * s->frame.linesize[0];
00252                 } else if ((line_packets & 0xC000) == 0x4000) {
00253                     av_log(avctx, AV_LOG_ERROR, "Undefined opcode (%x) in DELTA_FLI\n", line_packets);
00254                 } else if ((line_packets & 0xC000) == 0x8000) {
00255                     // "last byte" opcode
00256                     pixel_ptr= y_ptr + s->frame.linesize[0] - 1;
00257                     CHECK_PIXEL_PTR(0);
00258                     pixels[pixel_ptr] = line_packets & 0xff;
00259                 } else {
00260                     compressed_lines--;
00261                     pixel_ptr = y_ptr;
00262                     CHECK_PIXEL_PTR(0);
00263                     pixel_countdown = s->avctx->width;
00264                     for (i = 0; i < line_packets; i++) {
00265                         /* account for the skip bytes */
00266                         pixel_skip = buf[stream_ptr++];
00267                         pixel_ptr += pixel_skip;
00268                         pixel_countdown -= pixel_skip;
00269                         byte_run = (signed char)(buf[stream_ptr++]);
00270                         if (byte_run < 0) {
00271                             byte_run = -byte_run;
00272                             palette_idx1 = buf[stream_ptr++];
00273                             palette_idx2 = buf[stream_ptr++];
00274                             CHECK_PIXEL_PTR(byte_run * 2);
00275                             for (j = 0; j < byte_run; j++, pixel_countdown -= 2) {
00276                                 pixels[pixel_ptr++] = palette_idx1;
00277                                 pixels[pixel_ptr++] = palette_idx2;
00278                             }
00279                         } else {
00280                             CHECK_PIXEL_PTR(byte_run * 2);
00281                             for (j = 0; j < byte_run * 2; j++, pixel_countdown--) {
00282                                 palette_idx1 = buf[stream_ptr++];
00283                                 pixels[pixel_ptr++] = palette_idx1;
00284                             }
00285                         }
00286                     }
00287 
00288                     y_ptr += s->frame.linesize[0];
00289                 }
00290             }
00291             break;
00292 
00293         case FLI_LC:
00294             /* line compressed */
00295             starting_line = AV_RL16(&buf[stream_ptr]);
00296             stream_ptr += 2;
00297             y_ptr = 0;
00298             y_ptr += starting_line * s->frame.linesize[0];
00299 
00300             compressed_lines = AV_RL16(&buf[stream_ptr]);
00301             stream_ptr += 2;
00302             while (compressed_lines > 0) {
00303                 pixel_ptr = y_ptr;
00304                 CHECK_PIXEL_PTR(0);
00305                 pixel_countdown = s->avctx->width;
00306                 line_packets = buf[stream_ptr++];
00307                 if (line_packets > 0) {
00308                     for (i = 0; i < line_packets; i++) {
00309                         /* account for the skip bytes */
00310                         pixel_skip = buf[stream_ptr++];
00311                         pixel_ptr += pixel_skip;
00312                         pixel_countdown -= pixel_skip;
00313                         byte_run = (signed char)(buf[stream_ptr++]);
00314                         if (byte_run > 0) {
00315                             CHECK_PIXEL_PTR(byte_run);
00316                             for (j = 0; j < byte_run; j++, pixel_countdown--) {
00317                                 palette_idx1 = buf[stream_ptr++];
00318                                 pixels[pixel_ptr++] = palette_idx1;
00319                             }
00320                         } else if (byte_run < 0) {
00321                             byte_run = -byte_run;
00322                             palette_idx1 = buf[stream_ptr++];
00323                             CHECK_PIXEL_PTR(byte_run);
00324                             for (j = 0; j < byte_run; j++, pixel_countdown--) {
00325                                 pixels[pixel_ptr++] = palette_idx1;
00326                             }
00327                         }
00328                     }
00329                 }
00330 
00331                 y_ptr += s->frame.linesize[0];
00332                 compressed_lines--;
00333             }
00334             break;
00335 
00336         case FLI_BLACK:
00337             /* set the whole frame to color 0 (which is usually black) */
00338             memset(pixels, 0,
00339                 s->frame.linesize[0] * s->avctx->height);
00340             break;
00341 
00342         case FLI_BRUN:
00343             /* Byte run compression: This chunk type only occurs in the first
00344              * FLI frame and it will update the entire frame. */
00345             y_ptr = 0;
00346             for (lines = 0; lines < s->avctx->height; lines++) {
00347                 pixel_ptr = y_ptr;
00348                 /* disregard the line packets; instead, iterate through all
00349                  * pixels on a row */
00350                 stream_ptr++;
00351                 pixel_countdown = s->avctx->width;
00352                 while (pixel_countdown > 0) {
00353                     byte_run = (signed char)(buf[stream_ptr++]);
00354                     if (byte_run > 0) {
00355                         palette_idx1 = buf[stream_ptr++];
00356                         CHECK_PIXEL_PTR(byte_run);
00357                         for (j = 0; j < byte_run; j++) {
00358                             pixels[pixel_ptr++] = palette_idx1;
00359                             pixel_countdown--;
00360                             if (pixel_countdown < 0)
00361                                 av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n",
00362                                        pixel_countdown, lines);
00363                         }
00364                     } else {  /* copy bytes if byte_run < 0 */
00365                         byte_run = -byte_run;
00366                         CHECK_PIXEL_PTR(byte_run);
00367                         for (j = 0; j < byte_run; j++) {
00368                             palette_idx1 = buf[stream_ptr++];
00369                             pixels[pixel_ptr++] = palette_idx1;
00370                             pixel_countdown--;
00371                             if (pixel_countdown < 0)
00372                                 av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n",
00373                                        pixel_countdown, lines);
00374                         }
00375                     }
00376                 }
00377 
00378                 y_ptr += s->frame.linesize[0];
00379             }
00380             break;
00381 
00382         case FLI_COPY:
00383             /* copy the chunk (uncompressed frame) */
00384             if (chunk_size - 6 > s->avctx->width * s->avctx->height) {
00385                 av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \
00386                        "bigger than image, skipping chunk\n", chunk_size - 6);
00387                 stream_ptr += chunk_size - 6;
00388             } else {
00389                 for (y_ptr = 0; y_ptr < s->frame.linesize[0] * s->avctx->height;
00390                      y_ptr += s->frame.linesize[0]) {
00391                     memcpy(&pixels[y_ptr], &buf[stream_ptr],
00392                         s->avctx->width);
00393                     stream_ptr += s->avctx->width;
00394                 }
00395             }
00396             break;
00397 
00398         case FLI_MINI:
00399             /* some sort of a thumbnail? disregard this chunk... */
00400             stream_ptr += chunk_size - 6;
00401             break;
00402 
00403         default:
00404             av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type);
00405             break;
00406         }
00407 
00408         frame_size -= chunk_size;
00409         num_chunks--;
00410     }
00411 
00412     /* by the end of the chunk, the stream ptr should equal the frame
00413      * size (minus 1, possibly); if it doesn't, issue a warning */
00414     if ((stream_ptr != buf_size) && (stream_ptr != buf_size - 1))
00415         av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \
00416                "and final chunk ptr = %d\n", buf_size, stream_ptr);
00417 
00418     /* make the palette available on the way out */
00419     memcpy(s->frame.data[1], s->palette, AVPALETTE_SIZE);
00420     if (s->new_palette) {
00421         s->frame.palette_has_changed = 1;
00422         s->new_palette = 0;
00423     }
00424 
00425     *data_size=sizeof(AVFrame);
00426     *(AVFrame*)data = s->frame;
00427 
00428     return buf_size;
00429 }
00430 
00431 static int flic_decode_frame_15_16BPP(AVCodecContext *avctx,
00432                                       void *data, int *data_size,
00433                                       const uint8_t *buf, int buf_size)
00434 {
00435     /* Note, the only difference between the 15Bpp and 16Bpp */
00436     /* Format is the pixel format, the packets are processed the same. */
00437     FlicDecodeContext *s = avctx->priv_data;
00438 
00439     int stream_ptr = 0;
00440     int pixel_ptr;
00441     unsigned char palette_idx1;
00442 
00443     unsigned int frame_size;
00444     int num_chunks;
00445 
00446     unsigned int chunk_size;
00447     int chunk_type;
00448 
00449     int i, j;
00450 
00451     int lines;
00452     int compressed_lines;
00453     signed short line_packets;
00454     int y_ptr;
00455     int byte_run;
00456     int pixel_skip;
00457     int pixel_countdown;
00458     unsigned char *pixels;
00459     int pixel;
00460     unsigned int pixel_limit;
00461 
00462     s->frame.reference = 1;
00463     s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
00464     if (avctx->reget_buffer(avctx, &s->frame) < 0) {
00465         av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
00466         return -1;
00467     }
00468 
00469     pixels = s->frame.data[0];
00470     pixel_limit = s->avctx->height * s->frame.linesize[0];
00471 
00472     frame_size = AV_RL32(&buf[stream_ptr]);
00473     stream_ptr += 6;  /* skip the magic number */
00474     num_chunks = AV_RL16(&buf[stream_ptr]);
00475     stream_ptr += 10;  /* skip padding */
00476 
00477     frame_size -= 16;
00478 
00479     /* iterate through the chunks */
00480     while ((frame_size > 0) && (num_chunks > 0)) {
00481         chunk_size = AV_RL32(&buf[stream_ptr]);
00482         stream_ptr += 4;
00483         chunk_type = AV_RL16(&buf[stream_ptr]);
00484         stream_ptr += 2;
00485 
00486         switch (chunk_type) {
00487         case FLI_256_COLOR:
00488         case FLI_COLOR:
00489             /* For some reason, it seems that non-palettized flics do
00490              * include one of these chunks in their first frame.
00491              * Why I do not know, it seems rather extraneous. */
00492 /*            av_log(avctx, AV_LOG_ERROR, "Unexpected Palette chunk %d in non-paletised FLC\n",chunk_type);*/
00493             stream_ptr = stream_ptr + chunk_size - 6;
00494             break;
00495 
00496         case FLI_DELTA:
00497         case FLI_DTA_LC:
00498             y_ptr = 0;
00499             compressed_lines = AV_RL16(&buf[stream_ptr]);
00500             stream_ptr += 2;
00501             while (compressed_lines > 0) {
00502                 line_packets = AV_RL16(&buf[stream_ptr]);
00503                 stream_ptr += 2;
00504                 if (line_packets < 0) {
00505                     line_packets = -line_packets;
00506                     y_ptr += line_packets * s->frame.linesize[0];
00507                 } else {
00508                     compressed_lines--;
00509                     pixel_ptr = y_ptr;
00510                     CHECK_PIXEL_PTR(0);
00511                     pixel_countdown = s->avctx->width;
00512                     for (i = 0; i < line_packets; i++) {
00513                         /* account for the skip bytes */
00514                         pixel_skip = buf[stream_ptr++];
00515                         pixel_ptr += (pixel_skip*2); /* Pixel is 2 bytes wide */
00516                         pixel_countdown -= pixel_skip;
00517                         byte_run = (signed char)(buf[stream_ptr++]);
00518                         if (byte_run < 0) {
00519                             byte_run = -byte_run;
00520                             pixel    = AV_RL16(&buf[stream_ptr]);
00521                             stream_ptr += 2;
00522                             CHECK_PIXEL_PTR(2 * byte_run);
00523                             for (j = 0; j < byte_run; j++, pixel_countdown -= 2) {
00524                                 *((signed short*)(&pixels[pixel_ptr])) = pixel;
00525                                 pixel_ptr += 2;
00526                             }
00527                         } else {
00528                             CHECK_PIXEL_PTR(2 * byte_run);
00529                             for (j = 0; j < byte_run; j++, pixel_countdown--) {
00530                                 *((signed short*)(&pixels[pixel_ptr])) = AV_RL16(&buf[stream_ptr]);
00531                                 stream_ptr += 2;
00532                                 pixel_ptr += 2;
00533                             }
00534                         }
00535                     }
00536 
00537                     y_ptr += s->frame.linesize[0];
00538                 }
00539             }
00540             break;
00541 
00542         case FLI_LC:
00543             av_log(avctx, AV_LOG_ERROR, "Unexpected FLI_LC chunk in non-paletised FLC\n");
00544             stream_ptr = stream_ptr + chunk_size - 6;
00545             break;
00546 
00547         case FLI_BLACK:
00548             /* set the whole frame to 0x0000 which is black in both 15Bpp and 16Bpp modes. */
00549             memset(pixels, 0x0000,
00550                    s->frame.linesize[0] * s->avctx->height);
00551             break;
00552 
00553         case FLI_BRUN:
00554             y_ptr = 0;
00555             for (lines = 0; lines < s->avctx->height; lines++) {
00556                 pixel_ptr = y_ptr;
00557                 /* disregard the line packets; instead, iterate through all
00558                  * pixels on a row */
00559                 stream_ptr++;
00560                 pixel_countdown = (s->avctx->width * 2);
00561 
00562                 while (pixel_countdown > 0) {
00563                     byte_run = (signed char)(buf[stream_ptr++]);
00564                     if (byte_run > 0) {
00565                         palette_idx1 = buf[stream_ptr++];
00566                         CHECK_PIXEL_PTR(byte_run);
00567                         for (j = 0; j < byte_run; j++) {
00568                             pixels[pixel_ptr++] = palette_idx1;
00569                             pixel_countdown--;
00570                             if (pixel_countdown < 0)
00571                                 av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) (linea%d)\n",
00572                                        pixel_countdown, lines);
00573                         }
00574                     } else {  /* copy bytes if byte_run < 0 */
00575                         byte_run = -byte_run;
00576                         CHECK_PIXEL_PTR(byte_run);
00577                         for (j = 0; j < byte_run; j++) {
00578                             palette_idx1 = buf[stream_ptr++];
00579                             pixels[pixel_ptr++] = palette_idx1;
00580                             pixel_countdown--;
00581                             if (pixel_countdown < 0)
00582                                 av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d) at line %d\n",
00583                                        pixel_countdown, lines);
00584                         }
00585                     }
00586                 }
00587 
00588                 /* Now FLX is strange, in that it is "byte" as opposed to "pixel" run length compressed.
00589                  * This does not give us any good oportunity to perform word endian conversion
00590                  * during decompression. So if it is required (i.e., this is not a LE target, we do
00591                  * a second pass over the line here, swapping the bytes.
00592                  */
00593 #if HAVE_BIGENDIAN
00594                 pixel_ptr = y_ptr;
00595                 pixel_countdown = s->avctx->width;
00596                 while (pixel_countdown > 0) {
00597                     *((signed short*)(&pixels[pixel_ptr])) = AV_RL16(&buf[pixel_ptr]);
00598                     pixel_ptr += 2;
00599                 }
00600 #endif
00601                 y_ptr += s->frame.linesize[0];
00602             }
00603             break;
00604 
00605         case FLI_DTA_BRUN:
00606             y_ptr = 0;
00607             for (lines = 0; lines < s->avctx->height; lines++) {
00608                 pixel_ptr = y_ptr;
00609                 /* disregard the line packets; instead, iterate through all
00610                  * pixels on a row */
00611                 stream_ptr++;
00612                 pixel_countdown = s->avctx->width; /* Width is in pixels, not bytes */
00613 
00614                 while (pixel_countdown > 0) {
00615                     byte_run = (signed char)(buf[stream_ptr++]);
00616                     if (byte_run > 0) {
00617                         pixel    = AV_RL16(&buf[stream_ptr]);
00618                         stream_ptr += 2;
00619                         CHECK_PIXEL_PTR(2 * byte_run);
00620                         for (j = 0; j < byte_run; j++) {
00621                             *((signed short*)(&pixels[pixel_ptr])) = pixel;
00622                             pixel_ptr += 2;
00623                             pixel_countdown--;
00624                             if (pixel_countdown < 0)
00625                                 av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n",
00626                                        pixel_countdown);
00627                         }
00628                     } else {  /* copy pixels if byte_run < 0 */
00629                         byte_run = -byte_run;
00630                         CHECK_PIXEL_PTR(2 * byte_run);
00631                         for (j = 0; j < byte_run; j++) {
00632                             *((signed short*)(&pixels[pixel_ptr])) = AV_RL16(&buf[stream_ptr]);
00633                             stream_ptr += 2;
00634                             pixel_ptr  += 2;
00635                             pixel_countdown--;
00636                             if (pixel_countdown < 0)
00637                                 av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n",
00638                                        pixel_countdown);
00639                         }
00640                     }
00641                 }
00642 
00643                 y_ptr += s->frame.linesize[0];
00644             }
00645             break;
00646 
00647         case FLI_COPY:
00648         case FLI_DTA_COPY:
00649             /* copy the chunk (uncompressed frame) */
00650             if (chunk_size - 6 > (unsigned int)(s->avctx->width * s->avctx->height)*2) {
00651                 av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \
00652                        "bigger than image, skipping chunk\n", chunk_size - 6);
00653                 stream_ptr += chunk_size - 6;
00654             } else {
00655 
00656                 for (y_ptr = 0; y_ptr < s->frame.linesize[0] * s->avctx->height;
00657                      y_ptr += s->frame.linesize[0]) {
00658 
00659                     pixel_countdown = s->avctx->width;
00660                     pixel_ptr = 0;
00661                     while (pixel_countdown > 0) {
00662                       *((signed short*)(&pixels[y_ptr + pixel_ptr])) = AV_RL16(&buf[stream_ptr+pixel_ptr]);
00663                       pixel_ptr += 2;
00664                       pixel_countdown--;
00665                     }
00666                     stream_ptr += s->avctx->width*2;
00667                 }
00668             }
00669             break;
00670 
00671         case FLI_MINI:
00672             /* some sort of a thumbnail? disregard this chunk... */
00673             stream_ptr += chunk_size - 6;
00674             break;
00675 
00676         default:
00677             av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type);
00678             break;
00679         }
00680 
00681         frame_size -= chunk_size;
00682         num_chunks--;
00683     }
00684 
00685     /* by the end of the chunk, the stream ptr should equal the frame
00686      * size (minus 1, possibly); if it doesn't, issue a warning */
00687     if ((stream_ptr != buf_size) && (stream_ptr != buf_size - 1))
00688         av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \
00689                "and final chunk ptr = %d\n", buf_size, stream_ptr);
00690 
00691 
00692     *data_size=sizeof(AVFrame);
00693     *(AVFrame*)data = s->frame;
00694 
00695     return buf_size;
00696 }
00697 
00698 static int flic_decode_frame_24BPP(AVCodecContext *avctx,
00699                                    void *data, int *data_size,
00700                                    const uint8_t *buf, int buf_size)
00701 {
00702   av_log(avctx, AV_LOG_ERROR, "24Bpp FLC Unsupported due to lack of test files.\n");
00703   return -1;
00704 }
00705 
00706 static int flic_decode_frame(AVCodecContext *avctx,
00707                              void *data, int *data_size,
00708                              AVPacket *avpkt)
00709 {
00710     const uint8_t *buf = avpkt->data;
00711     int buf_size = avpkt->size;
00712     if (avctx->pix_fmt == PIX_FMT_PAL8) {
00713       return flic_decode_frame_8BPP(avctx, data, data_size,
00714                                     buf, buf_size);
00715     }
00716     else if ((avctx->pix_fmt == PIX_FMT_RGB555) ||
00717              (avctx->pix_fmt == PIX_FMT_RGB565)) {
00718       return flic_decode_frame_15_16BPP(avctx, data, data_size,
00719                                         buf, buf_size);
00720     }
00721     else if (avctx->pix_fmt == PIX_FMT_BGR24) {
00722       return flic_decode_frame_24BPP(avctx, data, data_size,
00723                                      buf, buf_size);
00724     }
00725 
00726     /* Should not get  here, ever as the pix_fmt is processed */
00727     /* in flic_decode_init and the above if should deal with */
00728     /* the finite set of possibilites allowable by here. */
00729     /* But in case we do, just error out. */
00730     av_log(avctx, AV_LOG_ERROR, "Unknown FLC format, my science cannot explain how this happened.\n");
00731     return -1;
00732 }
00733 
00734 
00735 static av_cold int flic_decode_end(AVCodecContext *avctx)
00736 {
00737     FlicDecodeContext *s = avctx->priv_data;
00738 
00739     if (s->frame.data[0])
00740         avctx->release_buffer(avctx, &s->frame);
00741 
00742     return 0;
00743 }
00744 
00745 AVCodec flic_decoder = {
00746     "flic",
00747     AVMEDIA_TYPE_VIDEO,
00748     CODEC_ID_FLIC,
00749     sizeof(FlicDecodeContext),
00750     flic_decode_init,
00751     NULL,
00752     flic_decode_end,
00753     flic_decode_frame,
00754     CODEC_CAP_DR1,
00755     NULL,
00756     NULL,
00757     NULL,
00758     NULL,
00759     .long_name = NULL_IF_CONFIG_SMALL("Autodesk Animator Flic video"),
00760 };

Generated on Fri Sep 16 2011 17:17:36 for FFmpeg by  doxygen 1.7.1