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, int pixmap)
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 && !pixmap) {
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  if (avctx->pix_fmt != AV_PIX_FMT_PAL8)
62  return AVERROR_INVALIDDATA;
63  r = bytestream2_get_byte(gbc);
64  bytestream2_skip(gbc, 1);
65  g = bytestream2_get_byte(gbc);
66  bytestream2_skip(gbc, 1);
67  b = bytestream2_get_byte(gbc);
68  bytestream2_skip(gbc, 1);
69  pal[pixmap ? i : idx] = (0xFFU << 24) | (r << 16) | (g << 8) | b;
70  }
71  return 0;
72 }
73 
75 {
76  int offset = avctx->width;
77  uint8_t *outdata = p->data[0];
78  int i, j;
79 
80  for (i = 0; i < avctx->height; i++) {
81  int size, left, code, pix;
82  uint8_t *out = outdata;
83  int pos = 0;
84 
85  /* size of packed line */
86  if (offset / 4 > 200)
87  size = left = bytestream2_get_be16(gbc);
88  else
89  size = left = bytestream2_get_byte(gbc);
90  if (bytestream2_get_bytes_left(gbc) < size)
91  return AVERROR_INVALIDDATA;
92 
93  /* decode line */
94  while (left > 0) {
95  code = bytestream2_get_byte(gbc);
96  if (code & 0x80 ) { /* run */
97  pix = bytestream2_get_byte(gbc);
98  for (j = 0; j < 257 - code; j++) {
99  if (pos < offset)
100  out[pos++] = (pix & 0xC0) >> 6;
101  if (pos < offset)
102  out[pos++] = (pix & 0x30) >> 4;
103  if (pos < offset)
104  out[pos++] = (pix & 0x0C) >> 2;
105  if (pos < offset)
106  out[pos++] = (pix & 0x03);
107  }
108  left -= 2;
109  } else { /* copy */
110  for (j = 0; j < code + 1; j++) {
111  pix = bytestream2_get_byte(gbc);
112  if (pos < offset)
113  out[pos++] = (pix & 0xC0) >> 6;
114  if (pos < offset)
115  out[pos++] = (pix & 0x30) >> 4;
116  if (pos < offset)
117  out[pos++] = (pix & 0x0C) >> 2;
118  if (pos < offset)
119  out[pos++] = (pix & 0x03);
120  }
121  left -= 1 + (code + 1);
122  }
123  }
124  outdata += p->linesize[0];
125  }
126  return 0;
127 }
128 
130 {
131  int offset = avctx->width;
132  uint8_t *outdata = p->data[0];
133  int i, j;
134 
135  for (i = 0; i < avctx->height; i++) {
136  int size, left, code, pix;
137  uint8_t *out = outdata;
138  int pos = 0;
139 
140  /* size of packed line */
141  size = left = bytestream2_get_be16(gbc);
142  if (bytestream2_get_bytes_left(gbc) < size)
143  return AVERROR_INVALIDDATA;
144 
145  /* decode line */
146  while (left > 0) {
147  code = bytestream2_get_byte(gbc);
148  if (code & 0x80 ) { /* run */
149  pix = bytestream2_get_byte(gbc);
150  for (j = 0; j < 257 - code; j++) {
151  if (pos < offset)
152  out[pos++] = (pix & 0xF0) >> 4;
153  if (pos < offset)
154  out[pos++] = pix & 0xF;
155  }
156  left -= 2;
157  } else { /* copy */
158  for (j = 0; j < code + 1; j++) {
159  pix = bytestream2_get_byte(gbc);
160  if (pos < offset)
161  out[pos++] = (pix & 0xF0) >> 4;
162  if (pos < offset)
163  out[pos++] = pix & 0xF;
164  }
165  left -= 1 + (code + 1);
166  }
167  }
168  outdata += p->linesize[0];
169  }
170  return 0;
171 }
172 
173 static int decode_rle16(AVCodecContext *avctx, AVFrame *p, GetByteContext *gbc)
174 {
175  int offset = avctx->width;
176  uint8_t *outdata = p->data[0];
177  int i, j;
178 
179  for (i = 0; i < avctx->height; i++) {
180  int size, left, code, pix;
181  uint16_t *out = (uint16_t *)outdata;
182  int pos = 0;
183 
184  /* size of packed line */
185  size = left = bytestream2_get_be16(gbc);
186  if (bytestream2_get_bytes_left(gbc) < size)
187  return AVERROR_INVALIDDATA;
188 
189  /* decode line */
190  while (left > 0) {
191  code = bytestream2_get_byte(gbc);
192  if (code & 0x80 ) { /* run */
193  pix = bytestream2_get_be16(gbc);
194  for (j = 0; j < 257 - code; j++) {
195  if (pos < offset) {
196  out[pos++] = pix;
197  }
198  }
199  left -= 3;
200  } else { /* copy */
201  for (j = 0; j < code + 1; j++) {
202  if (pos < offset) {
203  out[pos++] = bytestream2_get_be16(gbc);
204  } else {
205  bytestream2_skip(gbc, 2);
206  }
207  }
208  left -= 1 + (code + 1) * 2;
209  }
210  }
211  outdata += p->linesize[0];
212  }
213  return 0;
214 }
215 
216 static int decode_rle(AVCodecContext *avctx, AVFrame *p, GetByteContext *gbc,
217  int step)
218 {
219  int i, j;
220  int offset = avctx->width * step;
221  uint8_t *outdata = p->data[0];
222 
223  for (i = 0; i < avctx->height; i++) {
224  int size, left, code, pix;
225  uint8_t *out = outdata;
226  int pos = 0;
227 
228  /* size of packed line */
229  size = left = bytestream2_get_be16(gbc);
230  if (bytestream2_get_bytes_left(gbc) < size)
231  return AVERROR_INVALIDDATA;
232 
233  /* decode line */
234  while (left > 0) {
235  code = bytestream2_get_byte(gbc);
236  if (code & 0x80 ) { /* run */
237  pix = bytestream2_get_byte(gbc);
238  for (j = 0; j < 257 - code; j++) {
239  if (pos < offset)
240  out[pos] = pix;
241  pos += step;
242  if (pos >= offset && step > 1) {
243  pos -= offset;
244  pos++;
245  }
246  }
247  left -= 2;
248  } else { /* copy */
249  for (j = 0; j < code + 1; j++) {
250  pix = bytestream2_get_byte(gbc);
251  if (pos < offset)
252  out[pos] = pix;
253  pos += step;
254  if (pos >= offset && step > 1) {
255  pos -= offset;
256  pos++;
257  }
258  }
259  left -= 2 + code;
260  }
261  }
262  outdata += p->linesize[0];
263  }
264  return 0;
265 }
266 
267 static int check_header(const char *buf, int buf_size)
268 {
269  unsigned w, h, v0, v1;
270 
271  if (buf_size < 40)
272  return 0;
273 
274  w = AV_RB16(buf+6);
275  h = AV_RB16(buf+8);
276  v0 = AV_RB16(buf+10);
277  v1 = AV_RB16(buf+12);
278 
279  if (!w || !h)
280  return 0;
281 
282  if (v0 == 0x1101)
283  return 1;
284  if (v0 == 0x0011 && v1 == 0x02FF)
285  return 2;
286  return 0;
287 }
288 
289 
290 static int decode_frame(AVCodecContext *avctx,
291  void *data, int *got_frame,
292  AVPacket *avpkt)
293 {
294  AVFrame * const p = data;
295  GetByteContext gbc;
296  int colors;
297  int w, h, ret;
298  int ver;
299 
300  bytestream2_init(&gbc, avpkt->data, avpkt->size);
301  if ( bytestream2_get_bytes_left(&gbc) >= 552
302  && check_header(gbc.buffer + 512, bytestream2_get_bytes_left(&gbc) - 512)
303  )
304  bytestream2_skip(&gbc, 512);
305 
307 
308  /* smallest PICT header */
309  if (bytestream2_get_bytes_left(&gbc) < 40) {
310  av_log(avctx, AV_LOG_ERROR, "Frame is too small %d\n",
312  return AVERROR_INVALIDDATA;
313  }
314 
315  bytestream2_skip(&gbc, 6);
316  h = bytestream2_get_be16(&gbc);
317  w = bytestream2_get_be16(&gbc);
318 
319  ret = ff_set_dimensions(avctx, w, h);
320  if (ret < 0)
321  return ret;
322 
323  /* version 1 is identified by 0x1101
324  * it uses byte-aligned opcodes rather than word-aligned */
325  if (ver == 1) {
326  avpriv_request_sample(avctx, "QuickDraw version 1");
327  return AVERROR_PATCHWELCOME;
328  } else if (ver != 2) {
329  avpriv_request_sample(avctx, "QuickDraw version unknown (%X)", bytestream2_get_be32(&gbc));
330  return AVERROR_PATCHWELCOME;
331  }
332 
333  bytestream2_skip(&gbc, 4+26);
334 
335  while (bytestream2_get_bytes_left(&gbc) >= 4) {
336  int bppcnt, bpp;
337  int rowbytes, pack_type;
338  int flags;
339  int opcode = bytestream2_get_be16(&gbc);
340 
341  switch(opcode) {
342  case CLIP:
343  bytestream2_skip(&gbc, 10);
344  break;
345  case PACKBITSRECT:
346  case PACKBITSRGN:
347  av_log(avctx, AV_LOG_DEBUG, "Parsing Packbit opcode\n");
348 
349  flags = bytestream2_get_be16(&gbc) & 0xC000;
350  bytestream2_skip(&gbc, 28);
351  bppcnt = bytestream2_get_be16(&gbc); /* cmpCount */
352  bpp = bytestream2_get_be16(&gbc); /* cmpSize */
353 
354  av_log(avctx, AV_LOG_DEBUG, "bppcount %d bpp %d\n", bppcnt, bpp);
355  if (bppcnt == 1 && bpp == 8) {
356  avctx->pix_fmt = AV_PIX_FMT_PAL8;
357  } else if (bppcnt == 1 && (bpp == 4 || bpp == 2)) {
358  avctx->pix_fmt = AV_PIX_FMT_PAL8;
359  } else if (bppcnt == 3 && bpp == 5) {
360  avctx->pix_fmt = AV_PIX_FMT_RGB555;
361  } else {
362  av_log(avctx, AV_LOG_ERROR,
363  "Invalid pixel format (bppcnt %d bpp %d) in Packbit\n",
364  bppcnt, bpp);
365  return AVERROR_INVALIDDATA;
366  }
367 
368  /* jump to palette */
369  bytestream2_skip(&gbc, 18);
370  colors = bytestream2_get_be16(&gbc);
371 
372  if (colors < 0 || colors > 256) {
373  av_log(avctx, AV_LOG_ERROR,
374  "Error color count - %i(0x%X)\n", colors, colors);
375  return AVERROR_INVALIDDATA;
376  }
377  if (bytestream2_get_bytes_left(&gbc) < (colors + 1) * 8) {
378  av_log(avctx, AV_LOG_ERROR, "Palette is too small %d\n",
380  return AVERROR_INVALIDDATA;
381  }
382  if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
383  return ret;
384 
385  ret = parse_palette(avctx, &gbc, (uint32_t *)p->data[1], colors, flags & 0x8000);
386  if (ret < 0)
387  return ret;
388  p->palette_has_changed = 1;
389 
390  /* jump to image data */
391  bytestream2_skip(&gbc, 18);
392 
393  if (opcode == PACKBITSRGN) {
394  bytestream2_skip(&gbc, 2 + 8); /* size + rect */
395  avpriv_report_missing_feature(avctx, "Packbit mask region");
396  }
397 
398  if (avctx->pix_fmt == AV_PIX_FMT_RGB555)
399  ret = decode_rle16(avctx, p, &gbc);
400  else if (bpp == 2)
401  ret = decode_rle_bpp2(avctx, p, &gbc);
402  else if (bpp == 4)
403  ret = decode_rle_bpp4(avctx, p, &gbc);
404  else
405  ret = decode_rle(avctx, p, &gbc, bppcnt);
406  if (ret < 0)
407  return ret;
408  *got_frame = 1;
409  break;
410  case DIRECTBITSRECT:
411  case DIRECTBITSRGN:
412  av_log(avctx, AV_LOG_DEBUG, "Parsing Directbit opcode\n");
413 
414  bytestream2_skip(&gbc, 4);
415  rowbytes = bytestream2_get_be16(&gbc) & 0x3FFF;
416  if (rowbytes <= 250) {
417  avpriv_report_missing_feature(avctx, "Short rowbytes");
418  return AVERROR_PATCHWELCOME;
419  }
420 
421  bytestream2_skip(&gbc, 4);
422  h = bytestream2_get_be16(&gbc);
423  w = bytestream2_get_be16(&gbc);
424  bytestream2_skip(&gbc, 2);
425 
426  ret = ff_set_dimensions(avctx, w, h);
427  if (ret < 0)
428  return ret;
429 
430  pack_type = bytestream2_get_be16(&gbc);
431 
432  bytestream2_skip(&gbc, 16);
433  bppcnt = bytestream2_get_be16(&gbc); /* cmpCount */
434  bpp = bytestream2_get_be16(&gbc); /* cmpSize */
435 
436  av_log(avctx, AV_LOG_DEBUG, "bppcount %d bpp %d\n", bppcnt, bpp);
437  if (bppcnt == 3 && bpp == 8) {
438  avctx->pix_fmt = AV_PIX_FMT_RGB24;
439  } else if (bppcnt == 3 && bpp == 5 || bppcnt == 2 && bpp == 8) {
440  avctx->pix_fmt = AV_PIX_FMT_RGB555;
441  } else if (bppcnt == 4 && bpp == 8) {
442  avctx->pix_fmt = AV_PIX_FMT_ARGB;
443  } else {
444  av_log(avctx, AV_LOG_ERROR,
445  "Invalid pixel format (bppcnt %d bpp %d) in Directbit\n",
446  bppcnt, bpp);
447  return AVERROR_INVALIDDATA;
448  }
449 
450  /* set packing when default is selected */
451  if (pack_type == 0)
452  pack_type = bppcnt;
453 
454  if (pack_type != 3 && pack_type != 4) {
455  avpriv_request_sample(avctx, "Pack type %d", pack_type);
456  return AVERROR_PATCHWELCOME;
457  }
458  if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
459  return ret;
460 
461  /* jump to data */
462  bytestream2_skip(&gbc, 30);
463 
464  if (opcode == DIRECTBITSRGN) {
465  bytestream2_skip(&gbc, 2 + 8); /* size + rect */
466  avpriv_report_missing_feature(avctx, "DirectBit mask region");
467  }
468 
469  if (avctx->pix_fmt == AV_PIX_FMT_RGB555)
470  ret = decode_rle16(avctx, p, &gbc);
471  else
472  ret = decode_rle(avctx, p, &gbc, bppcnt);
473  if (ret < 0)
474  return ret;
475  *got_frame = 1;
476  break;
477  case LONGCOMMENT:
478  bytestream2_get_be16(&gbc);
479  bytestream2_skip(&gbc, bytestream2_get_be16(&gbc));
480  break;
481  default:
482  av_log(avctx, AV_LOG_TRACE, "Unknown 0x%04X opcode\n", opcode);
483  break;
484  }
485  /* exit the loop when a known pixel block has been found */
486  if (*got_frame) {
487  int eop, trail;
488 
489  /* re-align to a word */
491 
492  eop = bytestream2_get_be16(&gbc);
493  trail = bytestream2_get_bytes_left(&gbc);
494  if (eop != EOP)
495  av_log(avctx, AV_LOG_WARNING,
496  "Missing end of picture opcode (found 0x%04X)\n", eop);
497  if (trail)
498  av_log(avctx, AV_LOG_WARNING, "Got %d trailing bytes\n", trail);
499  break;
500  }
501  }
502 
503  if (*got_frame) {
505  p->key_frame = 1;
506 
507  return avpkt->size;
508  } else {
509  av_log(avctx, AV_LOG_ERROR, "Frame contained no usable data\n");
510 
511  return AVERROR_INVALIDDATA;
512  }
513 }
514 
516  .name = "qdraw",
517  .long_name = NULL_IF_CONFIG_SMALL("Apple QuickDraw"),
518  .type = AVMEDIA_TYPE_VIDEO,
519  .id = AV_CODEC_ID_QDRAW,
520  .decode = decode_frame,
521  .capabilities = AV_CODEC_CAP_DR1,
522 };
#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:226
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:68
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:104
const char * g
Definition: vf_curves.c:115
int size
Definition: avcodec.h:1446
const char * b
Definition: vf_curves.c:116
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:1743
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:3424
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.
uint8_t
8 bits with AV_PIX_FMT_RGB32 palette
Definition: pixfmt.h:77
AVCodec ff_qdraw_decoder
Definition: qdrw.c:515
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition: log.h:202
uint8_t * data
Definition: avcodec.h:1445
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:129
#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:186
const char * r
Definition: vf_curves.c:114
#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:216
const char * name
Name of the codec implementation.
Definition: avcodec.h:3431
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: qdrw.c:290
static const uint8_t offset[127][2]
Definition: vf_spp.c:92
packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
Definition: pixfmt.h:92
static int decode_rle16(AVCodecContext *avctx, AVFrame *p, GetByteContext *gbc)
Definition: qdrw.c:173
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:309
int width
picture width / height.
Definition: avcodec.h:1706
uint8_t w
Definition: llviddspenc.c:38
static int parse_palette(AVCodecContext *avctx, GetByteContext *gbc, uint32_t *pal, int colors, int pixmap)
Definition: qdrw.c:47
#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:257
main external API structure.
Definition: avcodec.h:1533
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1918
void * buf
Definition: avisynth_c.h:690
int palette_has_changed
Tell user application that palette has changed from previous frame.
Definition: frame.h:383
void avpriv_report_missing_feature(void *avc, const char *msg,...) av_printf_format(2
Log a generic warning message about a missing feature.
#define flags(name, subs,...)
Definition: cbs_av1.c:596
QuickdrawOpcodes
Definition: qdrw.c:35
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:240
common internal api header.
common internal and external API header
static int decode_rle_bpp2(AVCodecContext *avctx, AVFrame *p, GetByteContext *gbc)
Definition: qdrw.c:74
#define AV_PIX_FMT_RGB555
Definition: pixfmt.h:367
int key_frame
1 -> keyframe, 0-> not
Definition: frame.h:304
static int check_header(const char *buf, int buf_size)
Definition: qdrw.c:267
FILE * out
Definition: movenc.c:54
This structure stores compressed data.
Definition: avcodec.h:1422
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
Definition: avcodec.h:968