FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
qdrw.c
Go to the documentation of this file.
1 /*
2  * QuickDraw (qdrw) codec
3  * Copyright (c) 2004 Konstantin Shishkov
4  * Copyright (c) 2015 Vittorio Giovara
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 /**
24  * @file
25  * Apple QuickDraw codec.
26  * https://developer.apple.com/legacy/library/documentation/mac/QuickDraw/QuickDraw-461.html
27  */
28 
29 #include "libavutil/common.h"
30 #include "libavutil/intreadwrite.h"
31 #include "avcodec.h"
32 #include "bytestream.h"
33 #include "internal.h"
34 
36  CLIP = 0x0001,
37  PACKBITSRECT = 0x0098,
41  SHORTCOMMENT = 0x00A0,
43 
44  EOP = 0x00FF,
45 };
46 
48  uint32_t *pal, int colors)
49 {
50  int i;
51 
52  for (i = 0; i <= colors; i++) {
53  uint8_t r, g, b;
54  unsigned int idx = bytestream2_get_be16(gbc); /* color index */
55  if (idx > 255) {
56  av_log(avctx, AV_LOG_WARNING,
57  "Palette index out of range: %u\n", idx);
58  bytestream2_skip(gbc, 6);
59  continue;
60  }
61  r = bytestream2_get_byte(gbc);
62  bytestream2_skip(gbc, 1);
63  g = bytestream2_get_byte(gbc);
64  bytestream2_skip(gbc, 1);
65  b = bytestream2_get_byte(gbc);
66  bytestream2_skip(gbc, 1);
67  pal[idx] = (0xFFU << 24) | (r << 16) | (g << 8) | b;
68  }
69  return 0;
70 }
71 
73 {
74  int offset = avctx->width;
75  uint8_t *outdata = p->data[0];
76  int i, j;
77 
78  for (i = 0; i < avctx->height; i++) {
79  int size, left, code, pix;
80  uint8_t *out = outdata;
81  int pos = 0;
82 
83  /* size of packed line */
84  size = left = bytestream2_get_be16(gbc);
85  if (bytestream2_get_bytes_left(gbc) < size)
86  return AVERROR_INVALIDDATA;
87 
88  /* decode line */
89  while (left > 0) {
90  code = bytestream2_get_byte(gbc);
91  if (code & 0x80 ) { /* run */
92  pix = bytestream2_get_byte(gbc);
93  for (j = 0; j < 257 - code; j++) {
94  out[pos++] = (pix & 0xC0) >> 6;
95  out[pos++] = (pix & 0x30) >> 4;
96  out[pos++] = (pix & 0x0C) >> 2;
97  out[pos++] = (pix & 0x03);
98  if (pos >= offset) {
99  pos -= offset;
100  pos++;
101  }
102  if (pos >= offset)
103  return AVERROR_INVALIDDATA;
104  }
105  left -= 2;
106  } else { /* copy */
107  for (j = 0; j < code + 1; j++) {
108  pix = bytestream2_get_byte(gbc);
109  out[pos++] = (pix & 0xC0) >> 6;
110  out[pos++] = (pix & 0x30) >> 4;
111  out[pos++] = (pix & 0x0C) >> 2;
112  out[pos++] = (pix & 0x03);
113  if (pos >= offset) {
114  pos -= offset;
115  pos++;
116  }
117  if (pos >= offset)
118  return AVERROR_INVALIDDATA;
119  }
120  left -= 1 + (code + 1);
121  }
122  }
123  outdata += p->linesize[0];
124  }
125  return 0;
126 }
127 
129 {
130  int offset = avctx->width;
131  uint8_t *outdata = p->data[0];
132  int i, j;
133 
134  for (i = 0; i < avctx->height; i++) {
135  int size, left, code, pix;
136  uint8_t *out = outdata;
137  int pos = 0;
138 
139  /* size of packed line */
140  size = left = bytestream2_get_be16(gbc);
141  if (bytestream2_get_bytes_left(gbc) < size)
142  return AVERROR_INVALIDDATA;
143 
144  /* decode line */
145  while (left > 0) {
146  code = bytestream2_get_byte(gbc);
147  if (code & 0x80 ) { /* run */
148  pix = bytestream2_get_byte(gbc);
149  for (j = 0; j < 257 - code; j++) {
150  out[pos++] = (pix & 0xF0) >> 4;
151  out[pos++] = pix & 0xF;
152  if (pos >= offset) {
153  pos -= offset;
154  pos++;
155  }
156  if (pos >= offset)
157  return AVERROR_INVALIDDATA;
158  }
159  left -= 2;
160  } else { /* copy */
161  for (j = 0; j < code + 1; j++) {
162  pix = bytestream2_get_byte(gbc);
163  out[pos++] = (pix & 0xF0) >> 4;
164  out[pos++] = pix & 0xF;
165  if (pos >= offset) {
166  pos -= offset;
167  pos++;
168  }
169  if (pos >= offset)
170  return AVERROR_INVALIDDATA;
171  }
172  left -= 1 + (code + 1);
173  }
174  }
175  outdata += p->linesize[0];
176  }
177  return 0;
178 }
179 
180 static int decode_rle16(AVCodecContext *avctx, AVFrame *p, GetByteContext *gbc)
181 {
182  int offset = avctx->width;
183  uint8_t *outdata = p->data[0];
184  int i, j;
185 
186  for (i = 0; i < avctx->height; i++) {
187  int size, left, code, pix;
188  uint16_t *out = (uint16_t *)outdata;
189  int pos = 0;
190 
191  /* size of packed line */
192  size = left = bytestream2_get_be16(gbc);
193  if (bytestream2_get_bytes_left(gbc) < size)
194  return AVERROR_INVALIDDATA;
195 
196  /* decode line */
197  while (left > 0) {
198  code = bytestream2_get_byte(gbc);
199  if (code & 0x80 ) { /* run */
200  pix = bytestream2_get_be16(gbc);
201  for (j = 0; j < 257 - code; j++) {
202  out[pos] = pix;
203  pos++;
204  if (pos >= offset) {
205  pos -= offset;
206  pos++;
207  }
208  if (pos >= offset)
209  return AVERROR_INVALIDDATA;
210  }
211  left -= 3;
212  } else { /* copy */
213  for (j = 0; j < code + 1; j++) {
214  out[pos] = bytestream2_get_be16(gbc);
215  pos++;
216  if (pos >= offset) {
217  pos -= offset;
218  pos++;
219  }
220  if (pos >= offset)
221  return AVERROR_INVALIDDATA;
222  }
223  left -= 1 + (code + 1) * 2;
224  }
225  }
226  outdata += p->linesize[0];
227  }
228  return 0;
229 }
230 
231 static int decode_rle(AVCodecContext *avctx, AVFrame *p, GetByteContext *gbc,
232  int step)
233 {
234  int i, j;
235  int offset = avctx->width * step;
236  uint8_t *outdata = p->data[0];
237 
238  for (i = 0; i < avctx->height; i++) {
239  int size, left, code, pix;
240  uint8_t *out = outdata;
241  int pos = 0;
242 
243  /* size of packed line */
244  size = left = bytestream2_get_be16(gbc);
245  if (bytestream2_get_bytes_left(gbc) < size)
246  return AVERROR_INVALIDDATA;
247 
248  /* decode line */
249  while (left > 0) {
250  code = bytestream2_get_byte(gbc);
251  if (code & 0x80 ) { /* run */
252  pix = bytestream2_get_byte(gbc);
253  for (j = 0; j < 257 - code; j++) {
254  out[pos] = pix;
255  pos += step;
256  if (pos >= offset) {
257  pos -= offset;
258  pos++;
259  }
260  if (pos >= offset)
261  return AVERROR_INVALIDDATA;
262  }
263  left -= 2;
264  } else { /* copy */
265  for (j = 0; j < code + 1; j++) {
266  out[pos] = bytestream2_get_byte(gbc);
267  pos += step;
268  if (pos >= offset) {
269  pos -= offset;
270  pos++;
271  }
272  if (pos >= offset)
273  return AVERROR_INVALIDDATA;
274  }
275  left -= 2 + code;
276  }
277  }
278  outdata += p->linesize[0];
279  }
280  return 0;
281 }
282 
283 static int check_header(const char *buf, int buf_size)
284 {
285  unsigned w, h, v0, v1;
286 
287  if (buf_size < 40)
288  return 0;
289 
290  w = AV_RB16(buf+6);
291  h = AV_RB16(buf+8);
292  v0 = AV_RB16(buf+10);
293  v1 = AV_RB16(buf+12);
294 
295  if (!w || !h)
296  return 0;
297 
298  if (v0 == 0x1101)
299  return 1;
300  if (v0 == 0x0011 && v1 == 0x02FF)
301  return 2;
302  return 0;
303 }
304 
305 
306 static int decode_frame(AVCodecContext *avctx,
307  void *data, int *got_frame,
308  AVPacket *avpkt)
309 {
310  AVFrame * const p = data;
311  GetByteContext gbc;
312  int colors;
313  int w, h, ret;
314  int ver;
315 
316  bytestream2_init(&gbc, avpkt->data, avpkt->size);
317  if ( bytestream2_get_bytes_left(&gbc) >= 552
318  && check_header(gbc.buffer + 512, bytestream2_get_bytes_left(&gbc) - 512)
319  )
320  bytestream2_skip(&gbc, 512);
321 
323 
324  /* smallest PICT header */
325  if (bytestream2_get_bytes_left(&gbc) < 40) {
326  av_log(avctx, AV_LOG_ERROR, "Frame is too small %d\n",
328  return AVERROR_INVALIDDATA;
329  }
330 
331  bytestream2_skip(&gbc, 6);
332  h = bytestream2_get_be16(&gbc);
333  w = bytestream2_get_be16(&gbc);
334 
335  ret = ff_set_dimensions(avctx, w, h);
336  if (ret < 0)
337  return ret;
338 
339  /* version 1 is identified by 0x1101
340  * it uses byte-aligned opcodes rather than word-aligned */
341  if (ver == 1) {
342  avpriv_request_sample(avctx, "QuickDraw version 1");
343  return AVERROR_PATCHWELCOME;
344  } else if (ver != 2) {
345  avpriv_request_sample(avctx, "QuickDraw version unknown (%X)", bytestream2_get_be32(&gbc));
346  return AVERROR_PATCHWELCOME;
347  }
348 
349  bytestream2_skip(&gbc, 4+26);
350 
351  while (bytestream2_get_bytes_left(&gbc) >= 4) {
352  int bppcnt, bpp;
353  int rowbytes, pack_type;
354  int opcode = bytestream2_get_be16(&gbc);
355 
356  switch(opcode) {
357  case CLIP:
358  bytestream2_skip(&gbc, 10);
359  break;
360  case PACKBITSRECT:
361  case PACKBITSRGN:
362  av_log(avctx, AV_LOG_DEBUG, "Parsing Packbit opcode\n");
363 
364  bytestream2_skip(&gbc, 30);
365  bppcnt = bytestream2_get_be16(&gbc); /* cmpCount */
366  bpp = bytestream2_get_be16(&gbc); /* cmpSize */
367 
368  av_log(avctx, AV_LOG_DEBUG, "bppcount %d bpp %d\n", bppcnt, bpp);
369  if (bppcnt == 1 && bpp == 8) {
370  avctx->pix_fmt = AV_PIX_FMT_PAL8;
371  } else if (bppcnt == 1 && (bpp == 4 || bpp == 2)) {
372  avctx->pix_fmt = AV_PIX_FMT_PAL8;
373  } else if (bppcnt == 3 && bpp == 5) {
374  avctx->pix_fmt = AV_PIX_FMT_RGB555;
375  } else {
376  av_log(avctx, AV_LOG_ERROR,
377  "Invalid pixel format (bppcnt %d bpp %d) in Packbit\n",
378  bppcnt, bpp);
379  return AVERROR_INVALIDDATA;
380  }
381 
382  /* jump to palette */
383  bytestream2_skip(&gbc, 18);
384  colors = bytestream2_get_be16(&gbc);
385 
386  if (colors < 0 || colors > 256) {
387  av_log(avctx, AV_LOG_ERROR,
388  "Error color count - %i(0x%X)\n", colors, colors);
389  return AVERROR_INVALIDDATA;
390  }
391  if (bytestream2_get_bytes_left(&gbc) < (colors + 1) * 8) {
392  av_log(avctx, AV_LOG_ERROR, "Palette is too small %d\n",
394  return AVERROR_INVALIDDATA;
395  }
396  if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
397  return ret;
398 
399  parse_palette(avctx, &gbc, (uint32_t *)p->data[1], colors);
400  p->palette_has_changed = 1;
401 
402  /* jump to image data */
403  bytestream2_skip(&gbc, 18);
404 
405  if (opcode == PACKBITSRGN) {
406  bytestream2_skip(&gbc, 2 + 8); /* size + rect */
407  avpriv_report_missing_feature(avctx, "Packbit mask region");
408  }
409 
410  if (avctx->pix_fmt == AV_PIX_FMT_RGB555)
411  ret = decode_rle16(avctx, p, &gbc);
412  else if (bpp == 2)
413  ret = decode_rle_bpp2(avctx, p, &gbc);
414  else if (bpp == 4)
415  ret = decode_rle_bpp4(avctx, p, &gbc);
416  else
417  ret = decode_rle(avctx, p, &gbc, bppcnt);
418  if (ret < 0)
419  return ret;
420  *got_frame = 1;
421  break;
422  case DIRECTBITSRECT:
423  case DIRECTBITSRGN:
424  av_log(avctx, AV_LOG_DEBUG, "Parsing Directbit opcode\n");
425 
426  bytestream2_skip(&gbc, 4);
427  rowbytes = bytestream2_get_be16(&gbc) & 0x3FFF;
428  if (rowbytes <= 250) {
429  avpriv_report_missing_feature(avctx, "Short rowbytes");
430  return AVERROR_PATCHWELCOME;
431  }
432 
433  bytestream2_skip(&gbc, 4);
434  h = bytestream2_get_be16(&gbc);
435  w = bytestream2_get_be16(&gbc);
436  bytestream2_skip(&gbc, 2);
437 
438  ret = ff_set_dimensions(avctx, w, h);
439  if (ret < 0)
440  return ret;
441 
442  pack_type = bytestream2_get_be16(&gbc);
443 
444  bytestream2_skip(&gbc, 16);
445  bppcnt = bytestream2_get_be16(&gbc); /* cmpCount */
446  bpp = bytestream2_get_be16(&gbc); /* cmpSize */
447 
448  av_log(avctx, AV_LOG_DEBUG, "bppcount %d bpp %d\n", bppcnt, bpp);
449  if (bppcnt == 3 && bpp == 8) {
450  avctx->pix_fmt = AV_PIX_FMT_RGB24;
451  } else if (bppcnt == 3 && bpp == 5) {
452  avctx->pix_fmt = AV_PIX_FMT_RGB555;
453  } else if (bppcnt == 4 && bpp == 8) {
454  avctx->pix_fmt = AV_PIX_FMT_ARGB;
455  } else {
456  av_log(avctx, AV_LOG_ERROR,
457  "Invalid pixel format (bppcnt %d bpp %d) in Directbit\n",
458  bppcnt, bpp);
459  return AVERROR_INVALIDDATA;
460  }
461 
462  /* set packing when default is selected */
463  if (pack_type == 0)
464  pack_type = bppcnt;
465 
466  if (pack_type != 3 && pack_type != 4) {
467  avpriv_request_sample(avctx, "Pack type %d", pack_type);
468  return AVERROR_PATCHWELCOME;
469  }
470  if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
471  return ret;
472 
473  /* jump to data */
474  bytestream2_skip(&gbc, 30);
475 
476  if (opcode == DIRECTBITSRGN) {
477  bytestream2_skip(&gbc, 2 + 8); /* size + rect */
478  avpriv_report_missing_feature(avctx, "DirectBit mask region");
479  }
480 
481  if (avctx->pix_fmt == AV_PIX_FMT_RGB555)
482  ret = decode_rle16(avctx, p, &gbc);
483  else
484  ret = decode_rle(avctx, p, &gbc, bppcnt);
485  if (ret < 0)
486  return ret;
487  *got_frame = 1;
488  break;
489  case LONGCOMMENT:
490  bytestream2_get_be16(&gbc);
491  bytestream2_skip(&gbc, bytestream2_get_be16(&gbc));
492  break;
493  default:
494  av_log(avctx, AV_LOG_TRACE, "Unknown 0x%04X opcode\n", opcode);
495  break;
496  }
497  /* exit the loop when a known pixel block has been found */
498  if (*got_frame) {
499  int eop, trail;
500 
501  /* re-align to a word */
503 
504  eop = bytestream2_get_be16(&gbc);
505  trail = bytestream2_get_bytes_left(&gbc);
506  if (eop != EOP)
507  av_log(avctx, AV_LOG_WARNING,
508  "Missing end of picture opcode (found 0x%04X)\n", eop);
509  if (trail)
510  av_log(avctx, AV_LOG_WARNING, "Got %d trailing bytes\n", trail);
511  break;
512  }
513  }
514 
515  if (*got_frame) {
517  p->key_frame = 1;
518 
519  return avpkt->size;
520  } else {
521  av_log(avctx, AV_LOG_ERROR, "Frame contained no usable data\n");
522 
523  return AVERROR_INVALIDDATA;
524  }
525 }
526 
528  .name = "qdraw",
529  .long_name = NULL_IF_CONFIG_SMALL("Apple QuickDraw"),
530  .type = AVMEDIA_TYPE_VIDEO,
531  .id = AV_CODEC_ID_QDRAW,
532  .decode = decode_frame,
533  .capabilities = AV_CODEC_CAP_DR1,
534 };
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
This structure describes decoded (raw) audio or video data.
Definition: frame.h:190
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:101
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:64
int ff_set_dimensions(AVCodecContext *s, int width, int height)
Check that the provided frame dimensions are valid and set them on the codec context.
Definition: utils.c:210
const char * g
Definition: vf_curves.c:112
int size
Definition: avcodec.h:1617
const char * b
Definition: vf_curves.c:113
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:1919
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:133
Definition: qdrw.c:36
GLfloat v0
Definition: opengl_enc.c:107
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_WB32 unsigned int_TMPL AV_WB24 unsigned int_TMPL AV_RB16
Definition: bytestream.h:87
AVCodec.
Definition: avcodec.h:3646
Definition: qdrw.c:44
void void avpriv_request_sample(void *avc, const char *msg,...) av_printf_format(2
Log a generic warning message about a missing feature.
static int parse_palette(AVCodecContext *avctx, GetByteContext *gbc, uint32_t *pal, int colors)
Definition: qdrw.c:47
uint8_t
8 bits with AV_PIX_FMT_RGB32 palette
Definition: pixfmt.h:73
AVCodec ff_qdraw_decoder
Definition: qdrw.c:527
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition: log.h:202
uint8_t * data
Definition: avcodec.h:1616
const uint8_t * buffer
Definition: bytestream.h:34
ptrdiff_t size
Definition: opengl_enc.c:101
#define av_log(a,...)
static int decode_rle_bpp4(AVCodecContext *avctx, AVFrame *p, GetByteContext *gbc)
Definition: qdrw.c:128
#define U(x)
Definition: vp56_arith.h:37
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition: bytestream.h:164
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:180
const char * r
Definition: vf_curves.c:111
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:197
static av_always_inline unsigned int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:154
static int decode_rle(AVCodecContext *avctx, AVFrame *p, GetByteContext *gbc, int step)
Definition: qdrw.c:231
const char * name
Name of the codec implementation.
Definition: avcodec.h:3653
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: qdrw.c:306
static const uint8_t offset[127][2]
Definition: vf_spp.c:92
packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
Definition: pixfmt.h:93
static int decode_rle16(AVCodecContext *avctx, AVFrame *p, GetByteContext *gbc)
Definition: qdrw.c:180
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:264
int width
picture width / height.
Definition: avcodec.h:1878
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:62
Libavcodec external API header.
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:221
main external API structure.
Definition: avcodec.h:1691
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: utils.c:953
void * buf
Definition: avisynth_c.h:690
int palette_has_changed
Tell user application that palette has changed from previous frame.
Definition: frame.h:338
void avpriv_report_missing_feature(void *avc, const char *msg,...) av_printf_format(2
Log a generic warning message about a missing feature.
QuickdrawOpcodes
Definition: qdrw.c:35
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:204
common internal api header.
common internal and external API header
static int decode_rle_bpp2(AVCodecContext *avctx, AVFrame *p, GetByteContext *gbc)
Definition: qdrw.c:72
#define AV_PIX_FMT_RGB555
Definition: pixfmt.h:339
int key_frame
1 -> keyframe, 0-> not
Definition: frame.h:259
static int check_header(const char *buf, int buf_size)
Definition: qdrw.c:283
FILE * out
Definition: movenc.c:54
This structure stores compressed data.
Definition: avcodec.h:1593
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
Definition: avcodec.h:968