Libav 0.7.1
|
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 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 return AVERROR_INVALIDDATA; 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 AVPacket *avpkt) 00428 { 00429 const uint8_t *buf = avpkt->data; 00430 int buf_size = avpkt->size; 00431 QtrleContext *s = avctx->priv_data; 00432 int header, start_line; 00433 int stream_ptr, height, row_ptr; 00434 int has_palette = 0; 00435 00436 s->buf = buf; 00437 s->size = buf_size; 00438 00439 s->frame.reference = 1; 00440 s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | 00441 FF_BUFFER_HINTS_REUSABLE | FF_BUFFER_HINTS_READABLE; 00442 if (avctx->reget_buffer(avctx, &s->frame)) { 00443 av_log (s->avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); 00444 return -1; 00445 } 00446 00447 /* check if this frame is even supposed to change */ 00448 if (s->size < 8) 00449 goto done; 00450 00451 /* start after the chunk size */ 00452 stream_ptr = 4; 00453 00454 /* fetch the header */ 00455 header = AV_RB16(&s->buf[stream_ptr]); 00456 stream_ptr += 2; 00457 00458 /* if a header is present, fetch additional decoding parameters */ 00459 if (header & 0x0008) { 00460 if(s->size < 14) 00461 goto done; 00462 start_line = AV_RB16(&s->buf[stream_ptr]); 00463 stream_ptr += 4; 00464 height = AV_RB16(&s->buf[stream_ptr]); 00465 stream_ptr += 4; 00466 } else { 00467 start_line = 0; 00468 height = s->avctx->height; 00469 } 00470 row_ptr = s->frame.linesize[0] * start_line; 00471 00472 switch (avctx->bits_per_coded_sample) { 00473 case 1: 00474 case 33: 00475 qtrle_decode_1bpp(s, stream_ptr, row_ptr, height); 00476 break; 00477 00478 case 2: 00479 case 34: 00480 qtrle_decode_2n4bpp(s, stream_ptr, row_ptr, height, 2); 00481 has_palette = 1; 00482 break; 00483 00484 case 4: 00485 case 36: 00486 qtrle_decode_2n4bpp(s, stream_ptr, row_ptr, height, 4); 00487 has_palette = 1; 00488 break; 00489 00490 case 8: 00491 case 40: 00492 qtrle_decode_8bpp(s, stream_ptr, row_ptr, height); 00493 has_palette = 1; 00494 break; 00495 00496 case 16: 00497 qtrle_decode_16bpp(s, stream_ptr, row_ptr, height); 00498 break; 00499 00500 case 24: 00501 qtrle_decode_24bpp(s, stream_ptr, row_ptr, height); 00502 break; 00503 00504 case 32: 00505 qtrle_decode_32bpp(s, stream_ptr, row_ptr, height); 00506 break; 00507 00508 default: 00509 av_log (s->avctx, AV_LOG_ERROR, "Unsupported colorspace: %d bits/sample?\n", 00510 avctx->bits_per_coded_sample); 00511 break; 00512 } 00513 00514 if(has_palette) { 00515 const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, NULL); 00516 00517 if (pal) { 00518 s->frame.palette_has_changed = 1; 00519 memcpy(s->pal, pal, AVPALETTE_SIZE); 00520 } 00521 00522 /* make the palette available on the way out */ 00523 memcpy(s->frame.data[1], s->pal, AVPALETTE_SIZE); 00524 } 00525 00526 done: 00527 *data_size = sizeof(AVFrame); 00528 *(AVFrame*)data = s->frame; 00529 00530 /* always report that the buffer was completely consumed */ 00531 return buf_size; 00532 } 00533 00534 static av_cold int qtrle_decode_end(AVCodecContext *avctx) 00535 { 00536 QtrleContext *s = avctx->priv_data; 00537 00538 if (s->frame.data[0]) 00539 avctx->release_buffer(avctx, &s->frame); 00540 00541 return 0; 00542 } 00543 00544 AVCodec ff_qtrle_decoder = { 00545 "qtrle", 00546 AVMEDIA_TYPE_VIDEO, 00547 CODEC_ID_QTRLE, 00548 sizeof(QtrleContext), 00549 qtrle_decode_init, 00550 NULL, 00551 qtrle_decode_end, 00552 qtrle_decode_frame, 00553 CODEC_CAP_DR1, 00554 .long_name = NULL_IF_CONFIG_SMALL("QuickTime Animation (RLE) video"), 00555 }; 00556