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