Libav
|
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