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

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