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