1/* 2 * Deluxe Paint Animation decoder 3 * Copyright (c) 2009 Peter Ross 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * FFmpeg is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22/** 23 * @file 24 * Deluxe Paint Animation decoder 25 */ 26 27#include "avcodec.h" 28#include "bytestream.h" 29#include "codec_internal.h" 30#include "internal.h" 31 32typedef struct AnmContext { 33 AVFrame *frame; 34 int palette[AVPALETTE_COUNT]; 35} AnmContext; 36 37static av_cold int decode_init(AVCodecContext *avctx) 38{ 39 AnmContext *s = avctx->priv_data; 40 GetByteContext gb; 41 int i; 42 43 if (avctx->extradata_size < 16 * 8 + 4 * 256) 44 return AVERROR_INVALIDDATA; 45 46 avctx->pix_fmt = AV_PIX_FMT_PAL8; 47 48 s->frame = av_frame_alloc(); 49 if (!s->frame) 50 return AVERROR(ENOMEM); 51 52 bytestream2_init(&gb, avctx->extradata, avctx->extradata_size); 53 bytestream2_skipu(&gb, 16 * 8); 54 for (i = 0; i < 256; i++) 55 s->palette[i] = (0xFFU << 24) | bytestream2_get_le32u(&gb); 56 57 return 0; 58} 59 60/** 61 * Perform decode operation 62 * @param dst pointer to destination image buffer 63 * @param dst_end pointer to end of destination image buffer 64 * @param gb GetByteContext (optional, see below) 65 * @param pixel Fill color (optional, see below) 66 * @param count Pixel count 67 * @param x Pointer to x-axis counter 68 * @param width Image width 69 * @param linesize Destination image buffer linesize 70 * @return non-zero if destination buffer is exhausted 71 * 72 * a copy operation is achieved when 'gb' is set 73 * a fill operation is achieved when 'gb' is null and pixel is >= 0 74 * a skip operation is achieved when 'gb' is null and pixel is < 0 75 */ 76static inline int op(uint8_t **dst, const uint8_t *dst_end, 77 GetByteContext *gb, 78 int pixel, int count, 79 int *x, int width, int linesize) 80{ 81 int remaining = width - *x; 82 while(count > 0) { 83 int striplen = FFMIN(count, remaining); 84 if (gb) { 85 if (bytestream2_get_bytes_left(gb) < striplen) 86 goto exhausted; 87 bytestream2_get_bufferu(gb, *dst, striplen); 88 } else if (pixel >= 0) 89 memset(*dst, pixel, striplen); 90 *dst += striplen; 91 remaining -= striplen; 92 count -= striplen; 93 if (remaining <= 0) { 94 *dst += linesize - width; 95 remaining = width; 96 } 97 if (linesize > 0) { 98 if (*dst >= dst_end) goto exhausted; 99 } else { 100 if (*dst <= dst_end) goto exhausted; 101 } 102 } 103 *x = width - remaining; 104 return 0; 105 106exhausted: 107 *x = width - remaining; 108 return 1; 109} 110 111static int decode_frame(AVCodecContext *avctx, AVFrame *rframe, 112 int *got_frame, AVPacket *avpkt) 113{ 114 AnmContext *s = avctx->priv_data; 115 const int buf_size = avpkt->size; 116 uint8_t *dst, *dst_end; 117 GetByteContext gb; 118 int count, ret, x = 0; 119 120 if (buf_size < 7) 121 return AVERROR_INVALIDDATA; 122 123 if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0) 124 return ret; 125 dst = s->frame->data[0]; 126 dst_end = s->frame->data[0] + s->frame->linesize[0]*avctx->height; 127 128 bytestream2_init(&gb, avpkt->data, buf_size); 129 130 if (bytestream2_get_byte(&gb) != 0x42) { 131 avpriv_request_sample(avctx, "Unknown record type"); 132 return AVERROR_INVALIDDATA; 133 } 134 if (bytestream2_get_byte(&gb)) { 135 avpriv_request_sample(avctx, "Padding bytes"); 136 return AVERROR_PATCHWELCOME; 137 } 138 bytestream2_skip(&gb, 2); 139 140 do { 141 /* if statements are ordered by probability */ 142#define OP(gb, pixel, count) \ 143 op(&dst, dst_end, (gb), (pixel), (count), &x, avctx->width, s->frame->linesize[0]) 144 145 int type = bytestream2_get_byte(&gb); 146 count = type & 0x7F; 147 type >>= 7; 148 if (count) { 149 if (OP(type ? NULL : &gb, -1, count)) break; 150 } else if (!type) { 151 int pixel; 152 count = bytestream2_get_byte(&gb); /* count==0 gives nop */ 153 pixel = bytestream2_get_byte(&gb); 154 if (OP(NULL, pixel, count)) break; 155 } else { 156 int pixel; 157 type = bytestream2_get_le16(&gb); 158 count = type & 0x3FFF; 159 type >>= 14; 160 if (!count) { 161 if (type == 0) 162 break; // stop 163 if (type == 2) { 164 avpriv_request_sample(avctx, "Unknown opcode"); 165 return AVERROR_PATCHWELCOME; 166 } 167 continue; 168 } 169 pixel = type == 3 ? bytestream2_get_byte(&gb) : -1; 170 if (type == 1) count += 0x4000; 171 if (OP(type == 2 ? &gb : NULL, pixel, count)) break; 172 } 173 } while (bytestream2_get_bytes_left(&gb) > 0); 174 175 memcpy(s->frame->data[1], s->palette, AVPALETTE_SIZE); 176 177 *got_frame = 1; 178 if ((ret = av_frame_ref(rframe, s->frame)) < 0) 179 return ret; 180 181 return buf_size; 182} 183 184static av_cold int decode_end(AVCodecContext *avctx) 185{ 186 AnmContext *s = avctx->priv_data; 187 188 av_frame_free(&s->frame); 189 return 0; 190} 191 192const FFCodec ff_anm_decoder = { 193 .p.name = "anm", 194 .p.long_name = NULL_IF_CONFIG_SMALL("Deluxe Paint Animation"), 195 .p.type = AVMEDIA_TYPE_VIDEO, 196 .p.id = AV_CODEC_ID_ANM, 197 .priv_data_size = sizeof(AnmContext), 198 .init = decode_init, 199 .close = decode_end, 200 FF_CODEC_DECODE_CB(decode_frame), 201 .p.capabilities = AV_CODEC_CAP_DR1, 202 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 203}; 204