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

Generated on Sat Feb 16 2013 09:23:13 for ffmpeg by  doxygen 1.7.1