1/* 2 * Delphine Software International CIN video decoder 3 * Copyright (c) 2006 Gregory Montoir (cyx@users.sourceforge.net) 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 * Delphine Software International CIN video decoder 25 */ 26 27#include "avcodec.h" 28#include "bytestream.h" 29#include "codec_internal.h" 30#include "internal.h" 31 32typedef enum CinVideoBitmapIndex { 33 CIN_CUR_BMP = 0, /* current */ 34 CIN_PRE_BMP = 1, /* previous */ 35 CIN_INT_BMP = 2 /* intermediate */ 36} CinVideoBitmapIndex; 37 38typedef struct CinVideoContext { 39 AVCodecContext *avctx; 40 AVFrame *frame; 41 unsigned int bitmap_size; 42 uint32_t palette[256]; 43 uint8_t *bitmap_table[3]; 44} CinVideoContext; 45 46static av_cold void destroy_buffers(CinVideoContext *cin) 47{ 48 int i; 49 50 for (i = 0; i < 3; ++i) 51 av_freep(&cin->bitmap_table[i]); 52} 53 54static av_cold int allocate_buffers(CinVideoContext *cin) 55{ 56 int i; 57 58 for (i = 0; i < 3; ++i) { 59 cin->bitmap_table[i] = av_mallocz(cin->bitmap_size); 60 if (!cin->bitmap_table[i]) { 61 av_log(cin->avctx, AV_LOG_ERROR, "Can't allocate bitmap buffers.\n"); 62 return AVERROR(ENOMEM); 63 } 64 } 65 66 return 0; 67} 68 69static av_cold int cinvideo_decode_init(AVCodecContext *avctx) 70{ 71 CinVideoContext *cin = avctx->priv_data; 72 73 cin->avctx = avctx; 74 avctx->pix_fmt = AV_PIX_FMT_PAL8; 75 76 cin->frame = av_frame_alloc(); 77 if (!cin->frame) 78 return AVERROR(ENOMEM); 79 80 cin->bitmap_size = avctx->width * avctx->height; 81 if (allocate_buffers(cin)) 82 return AVERROR(ENOMEM); 83 84 return 0; 85} 86 87static void cin_apply_delta_data(const unsigned char *src, unsigned char *dst, 88 int size) 89{ 90 while (size--) 91 *dst++ += *src++; 92} 93 94static int cin_decode_huffman(const unsigned char *src, int src_size, 95 unsigned char *dst, int dst_size) 96{ 97 int b, huff_code = 0; 98 unsigned char huff_code_table[15]; 99 unsigned char *dst_cur = dst; 100 unsigned char *dst_end = dst + dst_size; 101 const unsigned char *src_end = src + src_size; 102 103 memcpy(huff_code_table, src, 15); 104 src += 15; 105 106 while (src < src_end) { 107 huff_code = *src++; 108 if ((huff_code >> 4) == 15) { 109 b = huff_code << 4; 110 huff_code = *src++; 111 *dst_cur++ = b | (huff_code >> 4); 112 } else 113 *dst_cur++ = huff_code_table[huff_code >> 4]; 114 if (dst_cur >= dst_end) 115 break; 116 117 huff_code &= 15; 118 if (huff_code == 15) { 119 *dst_cur++ = *src++; 120 } else 121 *dst_cur++ = huff_code_table[huff_code]; 122 if (dst_cur >= dst_end) 123 break; 124 } 125 126 return dst_cur - dst; 127} 128 129static int cin_decode_lzss(const unsigned char *src, int src_size, 130 unsigned char *dst, int dst_size) 131{ 132 uint16_t cmd; 133 int i, sz, offset, code; 134 unsigned char *dst_end = dst + dst_size, *dst_start = dst; 135 const unsigned char *src_end = src + src_size; 136 137 while (src < src_end && dst < dst_end) { 138 code = *src++; 139 for (i = 0; i < 8 && src < src_end && dst < dst_end; ++i) { 140 if (code & (1 << i)) { 141 *dst++ = *src++; 142 } else { 143 cmd = AV_RL16(src); 144 src += 2; 145 offset = cmd >> 4; 146 if ((int)(dst - dst_start) < offset + 1) 147 return AVERROR_INVALIDDATA; 148 sz = (cmd & 0xF) + 2; 149 /* don't use memcpy/memmove here as the decoding routine 150 * (ab)uses buffer overlappings to repeat bytes in the 151 * destination */ 152 sz = FFMIN(sz, dst_end - dst); 153 while (sz--) { 154 *dst = *(dst - offset - 1); 155 ++dst; 156 } 157 } 158 } 159 } 160 161 if (dst_end - dst > dst_size - dst_size/10) 162 return AVERROR_INVALIDDATA; 163 164 return 0; 165} 166 167static int cin_decode_rle(const unsigned char *src, int src_size, 168 unsigned char *dst, int dst_size) 169{ 170 int len, code; 171 unsigned char *dst_end = dst + dst_size; 172 const unsigned char *src_end = src + src_size; 173 174 while (src + 1 < src_end && dst < dst_end) { 175 code = *src++; 176 if (code & 0x80) { 177 len = code - 0x7F; 178 memset(dst, *src++, FFMIN(len, dst_end - dst)); 179 } else { 180 len = code + 1; 181 if (len > src_end-src) { 182 av_log(NULL, AV_LOG_ERROR, "RLE overread\n"); 183 return AVERROR_INVALIDDATA; 184 } 185 memcpy(dst, src, FFMIN3(len, dst_end - dst, src_end - src)); 186 src += len; 187 } 188 dst += len; 189 } 190 191 if (dst_end - dst > dst_size - dst_size/10) 192 return AVERROR_INVALIDDATA; 193 194 return 0; 195} 196 197static int cinvideo_decode_frame(AVCodecContext *avctx, AVFrame *rframe, 198 int *got_frame, AVPacket *avpkt) 199{ 200 const uint8_t *buf = avpkt->data; 201 int buf_size = avpkt->size; 202 CinVideoContext *cin = avctx->priv_data; 203 int i, y, palette_type, palette_colors_count, 204 bitmap_frame_type, bitmap_frame_size, res = 0; 205 206 palette_type = buf[0]; 207 palette_colors_count = AV_RL16(buf + 1); 208 bitmap_frame_type = buf[3]; 209 buf += 4; 210 211 bitmap_frame_size = buf_size - 4; 212 213 /* handle palette */ 214 if (bitmap_frame_size < palette_colors_count * (3 + (palette_type != 0))) 215 return AVERROR_INVALIDDATA; 216 if (palette_type == 0) { 217 if (palette_colors_count > 256) 218 return AVERROR_INVALIDDATA; 219 for (i = 0; i < palette_colors_count; ++i) { 220 cin->palette[i] = 0xFFU << 24 | bytestream_get_le24(&buf); 221 bitmap_frame_size -= 3; 222 } 223 } else { 224 for (i = 0; i < palette_colors_count; ++i) { 225 cin->palette[buf[0]] = 0xFFU << 24 | AV_RL24(buf + 1); 226 buf += 4; 227 bitmap_frame_size -= 4; 228 } 229 } 230 231 /* note: the decoding routines below assumes that 232 * surface.width = surface.pitch */ 233 switch (bitmap_frame_type) { 234 case 9: 235 res = cin_decode_rle(buf, bitmap_frame_size, 236 cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); 237 if (res < 0) 238 return res; 239 break; 240 case 34: 241 res = cin_decode_rle(buf, bitmap_frame_size, 242 cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); 243 if (res < 0) 244 return res; 245 cin_apply_delta_data(cin->bitmap_table[CIN_PRE_BMP], 246 cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); 247 break; 248 case 35: 249 bitmap_frame_size = cin_decode_huffman(buf, bitmap_frame_size, 250 cin->bitmap_table[CIN_INT_BMP], cin->bitmap_size); 251 res = cin_decode_rle(cin->bitmap_table[CIN_INT_BMP], bitmap_frame_size, 252 cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); 253 if (res < 0) 254 return res; 255 break; 256 case 36: 257 bitmap_frame_size = cin_decode_huffman(buf, bitmap_frame_size, 258 cin->bitmap_table[CIN_INT_BMP], 259 cin->bitmap_size); 260 res = cin_decode_rle(cin->bitmap_table[CIN_INT_BMP], bitmap_frame_size, 261 cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); 262 if (res < 0) 263 return res; 264 cin_apply_delta_data(cin->bitmap_table[CIN_PRE_BMP], 265 cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); 266 break; 267 case 37: 268 res = cin_decode_huffman(buf, bitmap_frame_size, 269 cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); 270 271 if (cin->bitmap_size - avctx->discard_damaged_percentage*cin->bitmap_size/100 > res) 272 return AVERROR_INVALIDDATA; 273 break; 274 case 38: 275 res = cin_decode_lzss(buf, bitmap_frame_size, 276 cin->bitmap_table[CIN_CUR_BMP], 277 cin->bitmap_size); 278 if (res < 0) 279 return res; 280 break; 281 case 39: 282 res = cin_decode_lzss(buf, bitmap_frame_size, 283 cin->bitmap_table[CIN_CUR_BMP], 284 cin->bitmap_size); 285 if (res < 0) 286 return res; 287 cin_apply_delta_data(cin->bitmap_table[CIN_PRE_BMP], 288 cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); 289 break; 290 } 291 292 if ((res = ff_reget_buffer(avctx, cin->frame, 0)) < 0) 293 return res; 294 295 memcpy(cin->frame->data[1], cin->palette, sizeof(cin->palette)); 296 cin->frame->palette_has_changed = 1; 297 for (y = 0; y < cin->avctx->height; ++y) 298 memcpy(cin->frame->data[0] + (cin->avctx->height - 1 - y) * cin->frame->linesize[0], 299 cin->bitmap_table[CIN_CUR_BMP] + y * cin->avctx->width, 300 cin->avctx->width); 301 302 FFSWAP(uint8_t *, cin->bitmap_table[CIN_CUR_BMP], 303 cin->bitmap_table[CIN_PRE_BMP]); 304 305 if ((res = av_frame_ref(rframe, cin->frame)) < 0) 306 return res; 307 308 *got_frame = 1; 309 310 return buf_size; 311} 312 313static av_cold int cinvideo_decode_end(AVCodecContext *avctx) 314{ 315 CinVideoContext *cin = avctx->priv_data; 316 317 av_frame_free(&cin->frame); 318 319 destroy_buffers(cin); 320 321 return 0; 322} 323 324const FFCodec ff_dsicinvideo_decoder = { 325 .p.name = "dsicinvideo", 326 .p.long_name = NULL_IF_CONFIG_SMALL("Delphine Software International CIN video"), 327 .p.type = AVMEDIA_TYPE_VIDEO, 328 .p.id = AV_CODEC_ID_DSICINVIDEO, 329 .priv_data_size = sizeof(CinVideoContext), 330 .init = cinvideo_decode_init, 331 .close = cinvideo_decode_end, 332 FF_CODEC_DECODE_CB(cinvideo_decode_frame), 333 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, 334 .p.capabilities = AV_CODEC_CAP_DR1, 335}; 336