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