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

libavcodec/qtrle.c

Go to the documentation of this file.
00001 /*
00002  * Quicktime Animation (RLE) Video Decoder
00003  * Copyright (C) 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 
00034 #include <stdio.h>
00035 #include <stdlib.h>
00036 #include <string.h>
00037 
00038 #include "libavutil/intreadwrite.h"
00039 #include "avcodec.h"
00040 
00041 typedef struct QtrleContext {
00042 
00043     AVCodecContext *avctx;
00044     AVFrame frame;
00045 
00046     const unsigned char *buf;
00047     int size;
00048 
00049 } QtrleContext;
00050 
00051 #define CHECK_STREAM_PTR(n) \
00052   if ((stream_ptr + n) > s->size) { \
00053     av_log (s->avctx, AV_LOG_INFO, "Problem: stream_ptr out of bounds (%d >= %d)\n", \
00054       stream_ptr + n, s->size); \
00055     return; \
00056   }
00057 
00058 #define CHECK_PIXEL_PTR(n) \
00059   if ((pixel_ptr + n > pixel_limit) || (pixel_ptr + n < 0)) { \
00060     av_log (s->avctx, AV_LOG_INFO, "Problem: pixel_ptr = %d, pixel_limit = %d\n", \
00061       pixel_ptr + n, pixel_limit); \
00062     return; \
00063   } \
00064 
00065 static void qtrle_decode_1bpp(QtrleContext *s, int stream_ptr, int row_ptr, int lines_to_change)
00066 {
00067     int rle_code;
00068     int pixel_ptr = 0;
00069     int row_inc = s->frame.linesize[0];
00070     unsigned char pi0, pi1;  /* 2 8-pixel values */
00071     unsigned char *rgb = s->frame.data[0];
00072     int pixel_limit = s->frame.linesize[0] * s->avctx->height;
00073     int skip;
00074 
00075     while (lines_to_change) {
00076         CHECK_STREAM_PTR(2);
00077         skip = s->buf[stream_ptr++];
00078         rle_code = (signed char)s->buf[stream_ptr++];
00079         if (rle_code == 0)
00080             break;
00081         if(skip & 0x80) {
00082             lines_to_change--;
00083             row_ptr += row_inc;
00084             pixel_ptr = row_ptr + 2 * (skip & 0x7f);
00085         } else
00086             pixel_ptr += 2 * skip;
00087         CHECK_PIXEL_PTR(0);  /* make sure pixel_ptr is positive */
00088 
00089         if (rle_code < 0) {
00090             /* decode the run length code */
00091             rle_code = -rle_code;
00092             /* get the next 2 bytes from the stream, treat them as groups
00093              * of 8 pixels, and output them rle_code times */
00094             CHECK_STREAM_PTR(2);
00095             pi0 = s->buf[stream_ptr++];
00096             pi1 = s->buf[stream_ptr++];
00097             CHECK_PIXEL_PTR(rle_code * 2);
00098 
00099             while (rle_code--) {
00100                 rgb[pixel_ptr++] = pi0;
00101                 rgb[pixel_ptr++] = pi1;
00102             }
00103         } else {
00104             /* copy the same pixel directly to output 2 times */
00105             rle_code *= 2;
00106             CHECK_STREAM_PTR(rle_code);
00107             CHECK_PIXEL_PTR(rle_code);
00108 
00109             while (rle_code--)
00110                 rgb[pixel_ptr++] = s->buf[stream_ptr++];
00111         }
00112     }
00113 }
00114 
00115 static inline void qtrle_decode_2n4bpp(QtrleContext *s, int stream_ptr,
00116                              int row_ptr, int lines_to_change, int bpp)
00117 {
00118     int rle_code, i;
00119     int pixel_ptr;
00120     int row_inc = s->frame.linesize[0];
00121     unsigned char pi[16];  /* 16 palette indices */
00122     unsigned char *rgb = s->frame.data[0];
00123     int pixel_limit = s->frame.linesize[0] * s->avctx->height;
00124     int num_pixels = (bpp == 4) ? 8 : 16;
00125 
00126     while (lines_to_change--) {
00127         CHECK_STREAM_PTR(2);
00128         pixel_ptr = row_ptr + (num_pixels * (s->buf[stream_ptr++] - 1));
00129         CHECK_PIXEL_PTR(0);  /* make sure pixel_ptr is positive */
00130 
00131         while ((rle_code = (signed char)s->buf[stream_ptr++]) != -1) {
00132             if (rle_code == 0) {
00133                 /* there's another skip code in the stream */
00134                 CHECK_STREAM_PTR(1);
00135                 pixel_ptr += (num_pixels * (s->buf[stream_ptr++] - 1));
00136                 CHECK_PIXEL_PTR(0);  /* make sure pixel_ptr is positive */
00137             } else if (rle_code < 0) {
00138                 /* decode the run length code */
00139                 rle_code = -rle_code;
00140                 /* get the next 4 bytes from the stream, treat them as palette
00141                  * indexes, and output them rle_code times */
00142                 CHECK_STREAM_PTR(4);
00143                 for (i = num_pixels-1; i >= 0; i--) {
00144                     pi[num_pixels-1-i] = (s->buf[stream_ptr] >> ((i*bpp) & 0x07)) & ((1<<bpp)-1);
00145                     stream_ptr+= ((i & ((num_pixels>>2)-1)) == 0);
00146                 }
00147                 CHECK_PIXEL_PTR(rle_code * num_pixels);
00148                 while (rle_code--) {
00149                     for (i = 0; i < num_pixels; i++)
00150                         rgb[pixel_ptr++] = pi[i];
00151                 }
00152             } else {
00153                 /* copy the same pixel directly to output 4 times */
00154                 rle_code *= 4;
00155                 CHECK_STREAM_PTR(rle_code);
00156                 CHECK_PIXEL_PTR(rle_code*(num_pixels>>2));
00157                 while (rle_code--) {
00158                     if(bpp == 4) {
00159                         rgb[pixel_ptr++] = ((s->buf[stream_ptr]) >> 4) & 0x0f;
00160                         rgb[pixel_ptr++] = (s->buf[stream_ptr++]) & 0x0f;
00161                     } else {
00162                         rgb[pixel_ptr++] = ((s->buf[stream_ptr]) >> 6) & 0x03;
00163                         rgb[pixel_ptr++] = ((s->buf[stream_ptr]) >> 4) & 0x03;
00164                         rgb[pixel_ptr++] = ((s->buf[stream_ptr]) >> 2) & 0x03;
00165                         rgb[pixel_ptr++] = (s->buf[stream_ptr++]) & 0x03;
00166                     }
00167                 }
00168             }
00169         }
00170         row_ptr += row_inc;
00171     }
00172 }
00173 
00174 static void qtrle_decode_8bpp(QtrleContext *s, int stream_ptr, int row_ptr, int lines_to_change)
00175 {
00176     int rle_code;
00177     int pixel_ptr;
00178     int row_inc = s->frame.linesize[0];
00179     unsigned char pi1, pi2, pi3, pi4;  /* 4 palette indexes */
00180     unsigned char *rgb = s->frame.data[0];
00181     int pixel_limit = s->frame.linesize[0] * s->avctx->height;
00182 
00183     while (lines_to_change--) {
00184         CHECK_STREAM_PTR(2);
00185         pixel_ptr = row_ptr + (4 * (s->buf[stream_ptr++] - 1));
00186         CHECK_PIXEL_PTR(0);  /* make sure pixel_ptr is positive */
00187 
00188         while ((rle_code = (signed char)s->buf[stream_ptr++]) != -1) {
00189             if (rle_code == 0) {
00190                 /* there's another skip code in the stream */
00191                 CHECK_STREAM_PTR(1);
00192                 pixel_ptr += (4 * (s->buf[stream_ptr++] - 1));
00193                 CHECK_PIXEL_PTR(0);  /* make sure pixel_ptr is positive */
00194             } else if (rle_code < 0) {
00195                 /* decode the run length code */
00196                 rle_code = -rle_code;
00197                 /* get the next 4 bytes from the stream, treat them as palette
00198                  * indexes, and output them rle_code times */
00199                 CHECK_STREAM_PTR(4);
00200                 pi1 = s->buf[stream_ptr++];
00201                 pi2 = s->buf[stream_ptr++];
00202                 pi3 = s->buf[stream_ptr++];
00203                 pi4 = s->buf[stream_ptr++];
00204 
00205                 CHECK_PIXEL_PTR(rle_code * 4);
00206 
00207                 while (rle_code--) {
00208                     rgb[pixel_ptr++] = pi1;
00209                     rgb[pixel_ptr++] = pi2;
00210                     rgb[pixel_ptr++] = pi3;
00211                     rgb[pixel_ptr++] = pi4;
00212                 }
00213             } else {
00214                 /* copy the same pixel directly to output 4 times */
00215                 rle_code *= 4;
00216                 CHECK_STREAM_PTR(rle_code);
00217                 CHECK_PIXEL_PTR(rle_code);
00218 
00219                 while (rle_code--) {
00220                     rgb[pixel_ptr++] = s->buf[stream_ptr++];
00221                 }
00222             }
00223         }
00224         row_ptr += row_inc;
00225     }
00226 }
00227 
00228 static void qtrle_decode_16bpp(QtrleContext *s, int stream_ptr, int row_ptr, int lines_to_change)
00229 {
00230     int rle_code;
00231     int pixel_ptr;
00232     int row_inc = s->frame.linesize[0];
00233     unsigned short rgb16;
00234     unsigned char *rgb = s->frame.data[0];
00235     int pixel_limit = s->frame.linesize[0] * s->avctx->height;
00236 
00237     while (lines_to_change--) {
00238         CHECK_STREAM_PTR(2);
00239         pixel_ptr = row_ptr + (s->buf[stream_ptr++] - 1) * 2;
00240         CHECK_PIXEL_PTR(0);  /* make sure pixel_ptr is positive */
00241 
00242         while ((rle_code = (signed char)s->buf[stream_ptr++]) != -1) {
00243             if (rle_code == 0) {
00244                 /* there's another skip code in the stream */
00245                 CHECK_STREAM_PTR(1);
00246                 pixel_ptr += (s->buf[stream_ptr++] - 1) * 2;
00247                 CHECK_PIXEL_PTR(0);  /* make sure pixel_ptr is positive */
00248             } else if (rle_code < 0) {
00249                 /* decode the run length code */
00250                 rle_code = -rle_code;
00251                 CHECK_STREAM_PTR(2);
00252                 rgb16 = AV_RB16(&s->buf[stream_ptr]);
00253                 stream_ptr += 2;
00254 
00255                 CHECK_PIXEL_PTR(rle_code * 2);
00256 
00257                 while (rle_code--) {
00258                     *(unsigned short *)(&rgb[pixel_ptr]) = rgb16;
00259                     pixel_ptr += 2;
00260                 }
00261             } else {
00262                 CHECK_STREAM_PTR(rle_code * 2);
00263                 CHECK_PIXEL_PTR(rle_code * 2);
00264 
00265                 /* copy pixels directly to output */
00266                 while (rle_code--) {
00267                     rgb16 = AV_RB16(&s->buf[stream_ptr]);
00268                     stream_ptr += 2;
00269                     *(unsigned short *)(&rgb[pixel_ptr]) = rgb16;
00270                     pixel_ptr += 2;
00271                 }
00272             }
00273         }
00274         row_ptr += row_inc;
00275     }
00276 }
00277 
00278 static void qtrle_decode_24bpp(QtrleContext *s, int stream_ptr, int row_ptr, int lines_to_change)
00279 {
00280     int rle_code;
00281     int pixel_ptr;
00282     int row_inc = s->frame.linesize[0];
00283     unsigned char r, g, b;
00284     unsigned char *rgb = s->frame.data[0];
00285     int pixel_limit = s->frame.linesize[0] * s->avctx->height;
00286 
00287     while (lines_to_change--) {
00288         CHECK_STREAM_PTR(2);
00289         pixel_ptr = row_ptr + (s->buf[stream_ptr++] - 1) * 3;
00290         CHECK_PIXEL_PTR(0);  /* make sure pixel_ptr is positive */
00291 
00292         while ((rle_code = (signed char)s->buf[stream_ptr++]) != -1) {
00293             if (rle_code == 0) {
00294                 /* there's another skip code in the stream */
00295                 CHECK_STREAM_PTR(1);
00296                 pixel_ptr += (s->buf[stream_ptr++] - 1) * 3;
00297                 CHECK_PIXEL_PTR(0);  /* make sure pixel_ptr is positive */
00298             } else if (rle_code < 0) {
00299                 /* decode the run length code */
00300                 rle_code = -rle_code;
00301                 CHECK_STREAM_PTR(3);
00302                 r = s->buf[stream_ptr++];
00303                 g = s->buf[stream_ptr++];
00304                 b = s->buf[stream_ptr++];
00305 
00306                 CHECK_PIXEL_PTR(rle_code * 3);
00307 
00308                 while (rle_code--) {
00309                     rgb[pixel_ptr++] = r;
00310                     rgb[pixel_ptr++] = g;
00311                     rgb[pixel_ptr++] = b;
00312                 }
00313             } else {
00314                 CHECK_STREAM_PTR(rle_code * 3);
00315                 CHECK_PIXEL_PTR(rle_code * 3);
00316 
00317                 /* copy pixels directly to output */
00318                 while (rle_code--) {
00319                     rgb[pixel_ptr++] = s->buf[stream_ptr++];
00320                     rgb[pixel_ptr++] = s->buf[stream_ptr++];
00321                     rgb[pixel_ptr++] = s->buf[stream_ptr++];
00322                 }
00323             }
00324         }
00325         row_ptr += row_inc;
00326     }
00327 }
00328 
00329 static void qtrle_decode_32bpp(QtrleContext *s, int stream_ptr, int row_ptr, int lines_to_change)
00330 {
00331     int rle_code;
00332     int pixel_ptr;
00333     int row_inc = s->frame.linesize[0];
00334     unsigned char a, r, g, b;
00335     unsigned int argb;
00336     unsigned char *rgb = s->frame.data[0];
00337     int pixel_limit = s->frame.linesize[0] * s->avctx->height;
00338 
00339     while (lines_to_change--) {
00340         CHECK_STREAM_PTR(2);
00341         pixel_ptr = row_ptr + (s->buf[stream_ptr++] - 1) * 4;
00342         CHECK_PIXEL_PTR(0);  /* make sure pixel_ptr is positive */
00343 
00344         while ((rle_code = (signed char)s->buf[stream_ptr++]) != -1) {
00345             if (rle_code == 0) {
00346                 /* there's another skip code in the stream */
00347                 CHECK_STREAM_PTR(1);
00348                 pixel_ptr += (s->buf[stream_ptr++] - 1) * 4;
00349                 CHECK_PIXEL_PTR(0);  /* make sure pixel_ptr is positive */
00350             } else if (rle_code < 0) {
00351                 /* decode the run length code */
00352                 rle_code = -rle_code;
00353                 CHECK_STREAM_PTR(4);
00354                 a = s->buf[stream_ptr++];
00355                 r = s->buf[stream_ptr++];
00356                 g = s->buf[stream_ptr++];
00357                 b = s->buf[stream_ptr++];
00358                 argb = (a << 24) | (r << 16) | (g << 8) | (b << 0);
00359 
00360                 CHECK_PIXEL_PTR(rle_code * 4);
00361 
00362                 while (rle_code--) {
00363                     *(unsigned int *)(&rgb[pixel_ptr]) = argb;
00364                     pixel_ptr += 4;
00365                 }
00366             } else {
00367                 CHECK_STREAM_PTR(rle_code * 4);
00368                 CHECK_PIXEL_PTR(rle_code * 4);
00369 
00370                 /* copy pixels directly to output */
00371                 while (rle_code--) {
00372                     a = s->buf[stream_ptr++];
00373                     r = s->buf[stream_ptr++];
00374                     g = s->buf[stream_ptr++];
00375                     b = s->buf[stream_ptr++];
00376                     argb = (a << 24) | (r << 16) | (g << 8) | (b << 0);
00377                     *(unsigned int *)(&rgb[pixel_ptr]) = argb;
00378                     pixel_ptr += 4;
00379                 }
00380             }
00381         }
00382         row_ptr += row_inc;
00383     }
00384 }
00385 
00386 static av_cold int qtrle_decode_init(AVCodecContext *avctx)
00387 {
00388     QtrleContext *s = avctx->priv_data;
00389 
00390     s->avctx = avctx;
00391     switch (avctx->bits_per_coded_sample) {
00392     case 1:
00393     case 33:
00394         avctx->pix_fmt = PIX_FMT_MONOWHITE;
00395         break;
00396 
00397     case 2:
00398     case 4:
00399     case 8:
00400     case 34:
00401     case 36:
00402     case 40:
00403         avctx->pix_fmt = PIX_FMT_PAL8;
00404         break;
00405 
00406     case 16:
00407         avctx->pix_fmt = PIX_FMT_RGB555;
00408         break;
00409 
00410     case 24:
00411         avctx->pix_fmt = PIX_FMT_RGB24;
00412         break;
00413 
00414     case 32:
00415         avctx->pix_fmt = PIX_FMT_RGB32;
00416         break;
00417 
00418     default:
00419         av_log (avctx, AV_LOG_ERROR, "Unsupported colorspace: %d bits/sample?\n",
00420             avctx->bits_per_coded_sample);
00421         return AVERROR_INVALIDDATA;
00422     }
00423 
00424     avcodec_get_frame_defaults(&s->frame);
00425     s->frame.data[0] = NULL;
00426 
00427     return 0;
00428 }
00429 
00430 static int qtrle_decode_frame(AVCodecContext *avctx,
00431                               void *data, int *data_size,
00432                               AVPacket *avpkt)
00433 {
00434     const uint8_t *buf = avpkt->data;
00435     int buf_size = avpkt->size;
00436     QtrleContext *s = avctx->priv_data;
00437     int header, start_line;
00438     int stream_ptr, height, row_ptr;
00439     int has_palette = 0;
00440 
00441     s->buf = buf;
00442     s->size = buf_size;
00443 
00444     s->frame.reference = 1;
00445     s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE |
00446                             FF_BUFFER_HINTS_REUSABLE | FF_BUFFER_HINTS_READABLE;
00447     if (avctx->reget_buffer(avctx, &s->frame)) {
00448         av_log (s->avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
00449         return -1;
00450     }
00451 
00452     /* check if this frame is even supposed to change */
00453     if (s->size < 8)
00454         goto done;
00455 
00456     /* start after the chunk size */
00457     stream_ptr = 4;
00458 
00459     /* fetch the header */
00460     header = AV_RB16(&s->buf[stream_ptr]);
00461     stream_ptr += 2;
00462 
00463     /* if a header is present, fetch additional decoding parameters */
00464     if (header & 0x0008) {
00465         if(s->size < 14)
00466             goto done;
00467         start_line = AV_RB16(&s->buf[stream_ptr]);
00468         stream_ptr += 4;
00469         height = AV_RB16(&s->buf[stream_ptr]);
00470         stream_ptr += 4;
00471         if (height > s->avctx->height - start_line)
00472             goto done;
00473     } else {
00474         start_line = 0;
00475         height = s->avctx->height;
00476     }
00477     row_ptr = s->frame.linesize[0] * start_line;
00478 
00479     switch (avctx->bits_per_coded_sample) {
00480     case 1:
00481     case 33:
00482         qtrle_decode_1bpp(s, stream_ptr, row_ptr, height);
00483         break;
00484 
00485     case 2:
00486     case 34:
00487         qtrle_decode_2n4bpp(s, stream_ptr, row_ptr, height, 2);
00488         has_palette = 1;
00489         break;
00490 
00491     case 4:
00492     case 36:
00493         qtrle_decode_2n4bpp(s, stream_ptr, row_ptr, height, 4);
00494         has_palette = 1;
00495         break;
00496 
00497     case 8:
00498     case 40:
00499         qtrle_decode_8bpp(s, stream_ptr, row_ptr, height);
00500         has_palette = 1;
00501         break;
00502 
00503     case 16:
00504         qtrle_decode_16bpp(s, stream_ptr, row_ptr, height);
00505         break;
00506 
00507     case 24:
00508         qtrle_decode_24bpp(s, stream_ptr, row_ptr, height);
00509         break;
00510 
00511     case 32:
00512         qtrle_decode_32bpp(s, stream_ptr, row_ptr, height);
00513         break;
00514 
00515     default:
00516         av_log (s->avctx, AV_LOG_ERROR, "Unsupported colorspace: %d bits/sample?\n",
00517             avctx->bits_per_coded_sample);
00518         break;
00519     }
00520 
00521     if(has_palette) {
00522         /* make the palette available on the way out */
00523         memcpy(s->frame.data[1], s->avctx->palctrl->palette, AVPALETTE_SIZE);
00524         if (s->avctx->palctrl->palette_changed) {
00525             s->frame.palette_has_changed = 1;
00526             s->avctx->palctrl->palette_changed = 0;
00527         }
00528     }
00529 
00530 done:
00531     *data_size = sizeof(AVFrame);
00532     *(AVFrame*)data = s->frame;
00533 
00534     /* always report that the buffer was completely consumed */
00535     return buf_size;
00536 }
00537 
00538 static av_cold int qtrle_decode_end(AVCodecContext *avctx)
00539 {
00540     QtrleContext *s = avctx->priv_data;
00541 
00542     if (s->frame.data[0])
00543         avctx->release_buffer(avctx, &s->frame);
00544 
00545     return 0;
00546 }
00547 
00548 AVCodec ff_qtrle_decoder = {
00549     "qtrle",
00550     AVMEDIA_TYPE_VIDEO,
00551     CODEC_ID_QTRLE,
00552     sizeof(QtrleContext),
00553     qtrle_decode_init,
00554     NULL,
00555     qtrle_decode_end,
00556     qtrle_decode_frame,
00557     CODEC_CAP_DR1,
00558     .long_name = NULL_IF_CONFIG_SMALL("QuickTime Animation (RLE) video"),
00559 };
00560 

Generated on Wed Apr 11 2012 07:31:34 for FFmpeg by  doxygen 1.7.1