• 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 Libav.
00006  *
00007  * Libav 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  * Libav 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 Libav; 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     uint32_t pal[256];
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 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                 argb = AV_RB32(s->buf + stream_ptr);
00350                 stream_ptr += 4;
00351 
00352                 CHECK_PIXEL_PTR(rle_code * 4);
00353 
00354                 while (rle_code--) {
00355                     AV_WN32A(rgb + pixel_ptr, argb);
00356                     pixel_ptr += 4;
00357                 }
00358             } else {
00359                 CHECK_STREAM_PTR(rle_code * 4);
00360                 CHECK_PIXEL_PTR(rle_code * 4);
00361 
00362                 /* copy pixels directly to output */
00363                 while (rle_code--) {
00364                     argb = AV_RB32(s->buf + stream_ptr);
00365                     AV_WN32A(rgb + pixel_ptr, argb);
00366                     stream_ptr += 4;
00367                     pixel_ptr  += 4;
00368                 }
00369             }
00370         }
00371         row_ptr += row_inc;
00372     }
00373 }
00374 
00375 static av_cold int qtrle_decode_init(AVCodecContext *avctx)
00376 {
00377     QtrleContext *s = avctx->priv_data;
00378 
00379     s->avctx = avctx;
00380     switch (avctx->bits_per_coded_sample) {
00381     case 1:
00382     case 33:
00383         avctx->pix_fmt = PIX_FMT_MONOWHITE;
00384         break;
00385 
00386     case 2:
00387     case 4:
00388     case 8:
00389     case 34:
00390     case 36:
00391     case 40:
00392         avctx->pix_fmt = PIX_FMT_PAL8;
00393         break;
00394 
00395     case 16:
00396         avctx->pix_fmt = PIX_FMT_RGB555;
00397         break;
00398 
00399     case 24:
00400         avctx->pix_fmt = PIX_FMT_RGB24;
00401         break;
00402 
00403     case 32:
00404         avctx->pix_fmt = PIX_FMT_RGB32;
00405         break;
00406 
00407     default:
00408         av_log (avctx, AV_LOG_ERROR, "Unsupported colorspace: %d bits/sample?\n",
00409             avctx->bits_per_coded_sample);
00410         return AVERROR_INVALIDDATA;
00411     }
00412 
00413     s->frame.data[0] = NULL;
00414 
00415     return 0;
00416 }
00417 
00418 static int qtrle_decode_frame(AVCodecContext *avctx,
00419                               void *data, int *data_size,
00420                               AVPacket *avpkt)
00421 {
00422     const uint8_t *buf = avpkt->data;
00423     int buf_size = avpkt->size;
00424     QtrleContext *s = avctx->priv_data;
00425     int header, start_line;
00426     int stream_ptr, height, row_ptr;
00427     int has_palette = 0;
00428 
00429     s->buf = buf;
00430     s->size = buf_size;
00431 
00432     s->frame.reference = 1;
00433     s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE |
00434                             FF_BUFFER_HINTS_REUSABLE | FF_BUFFER_HINTS_READABLE;
00435     if (avctx->reget_buffer(avctx, &s->frame)) {
00436         av_log (s->avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
00437         return -1;
00438     }
00439 
00440     /* check if this frame is even supposed to change */
00441     if (s->size < 8)
00442         goto done;
00443 
00444     /* start after the chunk size */
00445     stream_ptr = 4;
00446 
00447     /* fetch the header */
00448     header = AV_RB16(&s->buf[stream_ptr]);
00449     stream_ptr += 2;
00450 
00451     /* if a header is present, fetch additional decoding parameters */
00452     if (header & 0x0008) {
00453         if(s->size < 14)
00454             goto done;
00455         start_line = AV_RB16(&s->buf[stream_ptr]);
00456         stream_ptr += 4;
00457         height = AV_RB16(&s->buf[stream_ptr]);
00458         stream_ptr += 4;
00459     } else {
00460         start_line = 0;
00461         height = s->avctx->height;
00462     }
00463     row_ptr = s->frame.linesize[0] * start_line;
00464 
00465     switch (avctx->bits_per_coded_sample) {
00466     case 1:
00467     case 33:
00468         qtrle_decode_1bpp(s, stream_ptr, row_ptr, height);
00469         break;
00470 
00471     case 2:
00472     case 34:
00473         qtrle_decode_2n4bpp(s, stream_ptr, row_ptr, height, 2);
00474         has_palette = 1;
00475         break;
00476 
00477     case 4:
00478     case 36:
00479         qtrle_decode_2n4bpp(s, stream_ptr, row_ptr, height, 4);
00480         has_palette = 1;
00481         break;
00482 
00483     case 8:
00484     case 40:
00485         qtrle_decode_8bpp(s, stream_ptr, row_ptr, height);
00486         has_palette = 1;
00487         break;
00488 
00489     case 16:
00490         qtrle_decode_16bpp(s, stream_ptr, row_ptr, height);
00491         break;
00492 
00493     case 24:
00494         qtrle_decode_24bpp(s, stream_ptr, row_ptr, height);
00495         break;
00496 
00497     case 32:
00498         qtrle_decode_32bpp(s, stream_ptr, row_ptr, height);
00499         break;
00500 
00501     default:
00502         av_log (s->avctx, AV_LOG_ERROR, "Unsupported colorspace: %d bits/sample?\n",
00503             avctx->bits_per_coded_sample);
00504         break;
00505     }
00506 
00507     if(has_palette) {
00508         const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, NULL);
00509 
00510         if (pal) {
00511             s->frame.palette_has_changed = 1;
00512             memcpy(s->pal, pal, AVPALETTE_SIZE);
00513         }
00514 
00515         /* make the palette available on the way out */
00516         memcpy(s->frame.data[1], s->pal, AVPALETTE_SIZE);
00517     }
00518 
00519 done:
00520     *data_size = sizeof(AVFrame);
00521     *(AVFrame*)data = s->frame;
00522 
00523     /* always report that the buffer was completely consumed */
00524     return buf_size;
00525 }
00526 
00527 static av_cold int qtrle_decode_end(AVCodecContext *avctx)
00528 {
00529     QtrleContext *s = avctx->priv_data;
00530 
00531     if (s->frame.data[0])
00532         avctx->release_buffer(avctx, &s->frame);
00533 
00534     return 0;
00535 }
00536 
00537 AVCodec ff_qtrle_decoder = {
00538     .name           = "qtrle",
00539     .type           = AVMEDIA_TYPE_VIDEO,
00540     .id             = CODEC_ID_QTRLE,
00541     .priv_data_size = sizeof(QtrleContext),
00542     .init           = qtrle_decode_init,
00543     .close          = qtrle_decode_end,
00544     .decode         = qtrle_decode_frame,
00545     .capabilities   = CODEC_CAP_DR1,
00546     .long_name = NULL_IF_CONFIG_SMALL("QuickTime Animation (RLE) video"),
00547 };
00548 
Generated on Sun Apr 22 2012 21:54:03 for Libav by doxygen 1.7.1