qtrle.c
Go to the documentation of this file.
1 /*
2  * Quicktime Animation (RLE) Video Decoder
3  * Copyright (C) 2004 the ffmpeg project
4  *
5  * This file is part of Libav.
6  *
7  * Libav 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.
11  *
12  * Libav 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.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with Libav; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 
38 #include "libavutil/intreadwrite.h"
39 #include "avcodec.h"
40 
41 typedef struct QtrleContext {
42 
45 
46  const unsigned char *buf;
47  int size;
48 
49  uint32_t pal[256];
50 } QtrleContext;
51 
52 #define CHECK_STREAM_PTR(n) \
53  if ((stream_ptr + n) > s->size) { \
54  av_log (s->avctx, AV_LOG_INFO, "Problem: stream_ptr out of bounds (%d >= %d)\n", \
55  stream_ptr + n, s->size); \
56  return; \
57  }
58 
59 #define CHECK_PIXEL_PTR(n) \
60  if ((pixel_ptr + n > pixel_limit) || (pixel_ptr + n < 0)) { \
61  av_log (s->avctx, AV_LOG_INFO, "Problem: pixel_ptr = %d, pixel_limit = %d\n", \
62  pixel_ptr + n, pixel_limit); \
63  return; \
64  } \
65 
66 static void qtrle_decode_1bpp(QtrleContext *s, int stream_ptr, int row_ptr, int lines_to_change)
67 {
68  int rle_code;
69  int pixel_ptr = 0;
70  int row_inc = s->frame.linesize[0];
71  unsigned char pi0, pi1; /* 2 8-pixel values */
72  unsigned char *rgb = s->frame.data[0];
73  int pixel_limit = s->frame.linesize[0] * s->avctx->height;
74  int skip;
75 
76  while (lines_to_change) {
78  skip = s->buf[stream_ptr++];
79  rle_code = (signed char)s->buf[stream_ptr++];
80  if (rle_code == 0)
81  break;
82  if(skip & 0x80) {
83  lines_to_change--;
84  row_ptr += row_inc;
85  pixel_ptr = row_ptr + 2 * (skip & 0x7f);
86  } else
87  pixel_ptr += 2 * skip;
88  CHECK_PIXEL_PTR(0); /* make sure pixel_ptr is positive */
89 
90  if (rle_code < 0) {
91  /* decode the run length code */
92  rle_code = -rle_code;
93  /* get the next 2 bytes from the stream, treat them as groups
94  * of 8 pixels, and output them rle_code times */
96  pi0 = s->buf[stream_ptr++];
97  pi1 = s->buf[stream_ptr++];
98  CHECK_PIXEL_PTR(rle_code * 2);
99 
100  while (rle_code--) {
101  rgb[pixel_ptr++] = pi0;
102  rgb[pixel_ptr++] = pi1;
103  }
104  } else {
105  /* copy the same pixel directly to output 2 times */
106  rle_code *= 2;
107  CHECK_STREAM_PTR(rle_code);
108  CHECK_PIXEL_PTR(rle_code);
109 
110  while (rle_code--)
111  rgb[pixel_ptr++] = s->buf[stream_ptr++];
112  }
113  }
114 }
115 
116 static inline void qtrle_decode_2n4bpp(QtrleContext *s, int stream_ptr,
117  int row_ptr, int lines_to_change, int bpp)
118 {
119  int rle_code, i;
120  int pixel_ptr;
121  int row_inc = s->frame.linesize[0];
122  unsigned char pi[16]; /* 16 palette indices */
123  unsigned char *rgb = s->frame.data[0];
124  int pixel_limit = s->frame.linesize[0] * s->avctx->height;
125  int num_pixels = (bpp == 4) ? 8 : 16;
126 
127  while (lines_to_change--) {
128  CHECK_STREAM_PTR(2);
129  pixel_ptr = row_ptr + (num_pixels * (s->buf[stream_ptr++] - 1));
130 
131  while ((rle_code = (signed char)s->buf[stream_ptr++]) != -1) {
132  if (rle_code == 0) {
133  /* there's another skip code in the stream */
134  CHECK_STREAM_PTR(1);
135  pixel_ptr += (num_pixels * (s->buf[stream_ptr++] - 1));
136  CHECK_PIXEL_PTR(0); /* make sure pixel_ptr is positive */
137  } else if (rle_code < 0) {
138  /* decode the run length code */
139  rle_code = -rle_code;
140  /* get the next 4 bytes from the stream, treat them as palette
141  * indexes, and output them rle_code times */
142  CHECK_STREAM_PTR(4);
143  for (i = num_pixels-1; i >= 0; i--) {
144  pi[num_pixels-1-i] = (s->buf[stream_ptr] >> ((i*bpp) & 0x07)) & ((1<<bpp)-1);
145  stream_ptr+= ((i & ((num_pixels>>2)-1)) == 0);
146  }
147  CHECK_PIXEL_PTR(rle_code * num_pixels);
148  while (rle_code--) {
149  for (i = 0; i < num_pixels; i++)
150  rgb[pixel_ptr++] = pi[i];
151  }
152  } else {
153  /* copy the same pixel directly to output 4 times */
154  rle_code *= 4;
155  CHECK_STREAM_PTR(rle_code);
156  CHECK_PIXEL_PTR(rle_code*(num_pixels>>2));
157  while (rle_code--) {
158  if(bpp == 4) {
159  rgb[pixel_ptr++] = ((s->buf[stream_ptr]) >> 4) & 0x0f;
160  rgb[pixel_ptr++] = (s->buf[stream_ptr++]) & 0x0f;
161  } else {
162  rgb[pixel_ptr++] = ((s->buf[stream_ptr]) >> 6) & 0x03;
163  rgb[pixel_ptr++] = ((s->buf[stream_ptr]) >> 4) & 0x03;
164  rgb[pixel_ptr++] = ((s->buf[stream_ptr]) >> 2) & 0x03;
165  rgb[pixel_ptr++] = (s->buf[stream_ptr++]) & 0x03;
166  }
167  }
168  }
169  }
170  row_ptr += row_inc;
171  }
172 }
173 
174 static void qtrle_decode_8bpp(QtrleContext *s, int stream_ptr, int row_ptr, int lines_to_change)
175 {
176  int rle_code;
177  int pixel_ptr;
178  int row_inc = s->frame.linesize[0];
179  unsigned char pi1, pi2, pi3, pi4; /* 4 palette indexes */
180  unsigned char *rgb = s->frame.data[0];
181  int pixel_limit = s->frame.linesize[0] * s->avctx->height;
182 
183  while (lines_to_change--) {
184  CHECK_STREAM_PTR(2);
185  pixel_ptr = row_ptr + (4 * (s->buf[stream_ptr++] - 1));
186 
187  while ((rle_code = (signed char)s->buf[stream_ptr++]) != -1) {
188  if (rle_code == 0) {
189  /* there's another skip code in the stream */
190  CHECK_STREAM_PTR(1);
191  pixel_ptr += (4 * (s->buf[stream_ptr++] - 1));
192  CHECK_PIXEL_PTR(0); /* make sure pixel_ptr is positive */
193  } else if (rle_code < 0) {
194  /* decode the run length code */
195  rle_code = -rle_code;
196  /* get the next 4 bytes from the stream, treat them as palette
197  * indexes, and output them rle_code times */
198  CHECK_STREAM_PTR(4);
199  pi1 = s->buf[stream_ptr++];
200  pi2 = s->buf[stream_ptr++];
201  pi3 = s->buf[stream_ptr++];
202  pi4 = s->buf[stream_ptr++];
203 
204  CHECK_PIXEL_PTR(rle_code * 4);
205 
206  while (rle_code--) {
207  rgb[pixel_ptr++] = pi1;
208  rgb[pixel_ptr++] = pi2;
209  rgb[pixel_ptr++] = pi3;
210  rgb[pixel_ptr++] = pi4;
211  }
212  } else {
213  /* copy the same pixel directly to output 4 times */
214  rle_code *= 4;
215  CHECK_STREAM_PTR(rle_code);
216  CHECK_PIXEL_PTR(rle_code);
217 
218  while (rle_code--) {
219  rgb[pixel_ptr++] = s->buf[stream_ptr++];
220  }
221  }
222  }
223  row_ptr += row_inc;
224  }
225 }
226 
227 static void qtrle_decode_16bpp(QtrleContext *s, int stream_ptr, int row_ptr, int lines_to_change)
228 {
229  int rle_code;
230  int pixel_ptr;
231  int row_inc = s->frame.linesize[0];
232  unsigned short rgb16;
233  unsigned char *rgb = s->frame.data[0];
234  int pixel_limit = s->frame.linesize[0] * s->avctx->height;
235 
236  while (lines_to_change--) {
237  CHECK_STREAM_PTR(2);
238  pixel_ptr = row_ptr + (s->buf[stream_ptr++] - 1) * 2;
239 
240  while ((rle_code = (signed char)s->buf[stream_ptr++]) != -1) {
241  if (rle_code == 0) {
242  /* there's another skip code in the stream */
243  CHECK_STREAM_PTR(1);
244  pixel_ptr += (s->buf[stream_ptr++] - 1) * 2;
245  CHECK_PIXEL_PTR(0); /* make sure pixel_ptr is positive */
246  } else if (rle_code < 0) {
247  /* decode the run length code */
248  rle_code = -rle_code;
249  CHECK_STREAM_PTR(2);
250  rgb16 = AV_RB16(&s->buf[stream_ptr]);
251  stream_ptr += 2;
252 
253  CHECK_PIXEL_PTR(rle_code * 2);
254 
255  while (rle_code--) {
256  *(unsigned short *)(&rgb[pixel_ptr]) = rgb16;
257  pixel_ptr += 2;
258  }
259  } else {
260  CHECK_STREAM_PTR(rle_code * 2);
261  CHECK_PIXEL_PTR(rle_code * 2);
262 
263  /* copy pixels directly to output */
264  while (rle_code--) {
265  rgb16 = AV_RB16(&s->buf[stream_ptr]);
266  stream_ptr += 2;
267  *(unsigned short *)(&rgb[pixel_ptr]) = rgb16;
268  pixel_ptr += 2;
269  }
270  }
271  }
272  row_ptr += row_inc;
273  }
274 }
275 
276 static void qtrle_decode_24bpp(QtrleContext *s, int stream_ptr, int row_ptr, int lines_to_change)
277 {
278  int rle_code;
279  int pixel_ptr;
280  int row_inc = s->frame.linesize[0];
281  unsigned char r, g, b;
282  unsigned char *rgb = s->frame.data[0];
283  int pixel_limit = s->frame.linesize[0] * s->avctx->height;
284 
285  while (lines_to_change--) {
286  CHECK_STREAM_PTR(2);
287  pixel_ptr = row_ptr + (s->buf[stream_ptr++] - 1) * 3;
288 
289  while ((rle_code = (signed char)s->buf[stream_ptr++]) != -1) {
290  if (rle_code == 0) {
291  /* there's another skip code in the stream */
292  CHECK_STREAM_PTR(1);
293  pixel_ptr += (s->buf[stream_ptr++] - 1) * 3;
294  CHECK_PIXEL_PTR(0); /* make sure pixel_ptr is positive */
295  } else if (rle_code < 0) {
296  /* decode the run length code */
297  rle_code = -rle_code;
298  CHECK_STREAM_PTR(3);
299  r = s->buf[stream_ptr++];
300  g = s->buf[stream_ptr++];
301  b = s->buf[stream_ptr++];
302 
303  CHECK_PIXEL_PTR(rle_code * 3);
304 
305  while (rle_code--) {
306  rgb[pixel_ptr++] = r;
307  rgb[pixel_ptr++] = g;
308  rgb[pixel_ptr++] = b;
309  }
310  } else {
311  CHECK_STREAM_PTR(rle_code * 3);
312  CHECK_PIXEL_PTR(rle_code * 3);
313 
314  /* copy pixels directly to output */
315  while (rle_code--) {
316  rgb[pixel_ptr++] = s->buf[stream_ptr++];
317  rgb[pixel_ptr++] = s->buf[stream_ptr++];
318  rgb[pixel_ptr++] = s->buf[stream_ptr++];
319  }
320  }
321  }
322  row_ptr += row_inc;
323  }
324 }
325 
326 static void qtrle_decode_32bpp(QtrleContext *s, int stream_ptr, int row_ptr, int lines_to_change)
327 {
328  int rle_code;
329  int pixel_ptr;
330  int row_inc = s->frame.linesize[0];
331  unsigned int argb;
332  unsigned char *rgb = s->frame.data[0];
333  int pixel_limit = s->frame.linesize[0] * s->avctx->height;
334 
335  while (lines_to_change--) {
336  CHECK_STREAM_PTR(2);
337  pixel_ptr = row_ptr + (s->buf[stream_ptr++] - 1) * 4;
338 
339  while ((rle_code = (signed char)s->buf[stream_ptr++]) != -1) {
340  if (rle_code == 0) {
341  /* there's another skip code in the stream */
342  CHECK_STREAM_PTR(1);
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;
348  CHECK_STREAM_PTR(4);
349  argb = AV_RB32(s->buf + stream_ptr);
350  stream_ptr += 4;
351 
352  CHECK_PIXEL_PTR(rle_code * 4);
353 
354  while (rle_code--) {
355  AV_WN32A(rgb + pixel_ptr, argb);
356  pixel_ptr += 4;
357  }
358  } else {
359  CHECK_STREAM_PTR(rle_code * 4);
360  CHECK_PIXEL_PTR(rle_code * 4);
361 
362  /* copy pixels directly to output */
363  while (rle_code--) {
364  argb = AV_RB32(s->buf + stream_ptr);
365  AV_WN32A(rgb + pixel_ptr, argb);
366  stream_ptr += 4;
367  pixel_ptr += 4;
368  }
369  }
370  }
371  row_ptr += row_inc;
372  }
373 }
374 
376 {
377  QtrleContext *s = avctx->priv_data;
378 
379  s->avctx = avctx;
380  switch (avctx->bits_per_coded_sample) {
381  case 1:
382  case 33:
383  avctx->pix_fmt = PIX_FMT_MONOWHITE;
384  break;
385 
386  case 2:
387  case 4:
388  case 8:
389  case 34:
390  case 36:
391  case 40:
392  avctx->pix_fmt = PIX_FMT_PAL8;
393  break;
394 
395  case 16:
396  avctx->pix_fmt = PIX_FMT_RGB555;
397  break;
398 
399  case 24:
400  avctx->pix_fmt = PIX_FMT_RGB24;
401  break;
402 
403  case 32:
404  avctx->pix_fmt = PIX_FMT_RGB32;
405  break;
406 
407  default:
408  av_log (avctx, AV_LOG_ERROR, "Unsupported colorspace: %d bits/sample?\n",
409  avctx->bits_per_coded_sample);
410  return AVERROR_INVALIDDATA;
411  }
412 
413  s->frame.data[0] = NULL;
414 
415  return 0;
416 }
417 
419  void *data, int *data_size,
420  AVPacket *avpkt)
421 {
422  const uint8_t *buf = avpkt->data;
423  int buf_size = avpkt->size;
424  QtrleContext *s = avctx->priv_data;
425  int header, start_line;
426  int stream_ptr, height, row_ptr;
427  int has_palette = 0;
428 
429  s->buf = buf;
430  s->size = buf_size;
431 
432  s->frame.reference = 1;
435  if (avctx->reget_buffer(avctx, &s->frame)) {
436  av_log (s->avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
437  return -1;
438  }
439 
440  /* check if this frame is even supposed to change */
441  if (s->size < 8)
442  goto done;
443 
444  /* start after the chunk size */
445  stream_ptr = 4;
446 
447  /* fetch the header */
448  header = AV_RB16(&s->buf[stream_ptr]);
449  stream_ptr += 2;
450 
451  /* if a header is present, fetch additional decoding parameters */
452  if (header & 0x0008) {
453  if(s->size < 14)
454  goto done;
455  start_line = AV_RB16(&s->buf[stream_ptr]);
456  stream_ptr += 4;
457  height = AV_RB16(&s->buf[stream_ptr]);
458  stream_ptr += 4;
459  } else {
460  start_line = 0;
461  height = s->avctx->height;
462  }
463  row_ptr = s->frame.linesize[0] * start_line;
464 
465  switch (avctx->bits_per_coded_sample) {
466  case 1:
467  case 33:
468  qtrle_decode_1bpp(s, stream_ptr, row_ptr, height);
469  break;
470 
471  case 2:
472  case 34:
473  qtrle_decode_2n4bpp(s, stream_ptr, row_ptr, height, 2);
474  has_palette = 1;
475  break;
476 
477  case 4:
478  case 36:
479  qtrle_decode_2n4bpp(s, stream_ptr, row_ptr, height, 4);
480  has_palette = 1;
481  break;
482 
483  case 8:
484  case 40:
485  qtrle_decode_8bpp(s, stream_ptr, row_ptr, height);
486  has_palette = 1;
487  break;
488 
489  case 16:
490  qtrle_decode_16bpp(s, stream_ptr, row_ptr, height);
491  break;
492 
493  case 24:
494  qtrle_decode_24bpp(s, stream_ptr, row_ptr, height);
495  break;
496 
497  case 32:
498  qtrle_decode_32bpp(s, stream_ptr, row_ptr, height);
499  break;
500 
501  default:
502  av_log (s->avctx, AV_LOG_ERROR, "Unsupported colorspace: %d bits/sample?\n",
503  avctx->bits_per_coded_sample);
504  break;
505  }
506 
507  if(has_palette) {
508  const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, NULL);
509 
510  if (pal) {
511  s->frame.palette_has_changed = 1;
512  memcpy(s->pal, pal, AVPALETTE_SIZE);
513  }
514 
515  /* make the palette available on the way out */
516  memcpy(s->frame.data[1], s->pal, AVPALETTE_SIZE);
517  }
518 
519 done:
520  *data_size = sizeof(AVFrame);
521  *(AVFrame*)data = s->frame;
522 
523  /* always report that the buffer was completely consumed */
524  return buf_size;
525 }
526 
528 {
529  QtrleContext *s = avctx->priv_data;
530 
531  if (s->frame.data[0])
532  avctx->release_buffer(avctx, &s->frame);
533 
534  return 0;
535 }
536 
538  .name = "qtrle",
539  .type = AVMEDIA_TYPE_VIDEO,
540  .id = CODEC_ID_QTRLE,
541  .priv_data_size = sizeof(QtrleContext),
545  .capabilities = CODEC_CAP_DR1,
546  .long_name = NULL_IF_CONFIG_SMALL("QuickTime Animation (RLE) video"),
547 };
548