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  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[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 opcode = bytestream2_get_be16(&gbc);
339 
340  switch(opcode) {
341  case CLIP:
342  bytestream2_skip(&gbc, 10);
343  break;
344  case PACKBITSRECT:
345  case PACKBITSRGN:
346  av_log(avctx, AV_LOG_DEBUG, "Parsing Packbit opcode\n");
347 
348  bytestream2_skip(&gbc, 30);
349  bppcnt = bytestream2_get_be16(&gbc); /* cmpCount */
350  bpp = bytestream2_get_be16(&gbc); /* cmpSize */
351 
352  av_log(avctx, AV_LOG_DEBUG, "bppcount %d bpp %d\n", bppcnt, bpp);
353  if (bppcnt == 1 && bpp == 8) {
354  avctx->pix_fmt = AV_PIX_FMT_PAL8;
355  } else if (bppcnt == 1 && (bpp == 4 || bpp == 2)) {
356  avctx->pix_fmt = AV_PIX_FMT_PAL8;
357  } else if (bppcnt == 3 && bpp == 5) {
358  avctx->pix_fmt = AV_PIX_FMT_RGB555;
359  } else {
360  av_log(avctx, AV_LOG_ERROR,
361  "Invalid pixel format (bppcnt %d bpp %d) in Packbit\n",
362  bppcnt, bpp);
363  return AVERROR_INVALIDDATA;
364  }
365 
366  /* jump to palette */
367  bytestream2_skip(&gbc, 18);
368  colors = bytestream2_get_be16(&gbc);
369 
370  if (colors < 0 || colors > 256) {
371  av_log(avctx, AV_LOG_ERROR,
372  "Error color count - %i(0x%X)\n", colors, colors);
373  return AVERROR_INVALIDDATA;
374  }
375  if (bytestream2_get_bytes_left(&gbc) < (colors + 1) * 8) {
376  av_log(avctx, AV_LOG_ERROR, "Palette is too small %d\n",
378  return AVERROR_INVALIDDATA;
379  }
380  if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
381  return ret;
382 
383  ret = parse_palette(avctx, &gbc, (uint32_t *)p->data[1], colors);
384  if (ret < 0)
385  return ret;
386  p->palette_has_changed = 1;
387 
388  /* jump to image data */
389  bytestream2_skip(&gbc, 18);
390 
391  if (opcode == PACKBITSRGN) {
392  bytestream2_skip(&gbc, 2 + 8); /* size + rect */
393  avpriv_report_missing_feature(avctx, "Packbit mask region");
394  }
395 
396  if (avctx->pix_fmt == AV_PIX_FMT_RGB555)
397  ret = decode_rle16(avctx, p, &gbc);
398  else if (bpp == 2)
399  ret = decode_rle_bpp2(avctx, p, &gbc);
400  else if (bpp == 4)
401  ret = decode_rle_bpp4(avctx, p, &gbc);
402  else
403  ret = decode_rle(avctx, p, &gbc, bppcnt);
404  if (ret < 0)
405  return ret;
406  *got_frame = 1;
407  break;
408  case DIRECTBITSRECT:
409  case DIRECTBITSRGN:
410  av_log(avctx, AV_LOG_DEBUG, "Parsing Directbit opcode\n");
411 
412  bytestream2_skip(&gbc, 4);
413  rowbytes = bytestream2_get_be16(&gbc) & 0x3FFF;
414  if (rowbytes <= 250) {
415  avpriv_report_missing_feature(avctx, "Short rowbytes");
416  return AVERROR_PATCHWELCOME;
417  }
418 
419  bytestream2_skip(&gbc, 4);
420  h = bytestream2_get_be16(&gbc);
421  w = bytestream2_get_be16(&gbc);
422  bytestream2_skip(&gbc, 2);
423 
424  ret = ff_set_dimensions(avctx, w, h);
425  if (ret < 0)
426  return ret;
427 
428  pack_type = bytestream2_get_be16(&gbc);
429 
430  bytestream2_skip(&gbc, 16);
431  bppcnt = bytestream2_get_be16(&gbc); /* cmpCount */
432  bpp = bytestream2_get_be16(&gbc); /* cmpSize */
433 
434  av_log(avctx, AV_LOG_DEBUG, "bppcount %d bpp %d\n", bppcnt, bpp);
435  if (bppcnt == 3 && bpp == 8) {
436  avctx->pix_fmt = AV_PIX_FMT_RGB24;
437  } else if (bppcnt == 3 && bpp == 5) {
438  avctx->pix_fmt = AV_PIX_FMT_RGB555;
439  } else if (bppcnt == 4 && bpp == 8) {
440  avctx->pix_fmt = AV_PIX_FMT_ARGB;
441  } else {
442  av_log(avctx, AV_LOG_ERROR,
443  "Invalid pixel format (bppcnt %d bpp %d) in Directbit\n",
444  bppcnt, bpp);
445  return AVERROR_INVALIDDATA;
446  }
447 
448  /* set packing when default is selected */
449  if (pack_type == 0)
450  pack_type = bppcnt;
451 
452  if (pack_type != 3 && pack_type != 4) {
453  avpriv_request_sample(avctx, "Pack type %d", pack_type);
454  return AVERROR_PATCHWELCOME;
455  }
456  if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
457  return ret;
458 
459  /* jump to data */
460  bytestream2_skip(&gbc, 30);
461 
462  if (opcode == DIRECTBITSRGN) {
463  bytestream2_skip(&gbc, 2 + 8); /* size + rect */
464  avpriv_report_missing_feature(avctx, "DirectBit mask region");
465  }
466 
467  if (avctx->pix_fmt == AV_PIX_FMT_RGB555)
468  ret = decode_rle16(avctx, p, &gbc);
469  else
470  ret = decode_rle(avctx, p, &gbc, bppcnt);
471  if (ret < 0)
472  return ret;
473  *got_frame = 1;
474  break;
475  case LONGCOMMENT:
476  bytestream2_get_be16(&gbc);
477  bytestream2_skip(&gbc, bytestream2_get_be16(&gbc));
478  break;
479  default:
480  av_log(avctx, AV_LOG_TRACE, "Unknown 0x%04X opcode\n", opcode);
481  break;
482  }
483  /* exit the loop when a known pixel block has been found */
484  if (*got_frame) {
485  int eop, trail;
486 
487  /* re-align to a word */
489 
490  eop = bytestream2_get_be16(&gbc);
491  trail = bytestream2_get_bytes_left(&gbc);
492  if (eop != EOP)
493  av_log(avctx, AV_LOG_WARNING,
494  "Missing end of picture opcode (found 0x%04X)\n", eop);
495  if (trail)
496  av_log(avctx, AV_LOG_WARNING, "Got %d trailing bytes\n", trail);
497  break;
498  }
499  }
500 
501  if (*got_frame) {
503  p->key_frame = 1;
504 
505  return avpkt->size;
506  } else {
507  av_log(avctx, AV_LOG_ERROR, "Frame contained no usable data\n");
508 
509  return AVERROR_INVALIDDATA;
510  }
511 }
512 
514  .name = "qdraw",
515  .long_name = NULL_IF_CONFIG_SMALL("Apple QuickDraw"),
516  .type = AVMEDIA_TYPE_VIDEO,
517  .id = AV_CODEC_ID_QDRAW,
518  .decode = decode_frame,
519  .capabilities = AV_CODEC_CAP_DR1,
520 };
#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:187
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:1658
const char * b
Definition: vf_curves.c:113
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:1960
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:3681
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:513
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition: log.h:202
uint8_t * data
Definition: avcodec.h:1657
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:179
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:216
const char * name
Name of the codec implementation.
Definition: avcodec.h:3688
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:93
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:261
int width
picture width / height.
Definition: avcodec.h:1919
#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:218
main external API structure.
Definition: avcodec.h:1732
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:335
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:201
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:339
int key_frame
1 -> keyframe, 0-> not
Definition: frame.h:256
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:1634
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
Definition: avcodec.h:994