Libav 0.7.1
|
00001 /* 00002 * Deluxe Paint Animation decoder 00003 * Copyright (c) 2009 Peter Ross 00004 * 00005 * This file is part of Libav. 00006 * 00007 * Libav 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 * Libav 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 Libav; 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 if (*buf >= buf_end) 00085 goto exhausted; 00086 memcpy(*dst, *buf, striplen); 00087 *buf += striplen; 00088 } else if (pixel >= 0) 00089 memset(*dst, pixel, striplen); 00090 *dst += striplen; 00091 remaining -= striplen; 00092 count -= striplen; 00093 if (remaining <= 0) { 00094 *dst += linesize - width; 00095 remaining = width; 00096 } 00097 if (linesize > 0) { 00098 if (*dst >= dst_end) goto exhausted; 00099 } else { 00100 if (*dst <= dst_end) goto exhausted; 00101 } 00102 } 00103 *x = width - remaining; 00104 return 0; 00105 00106 exhausted: 00107 *x = width - remaining; 00108 return 1; 00109 } 00110 00111 static int decode_frame(AVCodecContext *avctx, 00112 void *data, int *data_size, 00113 AVPacket *avpkt) 00114 { 00115 AnmContext *s = avctx->priv_data; 00116 const uint8_t *buf = avpkt->data; 00117 const int buf_size = avpkt->size; 00118 const uint8_t *buf_end = buf + buf_size; 00119 uint8_t *dst, *dst_end; 00120 int count; 00121 00122 if(avctx->reget_buffer(avctx, &s->frame) < 0){ 00123 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 00124 return -1; 00125 } 00126 dst = s->frame.data[0]; 00127 dst_end = s->frame.data[0] + s->frame.linesize[0]*avctx->height; 00128 00129 if (buf[0] != 0x42) { 00130 av_log_ask_for_sample(avctx, "unknown record type\n"); 00131 return buf_size; 00132 } 00133 if (buf[1]) { 00134 av_log_ask_for_sample(avctx, "padding bytes not supported\n"); 00135 return buf_size; 00136 } 00137 buf += 4; 00138 00139 s->x = 0; 00140 do { 00141 /* if statements are ordered by probability */ 00142 #define OP(buf, pixel, count) \ 00143 op(&dst, dst_end, (buf), buf_end, (pixel), (count), &s->x, avctx->width, s->frame.linesize[0]) 00144 00145 int type = bytestream_get_byte(&buf); 00146 count = type & 0x7F; 00147 type >>= 7; 00148 if (count) { 00149 if (OP(type ? NULL : &buf, -1, count)) break; 00150 } else if (!type) { 00151 int pixel; 00152 count = bytestream_get_byte(&buf); /* count==0 gives nop */ 00153 pixel = bytestream_get_byte(&buf); 00154 if (OP(NULL, pixel, count)) break; 00155 } else { 00156 int pixel; 00157 type = bytestream_get_le16(&buf); 00158 count = type & 0x3FFF; 00159 type >>= 14; 00160 if (!count) { 00161 if (type == 0) 00162 break; // stop 00163 if (type == 2) { 00164 av_log_ask_for_sample(avctx, "unknown opcode"); 00165 return AVERROR_INVALIDDATA; 00166 } 00167 continue; 00168 } 00169 pixel = type == 3 ? bytestream_get_byte(&buf) : -1; 00170 if (type == 1) count += 0x4000; 00171 if (OP(type == 2 ? &buf : NULL, pixel, count)) break; 00172 } 00173 } while (buf + 1 < buf_end); 00174 00175 *data_size = sizeof(AVFrame); 00176 *(AVFrame*)data = s->frame; 00177 return buf_size; 00178 } 00179 00180 static av_cold int decode_end(AVCodecContext *avctx) 00181 { 00182 AnmContext *s = avctx->priv_data; 00183 if (s->frame.data[0]) 00184 avctx->release_buffer(avctx, &s->frame); 00185 return 0; 00186 } 00187 00188 AVCodec ff_anm_decoder = { 00189 "anm", 00190 AVMEDIA_TYPE_VIDEO, 00191 CODEC_ID_ANM, 00192 sizeof(AnmContext), 00193 decode_init, 00194 NULL, 00195 decode_end, 00196 decode_frame, 00197 CODEC_CAP_DR1, 00198 .long_name = NULL_IF_CONFIG_SMALL("Deluxe Paint Animation"), 00199 };