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 30typedef struct AnmContext { 31 AVFrame frame; 32 int x; ///< x coordinate position 33} AnmContext; 34 35static av_cold int decode_init(AVCodecContext *avctx) 36{ 37 AnmContext *s = avctx->priv_data; 38 const uint8_t *buf; 39 int i; 40 41 avctx->pix_fmt = PIX_FMT_PAL8; 42 43 if (avctx->extradata_size != 16*8 + 4*256) 44 return -1; 45 46 s->frame.reference = 1; 47 if (avctx->get_buffer(avctx, &s->frame) < 0) { 48 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 49 return -1; 50 } 51 52 buf = avctx->extradata + 16*8; 53 for (i = 0; i < 256; i++) 54 ((uint32_t*)s->frame.data[1])[i] = bytestream_get_le32(&buf); 55 56 return 0; 57} 58 59/** 60 * Perform decode operation 61 * @param dst, dst_end Destination image buffer 62 * @param buf, buf_end Source buffer (optional, see below) 63 * @param pixel Fill color (optional, see below) 64 * @param count Pixel count 65 * @param x Pointer to x-axis counter 66 * @param width Image width 67 * @param linesize Destination image buffer linesize 68 * @return non-zero if destination buffer is exhausted 69 * 70 * a copy operation is achieved when 'buf' is set 71 * a fill operation is acheived when 'buf' is null and pixel is >= 0 72 * a skip operation is acheived when 'buf' is null and pixel is < 0 73 */ 74static inline int op(uint8_t **dst, const uint8_t *dst_end, 75 const uint8_t **buf, const uint8_t *buf_end, 76 int pixel, int count, 77 int *x, int width, int linesize) 78{ 79 int remaining = width - *x; 80 while(count > 0) { 81 int striplen = FFMIN(count, remaining); 82 if (buf) { 83 striplen = FFMIN(striplen, buf_end - *buf); 84 memcpy(*dst, *buf, striplen); 85 *buf += striplen; 86 } else if (pixel >= 0) 87 memset(*dst, pixel, striplen); 88 *dst += striplen; 89 remaining -= striplen; 90 count -= striplen; 91 if (remaining <= 0) { 92 *dst += linesize - width; 93 remaining = width; 94 } 95 if (linesize > 0) { 96 if (*dst >= dst_end) goto exhausted; 97 } else { 98 if (*dst <= dst_end) goto exhausted; 99 } 100 } 101 *x = width - remaining; 102 return 0; 103 104exhausted: 105 *x = width - remaining; 106 return 1; 107} 108 109static int decode_frame(AVCodecContext *avctx, 110 void *data, int *data_size, 111 AVPacket *avpkt) 112{ 113 AnmContext *s = avctx->priv_data; 114 const uint8_t *buf = avpkt->data; 115 const int buf_size = avpkt->size; 116 const uint8_t *buf_end = buf + buf_size; 117 uint8_t *dst, *dst_end; 118 int count; 119 120 if(avctx->reget_buffer(avctx, &s->frame) < 0){ 121 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 122 return -1; 123 } 124 dst = s->frame.data[0]; 125 dst_end = s->frame.data[0] + s->frame.linesize[0]*avctx->height; 126 127 if (buf[0] != 0x42) { 128 av_log_ask_for_sample(avctx, "unknown record type\n"); 129 return buf_size; 130 } 131 if (buf[1]) { 132 av_log_ask_for_sample(avctx, "padding bytes not supported\n"); 133 return buf_size; 134 } 135 buf += 4; 136 137 s->x = 0; 138 do { 139 /* if statements are ordered by probability */ 140#define OP(buf, pixel, count) \ 141 op(&dst, dst_end, (buf), buf_end, (pixel), (count), &s->x, avctx->width, s->frame.linesize[0]) 142 143 int type = bytestream_get_byte(&buf); 144 count = type & 0x7F; 145 type >>= 7; 146 if (count) { 147 if (OP(type ? NULL : &buf, -1, count)) break; 148 } else if (!type) { 149 int pixel; 150 count = bytestream_get_byte(&buf); /* count==0 gives nop */ 151 pixel = bytestream_get_byte(&buf); 152 if (OP(NULL, pixel, count)) break; 153 } else { 154 int pixel; 155 type = bytestream_get_le16(&buf); 156 count = type & 0x3FFF; 157 type >>= 14; 158 if (!count) { 159 if (type == 0) 160 break; // stop 161 if (type == 2) { 162 av_log_ask_for_sample(avctx, "unknown opcode"); 163 return AVERROR_INVALIDDATA; 164 } 165 continue; 166 } 167 pixel = type == 3 ? bytestream_get_byte(&buf) : -1; 168 if (type == 1) count += 0x4000; 169 if (OP(type == 2 ? &buf : NULL, pixel, count)) break; 170 } 171 } while (buf + 1 < buf_end); 172 173 *data_size = sizeof(AVFrame); 174 *(AVFrame*)data = s->frame; 175 return buf_size; 176} 177 178static av_cold int decode_end(AVCodecContext *avctx) 179{ 180 AnmContext *s = avctx->priv_data; 181 if (s->frame.data[0]) 182 avctx->release_buffer(avctx, &s->frame); 183 return 0; 184} 185 186AVCodec anm_decoder = { 187 "anm", 188 AVMEDIA_TYPE_VIDEO, 189 CODEC_ID_ANM, 190 sizeof(AnmContext), 191 decode_init, 192 NULL, 193 decode_end, 194 decode_frame, 195 CODEC_CAP_DR1, 196 .long_name = NULL_IF_CONFIG_SMALL("Deluxe Paint Animation"), 197}; 198