Libav
|
00001 /* 00002 * Deluxe Paint Animation decoder 00003 * Copyright (c) 2009 Peter Ross 00004 * 00005 * This file is part of FFmpeg. 00006 * 00007 * FFmpeg is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * FFmpeg is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with FFmpeg; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00027 #include "avcodec.h" 00028 #include "bytestream.h" 00029 00030 typedef struct AnmContext { 00031 AVFrame frame; 00032 int x; 00033 } AnmContext; 00034 00035 static av_cold int decode_init(AVCodecContext *avctx) 00036 { 00037 AnmContext *s = avctx->priv_data; 00038 const uint8_t *buf; 00039 int i; 00040 00041 avctx->pix_fmt = PIX_FMT_PAL8; 00042 00043 if (avctx->extradata_size != 16*8 + 4*256) 00044 return -1; 00045 00046 s->frame.reference = 1; 00047 if (avctx->get_buffer(avctx, &s->frame) < 0) { 00048 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 00049 return -1; 00050 } 00051 00052 buf = avctx->extradata + 16*8; 00053 for (i = 0; i < 256; i++) 00054 ((uint32_t*)s->frame.data[1])[i] = bytestream_get_le32(&buf); 00055 00056 return 0; 00057 } 00058 00074 static inline int op(uint8_t **dst, const uint8_t *dst_end, 00075 const uint8_t **buf, const uint8_t *buf_end, 00076 int pixel, int count, 00077 int *x, int width, int linesize) 00078 { 00079 int remaining = width - *x; 00080 while(count > 0) { 00081 int striplen = FFMIN(count, remaining); 00082 if (buf) { 00083 striplen = FFMIN(striplen, buf_end - *buf); 00084 memcpy(*dst, *buf, striplen); 00085 *buf += striplen; 00086 } else if (pixel >= 0) 00087 memset(*dst, pixel, striplen); 00088 *dst += striplen; 00089 remaining -= striplen; 00090 count -= striplen; 00091 if (remaining <= 0) { 00092 *dst += linesize - width; 00093 remaining = width; 00094 } 00095 if (linesize > 0) { 00096 if (*dst >= dst_end) goto exhausted; 00097 } else { 00098 if (*dst <= dst_end) goto exhausted; 00099 } 00100 } 00101 *x = width - remaining; 00102 return 0; 00103 00104 exhausted: 00105 *x = width - remaining; 00106 return 1; 00107 } 00108 00109 static int decode_frame(AVCodecContext *avctx, 00110 void *data, int *data_size, 00111 AVPacket *avpkt) 00112 { 00113 AnmContext *s = avctx->priv_data; 00114 const uint8_t *buf = avpkt->data; 00115 const int buf_size = avpkt->size; 00116 const uint8_t *buf_end = buf + buf_size; 00117 uint8_t *dst, *dst_end; 00118 int count; 00119 00120 if(avctx->reget_buffer(avctx, &s->frame) < 0){ 00121 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 00122 return -1; 00123 } 00124 dst = s->frame.data[0]; 00125 dst_end = s->frame.data[0] + s->frame.linesize[0]*avctx->height; 00126 00127 if (buf[0] != 0x42) { 00128 av_log_ask_for_sample(avctx, "unknown record type\n"); 00129 return buf_size; 00130 } 00131 if (buf[1]) { 00132 av_log_ask_for_sample(avctx, "padding bytes not supported\n"); 00133 return buf_size; 00134 } 00135 buf += 4; 00136 00137 s->x = 0; 00138 do { 00139 /* if statements are ordered by probability */ 00140 #define OP(buf, pixel, count) \ 00141 op(&dst, dst_end, (buf), buf_end, (pixel), (count), &s->x, avctx->width, s->frame.linesize[0]) 00142 00143 int type = bytestream_get_byte(&buf); 00144 count = type & 0x7F; 00145 type >>= 7; 00146 if (count) { 00147 if (OP(type ? NULL : &buf, -1, count)) break; 00148 } else if (!type) { 00149 int pixel; 00150 count = bytestream_get_byte(&buf); /* count==0 gives nop */ 00151 pixel = bytestream_get_byte(&buf); 00152 if (OP(NULL, pixel, count)) break; 00153 } else { 00154 int pixel; 00155 type = bytestream_get_le16(&buf); 00156 count = type & 0x3FFF; 00157 type >>= 14; 00158 if (!count) { 00159 if (type == 0) 00160 break; // stop 00161 if (type == 2) { 00162 av_log_ask_for_sample(avctx, "unknown opcode"); 00163 return AVERROR_INVALIDDATA; 00164 } 00165 continue; 00166 } 00167 pixel = type == 3 ? bytestream_get_byte(&buf) : -1; 00168 if (type == 1) count += 0x4000; 00169 if (OP(type == 2 ? &buf : NULL, pixel, count)) break; 00170 } 00171 } while (buf + 1 < buf_end); 00172 00173 *data_size = sizeof(AVFrame); 00174 *(AVFrame*)data = s->frame; 00175 return buf_size; 00176 } 00177 00178 static av_cold int decode_end(AVCodecContext *avctx) 00179 { 00180 AnmContext *s = avctx->priv_data; 00181 if (s->frame.data[0]) 00182 avctx->release_buffer(avctx, &s->frame); 00183 return 0; 00184 } 00185 00186 AVCodec anm_decoder = { 00187 "anm", 00188 AVMEDIA_TYPE_VIDEO, 00189 CODEC_ID_ANM, 00190 sizeof(AnmContext), 00191 decode_init, 00192 NULL, 00193 decode_end, 00194 decode_frame, 00195 CODEC_CAP_DR1, 00196 .long_name = NULL_IF_CONFIG_SMALL("Deluxe Paint Animation"), 00197 };