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