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