2 * Quicktime Animation (RLE) Video Decoder
3 * Copyright (C) 2004 the ffmpeg project
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 * @file libavcodec/qtrle.c
24 * QT RLE Video Decoder by Mike Melanson (melanson@pcisys.net)
25 * For more information about the QT RLE format, visit:
26 * http://www.pcisys.net/~melanson/codecs/
28 * The QT RLE decoder has seven modes of operation:
29 * 1, 2, 4, 8, 16, 24, and 32 bits per pixel. For modes 1, 2, 4, and 8
30 * the decoder outputs PAL8 colorspace data. 16-bit data yields RGB555
31 * data. 24-bit data is RGB24 and 32-bit data is RGB32.
38 #include "libavutil/intreadwrite.h"
41 typedef struct QtrleContext
{
43 AVCodecContext
*avctx
;
46 const unsigned char *buf
;
51 #define CHECK_STREAM_PTR(n) \
52 if ((stream_ptr + n) > s->size) { \
53 av_log (s->avctx, AV_LOG_INFO, "Problem: stream_ptr out of bounds (%d >= %d)\n", \
54 stream_ptr + n, s->size); \
58 #define CHECK_PIXEL_PTR(n) \
59 if ((pixel_ptr + n > pixel_limit) || (pixel_ptr + n < 0)) { \
60 av_log (s->avctx, AV_LOG_INFO, "Problem: pixel_ptr = %d, pixel_limit = %d\n", \
61 pixel_ptr + n, pixel_limit); \
65 static void qtrle_decode_1bpp(QtrleContext *s, int stream_ptr, int row_ptr, int lines_to_change)
69 int row_inc
= s
->frame
.linesize
[0];
70 unsigned char pi0
, pi1
; /* 2 8-pixel values */
71 unsigned char *rgb
= s
->frame
.data
[0];
72 int pixel_limit
= s
->frame
.linesize
[0] * s
->avctx
->height
;
75 while (lines_to_change
) {
77 skip
= s
->buf
[stream_ptr
++];
78 rle_code
= (signed char)s
->buf
[stream_ptr
++];
84 pixel_ptr
= row_ptr
+ 2 * (skip
& 0x7f);
86 pixel_ptr
+= 2 * skip
;
87 CHECK_PIXEL_PTR(0); /* make sure pixel_ptr is positive */
90 /* decode the run length code */
92 /* get the next 2 bytes from the stream, treat them as groups
93 * of 8 pixels, and output them rle_code times */
95 pi0
= s
->buf
[stream_ptr
++];
96 pi1
= s
->buf
[stream_ptr
++];
97 CHECK_PIXEL_PTR(rle_code
* 2);
100 rgb
[pixel_ptr
++] = pi0
;
101 rgb
[pixel_ptr
++] = pi1
;
104 /* copy the same pixel directly to output 2 times */
106 CHECK_STREAM_PTR(rle_code
);
107 CHECK_PIXEL_PTR(rle_code
);
110 rgb
[pixel_ptr
++] = s
->buf
[stream_ptr
++];
115 static inline void qtrle_decode_2n4bpp(QtrleContext
*s
, int stream_ptr
,
116 int row_ptr
, int lines_to_change
, int bpp
)
120 int row_inc
= s
->frame
.linesize
[0];
121 unsigned char pi
[16]; /* 16 palette indices */
122 unsigned char *rgb
= s
->frame
.data
[0];
123 int pixel_limit
= s
->frame
.linesize
[0] * s
->avctx
->height
;
124 int num_pixels
= (bpp
== 4) ? 8 : 16;
126 while (lines_to_change
--) {
128 pixel_ptr
= row_ptr
+ (num_pixels
* (s
->buf
[stream_ptr
++] - 1));
130 while ((rle_code
= (signed char)s
->buf
[stream_ptr
++]) != -1) {
132 /* there's another skip code in the stream */
134 pixel_ptr
+= (num_pixels
* (s
->buf
[stream_ptr
++] - 1));
135 CHECK_PIXEL_PTR(0); /* make sure pixel_ptr is positive */
136 } else if (rle_code
< 0) {
137 /* decode the run length code */
138 rle_code
= -rle_code
;
139 /* get the next 4 bytes from the stream, treat them as palette
140 * indexes, and output them rle_code times */
142 for (i
= num_pixels
-1; i
>= 0; i
--) {
143 pi
[num_pixels
-1-i
] = (s
->buf
[stream_ptr
] >> ((i
*bpp
) & 0x07)) & ((1<<bpp
)-1);
144 stream_ptr
+= ((i
& ((num_pixels
>>2)-1)) == 0);
146 CHECK_PIXEL_PTR(rle_code
* num_pixels
);
148 for (i
= 0; i
< num_pixels
; i
++)
149 rgb
[pixel_ptr
++] = pi
[i
];
152 /* copy the same pixel directly to output 4 times */
154 CHECK_STREAM_PTR(rle_code
);
155 CHECK_PIXEL_PTR(rle_code
*(num_pixels
>>2));
158 rgb
[pixel_ptr
++] = ((s
->buf
[stream_ptr
]) >> 4) & 0x0f;
159 rgb
[pixel_ptr
++] = (s
->buf
[stream_ptr
++]) & 0x0f;
161 rgb
[pixel_ptr
++] = ((s
->buf
[stream_ptr
]) >> 6) & 0x03;
162 rgb
[pixel_ptr
++] = ((s
->buf
[stream_ptr
]) >> 4) & 0x03;
163 rgb
[pixel_ptr
++] = ((s
->buf
[stream_ptr
]) >> 2) & 0x03;
164 rgb
[pixel_ptr
++] = (s
->buf
[stream_ptr
++]) & 0x03;
173 static void qtrle_decode_8bpp(QtrleContext
*s
, int stream_ptr
, int row_ptr
, int lines_to_change
)
177 int row_inc
= s
->frame
.linesize
[0];
178 unsigned char pi1
, pi2
, pi3
, pi4
; /* 4 palette indexes */
179 unsigned char *rgb
= s
->frame
.data
[0];
180 int pixel_limit
= s
->frame
.linesize
[0] * s
->avctx
->height
;
182 while (lines_to_change
--) {
184 pixel_ptr
= row_ptr
+ (4 * (s
->buf
[stream_ptr
++] - 1));
186 while ((rle_code
= (signed char)s
->buf
[stream_ptr
++]) != -1) {
188 /* there's another skip code in the stream */
190 pixel_ptr
+= (4 * (s
->buf
[stream_ptr
++] - 1));
191 CHECK_PIXEL_PTR(0); /* make sure pixel_ptr is positive */
192 } else if (rle_code
< 0) {
193 /* decode the run length code */
194 rle_code
= -rle_code
;
195 /* get the next 4 bytes from the stream, treat them as palette
196 * indexes, and output them rle_code times */
198 pi1
= s
->buf
[stream_ptr
++];
199 pi2
= s
->buf
[stream_ptr
++];
200 pi3
= s
->buf
[stream_ptr
++];
201 pi4
= s
->buf
[stream_ptr
++];
203 CHECK_PIXEL_PTR(rle_code
* 4);
206 rgb
[pixel_ptr
++] = pi1
;
207 rgb
[pixel_ptr
++] = pi2
;
208 rgb
[pixel_ptr
++] = pi3
;
209 rgb
[pixel_ptr
++] = pi4
;
212 /* copy the same pixel directly to output 4 times */
214 CHECK_STREAM_PTR(rle_code
);
215 CHECK_PIXEL_PTR(rle_code
);
218 rgb
[pixel_ptr
++] = s
->buf
[stream_ptr
++];
226 static void qtrle_decode_16bpp(QtrleContext
*s
, int stream_ptr
, int row_ptr
, int lines_to_change
)
230 int row_inc
= s
->frame
.linesize
[0];
231 unsigned short rgb16
;
232 unsigned char *rgb
= s
->frame
.data
[0];
233 int pixel_limit
= s
->frame
.linesize
[0] * s
->avctx
->height
;
235 while (lines_to_change
--) {
237 pixel_ptr
= row_ptr
+ (s
->buf
[stream_ptr
++] - 1) * 2;
239 while ((rle_code
= (signed char)s
->buf
[stream_ptr
++]) != -1) {
241 /* there's another skip code in the stream */
243 pixel_ptr
+= (s
->buf
[stream_ptr
++] - 1) * 2;
244 CHECK_PIXEL_PTR(0); /* make sure pixel_ptr is positive */
245 } else if (rle_code
< 0) {
246 /* decode the run length code */
247 rle_code
= -rle_code
;
249 rgb16
= AV_RB16(&s
->buf
[stream_ptr
]);
252 CHECK_PIXEL_PTR(rle_code
* 2);
255 *(unsigned short *)(&rgb
[pixel_ptr
]) = rgb16
;
259 CHECK_STREAM_PTR(rle_code
* 2);
260 CHECK_PIXEL_PTR(rle_code
* 2);
262 /* copy pixels directly to output */
264 rgb16
= AV_RB16(&s
->buf
[stream_ptr
]);
266 *(unsigned short *)(&rgb
[pixel_ptr
]) = rgb16
;
275 static void qtrle_decode_24bpp(QtrleContext
*s
, int stream_ptr
, int row_ptr
, int lines_to_change
)
279 int row_inc
= s
->frame
.linesize
[0];
280 unsigned char r
, g
, b
;
281 unsigned char *rgb
= s
->frame
.data
[0];
282 int pixel_limit
= s
->frame
.linesize
[0] * s
->avctx
->height
;
284 while (lines_to_change
--) {
286 pixel_ptr
= row_ptr
+ (s
->buf
[stream_ptr
++] - 1) * 3;
288 while ((rle_code
= (signed char)s
->buf
[stream_ptr
++]) != -1) {
290 /* there's another skip code in the stream */
292 pixel_ptr
+= (s
->buf
[stream_ptr
++] - 1) * 3;
293 CHECK_PIXEL_PTR(0); /* make sure pixel_ptr is positive */
294 } else if (rle_code
< 0) {
295 /* decode the run length code */
296 rle_code
= -rle_code
;
298 r
= s
->buf
[stream_ptr
++];
299 g
= s
->buf
[stream_ptr
++];
300 b
= s
->buf
[stream_ptr
++];
302 CHECK_PIXEL_PTR(rle_code
* 3);
305 rgb
[pixel_ptr
++] = r
;
306 rgb
[pixel_ptr
++] = g
;
307 rgb
[pixel_ptr
++] = b
;
310 CHECK_STREAM_PTR(rle_code
* 3);
311 CHECK_PIXEL_PTR(rle_code
* 3);
313 /* copy pixels directly to output */
315 rgb
[pixel_ptr
++] = s
->buf
[stream_ptr
++];
316 rgb
[pixel_ptr
++] = s
->buf
[stream_ptr
++];
317 rgb
[pixel_ptr
++] = s
->buf
[stream_ptr
++];
325 static void qtrle_decode_32bpp(QtrleContext
*s
, int stream_ptr
, int row_ptr
, int lines_to_change
)
329 int row_inc
= s
->frame
.linesize
[0];
330 unsigned char a
, r
, g
, b
;
332 unsigned char *rgb
= s
->frame
.data
[0];
333 int pixel_limit
= s
->frame
.linesize
[0] * s
->avctx
->height
;
335 while (lines_to_change
--) {
337 pixel_ptr
= row_ptr
+ (s
->buf
[stream_ptr
++] - 1) * 4;
339 while ((rle_code
= (signed char)s
->buf
[stream_ptr
++]) != -1) {
341 /* there's another skip code in the stream */
343 pixel_ptr
+= (s
->buf
[stream_ptr
++] - 1) * 4;
344 CHECK_PIXEL_PTR(0); /* make sure pixel_ptr is positive */
345 } else if (rle_code
< 0) {
346 /* decode the run length code */
347 rle_code
= -rle_code
;
349 a
= s
->buf
[stream_ptr
++];
350 r
= s
->buf
[stream_ptr
++];
351 g
= s
->buf
[stream_ptr
++];
352 b
= s
->buf
[stream_ptr
++];
353 argb
= (a
<< 24) | (r
<< 16) | (g
<< 8) | (b
<< 0);
355 CHECK_PIXEL_PTR(rle_code
* 4);
358 *(unsigned int *)(&rgb
[pixel_ptr
]) = argb
;
362 CHECK_STREAM_PTR(rle_code
* 4);
363 CHECK_PIXEL_PTR(rle_code
* 4);
365 /* copy pixels directly to output */
367 a
= s
->buf
[stream_ptr
++];
368 r
= s
->buf
[stream_ptr
++];
369 g
= s
->buf
[stream_ptr
++];
370 b
= s
->buf
[stream_ptr
++];
371 argb
= (a
<< 24) | (r
<< 16) | (g
<< 8) | (b
<< 0);
372 *(unsigned int *)(&rgb
[pixel_ptr
]) = argb
;
381 static av_cold
int qtrle_decode_init(AVCodecContext
*avctx
)
383 QtrleContext
*s
= avctx
->priv_data
;
386 switch (avctx
->bits_per_coded_sample
) {
389 avctx
->pix_fmt
= PIX_FMT_MONOWHITE
;
398 avctx
->pix_fmt
= PIX_FMT_PAL8
;
402 avctx
->pix_fmt
= PIX_FMT_RGB555
;
406 avctx
->pix_fmt
= PIX_FMT_RGB24
;
410 avctx
->pix_fmt
= PIX_FMT_RGB32
;
414 av_log (avctx
, AV_LOG_ERROR
, "Unsupported colorspace: %d bits/sample?\n",
415 avctx
->bits_per_coded_sample
);
419 s
->frame
.data
[0] = NULL
;
424 static int qtrle_decode_frame(AVCodecContext
*avctx
,
425 void *data
, int *data_size
,
428 const uint8_t *buf
= avpkt
->data
;
429 int buf_size
= avpkt
->size
;
430 QtrleContext
*s
= avctx
->priv_data
;
431 int header
, start_line
;
432 int stream_ptr
, height
, row_ptr
;
438 s
->frame
.reference
= 1;
439 s
->frame
.buffer_hints
= FF_BUFFER_HINTS_VALID
| FF_BUFFER_HINTS_PRESERVE
|
440 FF_BUFFER_HINTS_REUSABLE
| FF_BUFFER_HINTS_READABLE
;
441 if (avctx
->reget_buffer(avctx
, &s
->frame
)) {
442 av_log (s
->avctx
, AV_LOG_ERROR
, "reget_buffer() failed\n");
446 /* check if this frame is even supposed to change */
450 /* start after the chunk size */
453 /* fetch the header */
454 header
= AV_RB16(&s
->buf
[stream_ptr
]);
457 /* if a header is present, fetch additional decoding parameters */
458 if (header
& 0x0008) {
461 start_line
= AV_RB16(&s
->buf
[stream_ptr
]);
463 height
= AV_RB16(&s
->buf
[stream_ptr
]);
467 height
= s
->avctx
->height
;
469 row_ptr
= s
->frame
.linesize
[0] * start_line
;
471 switch (avctx
->bits_per_coded_sample
) {
474 qtrle_decode_1bpp(s
, stream_ptr
, row_ptr
, height
);
479 qtrle_decode_2n4bpp(s
, stream_ptr
, row_ptr
, height
, 2);
485 qtrle_decode_2n4bpp(s
, stream_ptr
, row_ptr
, height
, 4);
491 qtrle_decode_8bpp(s
, stream_ptr
, row_ptr
, height
);
496 qtrle_decode_16bpp(s
, stream_ptr
, row_ptr
, height
);
500 qtrle_decode_24bpp(s
, stream_ptr
, row_ptr
, height
);
504 qtrle_decode_32bpp(s
, stream_ptr
, row_ptr
, height
);
508 av_log (s
->avctx
, AV_LOG_ERROR
, "Unsupported colorspace: %d bits/sample?\n",
509 avctx
->bits_per_coded_sample
);
514 /* make the palette available on the way out */
515 memcpy(s
->frame
.data
[1], s
->avctx
->palctrl
->palette
, AVPALETTE_SIZE
);
516 if (s
->avctx
->palctrl
->palette_changed
) {
517 s
->frame
.palette_has_changed
= 1;
518 s
->avctx
->palctrl
->palette_changed
= 0;
523 *data_size
= sizeof(AVFrame
);
524 *(AVFrame
*)data
= s
->frame
;
526 /* always report that the buffer was completely consumed */
530 static av_cold
int qtrle_decode_end(AVCodecContext
*avctx
)
532 QtrleContext
*s
= avctx
->priv_data
;
534 if (s
->frame
.data
[0])
535 avctx
->release_buffer(avctx
, &s
->frame
);
540 AVCodec qtrle_decoder
= {
544 sizeof(QtrleContext
),
550 .long_name
= NULL_IF_CONFIG_SMALL("QuickTime Animation (RLE) video"),