yading@10: /* yading@10: * QuickDraw (qdrw) codec yading@10: * Copyright (c) 2004 Konstantin Shishkov yading@10: * yading@10: * This file is part of FFmpeg. yading@10: * yading@10: * FFmpeg is free software; you can redistribute it and/or yading@10: * modify it under the terms of the GNU Lesser General Public yading@10: * License as published by the Free Software Foundation; either yading@10: * version 2.1 of the License, or (at your option) any later version. yading@10: * yading@10: * FFmpeg is distributed in the hope that it will be useful, yading@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@10: * Lesser General Public License for more details. yading@10: * yading@10: * You should have received a copy of the GNU Lesser General Public yading@10: * License along with FFmpeg; if not, write to the Free Software yading@10: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@10: */ yading@10: yading@10: /** yading@10: * @file yading@10: * Apple QuickDraw codec. yading@10: */ yading@10: yading@10: #include "libavutil/common.h" yading@10: #include "libavutil/intreadwrite.h" yading@10: #include "avcodec.h" yading@10: #include "internal.h" yading@10: yading@10: static int decode_frame(AVCodecContext *avctx, yading@10: void *data, int *got_frame, yading@10: AVPacket *avpkt) yading@10: { yading@10: const uint8_t *buf = avpkt->data; yading@10: const uint8_t *buf_end = avpkt->data + avpkt->size; yading@10: int buf_size = avpkt->size; yading@10: AVFrame * const p = data; yading@10: uint8_t* outdata; yading@10: int colors; yading@10: int i, ret; yading@10: uint32_t *pal; yading@10: int r, g, b; yading@10: yading@10: if ((ret = ff_get_buffer(avctx, p, 0)) < 0) yading@10: return ret; yading@10: p->pict_type = AV_PICTURE_TYPE_I; yading@10: p->key_frame = 1; yading@10: yading@10: outdata = p->data[0]; yading@10: yading@10: if (buf_end - buf < 0x68 + 4) yading@10: return AVERROR_INVALIDDATA; yading@10: buf += 0x68; /* jump to palette */ yading@10: colors = AV_RB32(buf); yading@10: buf += 4; yading@10: yading@10: if (colors < 0 || colors > 256) { yading@10: av_log(avctx, AV_LOG_ERROR, "Error color count - %i(0x%X)\n", colors, colors); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: if (buf_end - buf < (colors + 1) * 8) yading@10: return AVERROR_INVALIDDATA; yading@10: yading@10: pal = (uint32_t*)p->data[1]; yading@10: for (i = 0; i <= colors; i++) { yading@10: unsigned int idx; yading@10: idx = AV_RB16(buf); /* color index */ yading@10: buf += 2; yading@10: yading@10: if (idx > 255) { yading@10: av_log(avctx, AV_LOG_ERROR, "Palette index out of range: %u\n", idx); yading@10: buf += 6; yading@10: continue; yading@10: } yading@10: r = *buf++; yading@10: buf++; yading@10: g = *buf++; yading@10: buf++; yading@10: b = *buf++; yading@10: buf++; yading@10: pal[idx] = 0xFFU << 24 | r << 16 | g << 8 | b; yading@10: } yading@10: p->palette_has_changed = 1; yading@10: yading@10: if (buf_end - buf < 18) yading@10: return AVERROR_INVALIDDATA; yading@10: buf += 18; /* skip unneeded data */ yading@10: for (i = 0; i < avctx->height; i++) { yading@10: int size, left, code, pix; yading@10: const uint8_t *next; yading@10: uint8_t *out; yading@10: int tsize = 0; yading@10: yading@10: /* decode line */ yading@10: out = outdata; yading@10: size = AV_RB16(buf); /* size of packed line */ yading@10: buf += 2; yading@10: if (buf_end - buf < size) yading@10: return AVERROR_INVALIDDATA; yading@10: yading@10: left = size; yading@10: next = buf + size; yading@10: while (left > 0) { yading@10: code = *buf++; yading@10: if (code & 0x80 ) { /* run */ yading@10: pix = *buf++; yading@10: if ((out + (257 - code)) > (outdata + p->linesize[0])) yading@10: break; yading@10: memset(out, pix, 257 - code); yading@10: out += 257 - code; yading@10: tsize += 257 - code; yading@10: left -= 2; yading@10: } else { /* copy */ yading@10: if ((out + code) > (outdata + p->linesize[0])) yading@10: break; yading@10: if (buf_end - buf < code + 1) yading@10: return AVERROR_INVALIDDATA; yading@10: memcpy(out, buf, code + 1); yading@10: out += code + 1; yading@10: buf += code + 1; yading@10: left -= 2 + code; yading@10: tsize += code + 1; yading@10: } yading@10: } yading@10: buf = next; yading@10: outdata += p->linesize[0]; yading@10: } yading@10: yading@10: *got_frame = 1; yading@10: yading@10: return buf_size; yading@10: } yading@10: yading@10: static av_cold int decode_init(AVCodecContext *avctx) yading@10: { yading@10: avctx->pix_fmt= AV_PIX_FMT_PAL8; yading@10: yading@10: return 0; yading@10: } yading@10: yading@10: AVCodec ff_qdraw_decoder = { yading@10: .name = "qdraw", yading@10: .type = AVMEDIA_TYPE_VIDEO, yading@10: .id = AV_CODEC_ID_QDRAW, yading@10: .init = decode_init, yading@10: .decode = decode_frame, yading@10: .capabilities = CODEC_CAP_DR1, yading@10: .long_name = NULL_IF_CONFIG_SMALL("Apple QuickDraw"), yading@10: };