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

Generated on Tue Nov 4 2014 12:59:21 for ffmpeg by  doxygen 1.7.1