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  PACKBITSRECT = 0x0098,
40  SHORTCOMMENT = 0x00A0,
42 
43  EOP = 0x00FF,
44 };
45 
47  uint32_t *pal, int colors)
48 {
49  int i;
50 
51  for (i = 0; i <= colors; i++) {
52  uint8_t r, g, b;
53  unsigned int idx = bytestream2_get_be16(gbc); /* color index */
54  if (idx > 255) {
55  av_log(avctx, AV_LOG_WARNING,
56  "Palette index out of range: %u\n", idx);
57  bytestream2_skip(gbc, 6);
58  continue;
59  }
60  r = bytestream2_get_byte(gbc);
61  bytestream2_skip(gbc, 1);
62  g = bytestream2_get_byte(gbc);
63  bytestream2_skip(gbc, 1);
64  b = bytestream2_get_byte(gbc);
65  bytestream2_skip(gbc, 1);
66  pal[idx] = (0xFFU << 24) | (r << 16) | (g << 8) | b;
67  }
68  return 0;
69 }
70 
71 static int decode_rle(AVCodecContext *avctx, AVFrame *p, GetByteContext *gbc,
72  int step)
73 {
74  int i, j;
75  int offset = avctx->width * step;
76  uint8_t *outdata = p->data[0];
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;
95  pos += step;
96  if (pos >= offset) {
97  pos -= offset;
98  pos++;
99  }
100  if (pos >= offset)
101  return AVERROR_INVALIDDATA;
102  }
103  left -= 2;
104  } else { /* copy */
105  for (j = 0; j < code + 1; j++) {
106  out[pos] = bytestream2_get_byte(gbc);
107  pos += step;
108  if (pos >= offset) {
109  pos -= offset;
110  pos++;
111  }
112  if (pos >= offset)
113  return AVERROR_INVALIDDATA;
114  }
115  left -= 2 + code;
116  }
117  }
118  outdata += p->linesize[0];
119  }
120  return 0;
121 }
122 
123 static int check_header(const char *buf, int buf_size)
124 {
125  unsigned w, h, v0, v1;
126 
127  if (buf_size < 40)
128  return 0;
129 
130  w = AV_RB16(buf+6);
131  h = AV_RB16(buf+8);
132  v0 = AV_RB16(buf+10);
133  v1 = AV_RB16(buf+12);
134 
135  if (!w || !h)
136  return 0;
137 
138  if (v0 == 0x1101)
139  return 1;
140  if (v0 == 0x0011 && v1 == 0x02FF)
141  return 2;
142  return 0;
143 }
144 
145 
146 static int decode_frame(AVCodecContext *avctx,
147  void *data, int *got_frame,
148  AVPacket *avpkt)
149 {
150  AVFrame * const p = data;
151  GetByteContext gbc;
152  int colors;
153  int w, h, ret;
154  int ver;
155 
156  bytestream2_init(&gbc, avpkt->data, avpkt->size);
157  if ( bytestream2_get_bytes_left(&gbc) >= 552
158  && check_header(gbc.buffer + 512, bytestream2_get_bytes_left(&gbc) - 512)
159  )
160  bytestream2_skip(&gbc, 512);
161 
163 
164  /* smallest PICT header */
165  if (bytestream2_get_bytes_left(&gbc) < 40) {
166  av_log(avctx, AV_LOG_ERROR, "Frame is too small %d\n",
168  return AVERROR_INVALIDDATA;
169  }
170 
171  bytestream2_skip(&gbc, 6);
172  h = bytestream2_get_be16(&gbc);
173  w = bytestream2_get_be16(&gbc);
174 
175  ret = ff_set_dimensions(avctx, w, h);
176  if (ret < 0)
177  return ret;
178 
179  /* version 1 is identified by 0x1101
180  * it uses byte-aligned opcodes rather than word-aligned */
181  if (ver == 1) {
182  avpriv_request_sample(avctx, "QuickDraw version 1");
183  return AVERROR_PATCHWELCOME;
184  } else if (ver != 2) {
185  avpriv_request_sample(avctx, "QuickDraw version unknown (%X)", bytestream2_get_be32(&gbc));
186  return AVERROR_PATCHWELCOME;
187  }
188 
189  bytestream2_skip(&gbc, 4+26);
190 
191  while (bytestream2_get_bytes_left(&gbc) >= 4) {
192  int bppcnt, bpp;
193  int rowbytes, pack_type;
194  int opcode = bytestream2_get_be16(&gbc);
195 
196  switch(opcode) {
197  case PACKBITSRECT:
198  case PACKBITSRGN:
199  av_log(avctx, AV_LOG_DEBUG, "Parsing Packbit opcode\n");
200 
201  bytestream2_skip(&gbc, 30);
202  bppcnt = bytestream2_get_be16(&gbc); /* cmpCount */
203  bpp = bytestream2_get_be16(&gbc); /* cmpSize */
204 
205  av_log(avctx, AV_LOG_DEBUG, "bppcount %d bpp %d\n", bppcnt, bpp);
206  if (bppcnt == 1 && bpp == 8) {
207  avctx->pix_fmt = AV_PIX_FMT_PAL8;
208  } else {
209  av_log(avctx, AV_LOG_ERROR,
210  "Invalid pixel format (bppcnt %d bpp %d) in Packbit\n",
211  bppcnt, bpp);
212  return AVERROR_INVALIDDATA;
213  }
214 
215  /* jump to palette */
216  bytestream2_skip(&gbc, 18);
217  colors = bytestream2_get_be16(&gbc);
218 
219  if (colors < 0 || colors > 256) {
220  av_log(avctx, AV_LOG_ERROR,
221  "Error color count - %i(0x%X)\n", colors, colors);
222  return AVERROR_INVALIDDATA;
223  }
224  if (bytestream2_get_bytes_left(&gbc) < (colors + 1) * 8) {
225  av_log(avctx, AV_LOG_ERROR, "Palette is too small %d\n",
227  return AVERROR_INVALIDDATA;
228  }
229  if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
230  return ret;
231 
232  parse_palette(avctx, &gbc, (uint32_t *)p->data[1], colors);
233  p->palette_has_changed = 1;
234 
235  /* jump to image data */
236  bytestream2_skip(&gbc, 18);
237 
238  if (opcode == PACKBITSRGN) {
239  bytestream2_skip(&gbc, 2 + 8); /* size + rect */
240  avpriv_report_missing_feature(avctx, "Packbit mask region");
241  }
242 
243  ret = decode_rle(avctx, p, &gbc, bppcnt);
244  if (ret < 0)
245  return ret;
246  *got_frame = 1;
247  break;
248  case DIRECTBITSRECT:
249  case DIRECTBITSRGN:
250  av_log(avctx, AV_LOG_DEBUG, "Parsing Directbit opcode\n");
251 
252  bytestream2_skip(&gbc, 4);
253  rowbytes = bytestream2_get_be16(&gbc) & 0x3FFF;
254  if (rowbytes <= 250) {
255  avpriv_report_missing_feature(avctx, "Short rowbytes");
256  return AVERROR_PATCHWELCOME;
257  }
258 
259  bytestream2_skip(&gbc, 10);
260  pack_type = bytestream2_get_be16(&gbc);
261 
262  bytestream2_skip(&gbc, 16);
263  bppcnt = bytestream2_get_be16(&gbc); /* cmpCount */
264  bpp = bytestream2_get_be16(&gbc); /* cmpSize */
265 
266  av_log(avctx, AV_LOG_DEBUG, "bppcount %d bpp %d\n", bppcnt, bpp);
267  if (bppcnt == 3 && bpp == 8) {
268  avctx->pix_fmt = AV_PIX_FMT_RGB24;
269  } else if (bppcnt == 4 && bpp == 8) {
270  avctx->pix_fmt = AV_PIX_FMT_ARGB;
271  } else {
272  av_log(avctx, AV_LOG_ERROR,
273  "Invalid pixel format (bppcnt %d bpp %d) in Directbit\n",
274  bppcnt, bpp);
275  return AVERROR_INVALIDDATA;
276  }
277 
278  /* set packing when default is selected */
279  if (pack_type == 0)
280  pack_type = bppcnt;
281 
282  if (pack_type != 3 && pack_type != 4) {
283  avpriv_request_sample(avctx, "Pack type %d", pack_type);
284  return AVERROR_PATCHWELCOME;
285  }
286  if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
287  return ret;
288 
289  /* jump to data */
290  bytestream2_skip(&gbc, 30);
291 
292  if (opcode == DIRECTBITSRGN) {
293  bytestream2_skip(&gbc, 2 + 8); /* size + rect */
294  avpriv_report_missing_feature(avctx, "DirectBit mask region");
295  }
296 
297  ret = decode_rle(avctx, p, &gbc, bppcnt);
298  if (ret < 0)
299  return ret;
300  *got_frame = 1;
301  break;
302  case LONGCOMMENT:
303  bytestream2_get_be16(&gbc);
304  bytestream2_skip(&gbc, bytestream2_get_be16(&gbc));
305  break;
306  default:
307  av_log(avctx, AV_LOG_TRACE, "Unknown 0x%04X opcode\n", opcode);
308  break;
309  }
310  /* exit the loop when a known pixel block has been found */
311  if (*got_frame) {
312  int eop, trail;
313 
314  /* re-align to a word */
316 
317  eop = bytestream2_get_be16(&gbc);
318  trail = bytestream2_get_bytes_left(&gbc);
319  if (eop != EOP)
320  av_log(avctx, AV_LOG_WARNING,
321  "Missing end of picture opcode (found 0x%04X)\n", eop);
322  if (trail)
323  av_log(avctx, AV_LOG_WARNING, "Got %d trailing bytes\n", trail);
324  break;
325  }
326  }
327 
328  if (*got_frame) {
330  p->key_frame = 1;
331 
332  return avpkt->size;
333  } else {
334  av_log(avctx, AV_LOG_ERROR, "Frame contained no usable data\n");
335 
336  return AVERROR_INVALIDDATA;
337  }
338 }
339 
341  .name = "qdraw",
342  .long_name = NULL_IF_CONFIG_SMALL("Apple QuickDraw"),
343  .type = AVMEDIA_TYPE_VIDEO,
344  .id = AV_CODEC_ID_QDRAW,
345  .decode = decode_frame,
346  .capabilities = AV_CODEC_CAP_DR1,
347 };
#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:1613
const char * b
Definition: vf_curves.c:113
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:1915
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:133
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:3620
Definition: qdrw.c:43
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:46
uint8_t
8 bits with AV_PIX_FMT_RGB32 palette
Definition: pixfmt.h:73
AVCodec ff_qdraw_decoder
Definition: qdrw.c:340
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition: log.h:202
uint8_t * data
Definition: avcodec.h:1612
const uint8_t * buffer
Definition: bytestream.h:34
ptrdiff_t size
Definition: opengl_enc.c:101
#define av_log(a,...)
#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:176
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:71
const char * name
Name of the codec implementation.
Definition: avcodec.h:3627
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: qdrw.c:146
static const uint8_t offset[127][2]
Definition: vf_spp.c:92
packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
Definition: pixfmt.h:93
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:264
int width
picture width / height.
Definition: avcodec.h:1874
#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:1687
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: utils.c:948
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
int key_frame
1 -> keyframe, 0-> not
Definition: frame.h:259
static int check_header(const char *buf, int buf_size)
Definition: qdrw.c:123
FILE * out
Definition: movenc.c:54
This structure stores compressed data.
Definition: avcodec.h:1589
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
Definition: avcodec.h:964