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 "internal.h" 30 31typedef enum CinVideoBitmapIndex { 32 CIN_CUR_BMP = 0, /* current */ 33 CIN_PRE_BMP = 1, /* previous */ 34 CIN_INT_BMP = 2 /* intermediate */ 35} CinVideoBitmapIndex; 36 37typedef struct CinVideoContext { 38 AVCodecContext *avctx; 39 AVFrame *frame; 40 unsigned int bitmap_size; 41 uint32_t palette[256]; 42 uint8_t *bitmap_table[3]; 43} CinVideoContext; 44 45static av_cold void destroy_buffers(CinVideoContext *cin) 46{ 47 int i; 48 49 for (i = 0; i < 3; ++i) 50 av_freep(&cin->bitmap_table[i]); 51} 52 53static av_cold int allocate_buffers(CinVideoContext *cin) 54{ 55 int i; 56 57 for (i = 0; i < 3; ++i) { 58 cin->bitmap_table[i] = av_mallocz(cin->bitmap_size); 59 if (!cin->bitmap_table[i]) { 60 av_log(cin->avctx, AV_LOG_ERROR, "Can't allocate bitmap buffers.\n"); 61 destroy_buffers(cin); 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 return 0; 162} 163 164static int cin_decode_rle(const unsigned char *src, int src_size, 165 unsigned char *dst, int dst_size) 166{ 167 int len, code; 168 unsigned char *dst_end = dst + dst_size; 169 const unsigned char *src_end = src + src_size; 170 171 while (src + 1 < src_end && dst < dst_end) { 172 code = *src++; 173 if (code & 0x80) { 174 len = code - 0x7F; 175 memset(dst, *src++, FFMIN(len, dst_end - dst)); 176 } else { 177 len = code + 1; 178 if (len > src_end-src) { 179 av_log(NULL, AV_LOG_ERROR, "RLE overread\n"); 180 return AVERROR_INVALIDDATA; 181 } 182 memcpy(dst, src, FFMIN3(len, dst_end - dst, src_end - src)); 183 src += len; 184 } 185 dst += len; 186 } 187 return 0; 188} 189 190static int cinvideo_decode_frame(AVCodecContext *avctx, 191 void *data, int *got_frame, 192 AVPacket *avpkt) 193{ 194 const uint8_t *buf = avpkt->data; 195 int buf_size = avpkt->size; 196 CinVideoContext *cin = avctx->priv_data; 197 int i, y, palette_type, palette_colors_count, 198 bitmap_frame_type, bitmap_frame_size, res = 0; 199 200 palette_type = buf[0]; 201 palette_colors_count = AV_RL16(buf + 1); 202 bitmap_frame_type = buf[3]; 203 buf += 4; 204 205 bitmap_frame_size = buf_size - 4; 206 207 /* handle palette */ 208 if (bitmap_frame_size < palette_colors_count * (3 + (palette_type != 0))) 209 return AVERROR_INVALIDDATA; 210 if (palette_type == 0) { 211 if (palette_colors_count > 256) 212 return AVERROR_INVALIDDATA; 213 for (i = 0; i < palette_colors_count; ++i) { 214 cin->palette[i] = 0xFFU << 24 | bytestream_get_le24(&buf); 215 bitmap_frame_size -= 3; 216 } 217 } else { 218 for (i = 0; i < palette_colors_count; ++i) { 219 cin->palette[buf[0]] = 0xFFU << 24 | AV_RL24(buf + 1); 220 buf += 4; 221 bitmap_frame_size -= 4; 222 } 223 } 224 225 /* note: the decoding routines below assumes that 226 * surface.width = surface.pitch */ 227 switch (bitmap_frame_type) { 228 case 9: 229 cin_decode_rle(buf, bitmap_frame_size, 230 cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); 231 break; 232 case 34: 233 cin_decode_rle(buf, bitmap_frame_size, 234 cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); 235 cin_apply_delta_data(cin->bitmap_table[CIN_PRE_BMP], 236 cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); 237 break; 238 case 35: 239 bitmap_frame_size = cin_decode_huffman(buf, bitmap_frame_size, 240 cin->bitmap_table[CIN_INT_BMP], cin->bitmap_size); 241 cin_decode_rle(cin->bitmap_table[CIN_INT_BMP], bitmap_frame_size, 242 cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); 243 break; 244 case 36: 245 bitmap_frame_size = cin_decode_huffman(buf, bitmap_frame_size, 246 cin->bitmap_table[CIN_INT_BMP], 247 cin->bitmap_size); 248 cin_decode_rle(cin->bitmap_table[CIN_INT_BMP], bitmap_frame_size, 249 cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); 250 cin_apply_delta_data(cin->bitmap_table[CIN_PRE_BMP], 251 cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); 252 break; 253 case 37: 254 cin_decode_huffman(buf, bitmap_frame_size, 255 cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); 256 break; 257 case 38: 258 res = cin_decode_lzss(buf, bitmap_frame_size, 259 cin->bitmap_table[CIN_CUR_BMP], 260 cin->bitmap_size); 261 if (res < 0) 262 return res; 263 break; 264 case 39: 265 res = cin_decode_lzss(buf, bitmap_frame_size, 266 cin->bitmap_table[CIN_CUR_BMP], 267 cin->bitmap_size); 268 if (res < 0) 269 return res; 270 cin_apply_delta_data(cin->bitmap_table[CIN_PRE_BMP], 271 cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); 272 break; 273 } 274 275 if ((res = ff_reget_buffer(avctx, cin->frame)) < 0) 276 return res; 277 278 memcpy(cin->frame->data[1], cin->palette, sizeof(cin->palette)); 279 cin->frame->palette_has_changed = 1; 280 for (y = 0; y < cin->avctx->height; ++y) 281 memcpy(cin->frame->data[0] + (cin->avctx->height - 1 - y) * cin->frame->linesize[0], 282 cin->bitmap_table[CIN_CUR_BMP] + y * cin->avctx->width, 283 cin->avctx->width); 284 285 FFSWAP(uint8_t *, cin->bitmap_table[CIN_CUR_BMP], 286 cin->bitmap_table[CIN_PRE_BMP]); 287 288 if ((res = av_frame_ref(data, cin->frame)) < 0) 289 return res; 290 291 *got_frame = 1; 292 293 return buf_size; 294} 295 296static av_cold int cinvideo_decode_end(AVCodecContext *avctx) 297{ 298 CinVideoContext *cin = avctx->priv_data; 299 300 av_frame_free(&cin->frame); 301 302 destroy_buffers(cin); 303 304 return 0; 305} 306 307AVCodec ff_dsicinvideo_decoder = { 308 .name = "dsicinvideo", 309 .long_name = NULL_IF_CONFIG_SMALL("Delphine Software International CIN video"), 310 .type = AVMEDIA_TYPE_VIDEO, 311 .id = AV_CODEC_ID_DSICINVIDEO, 312 .priv_data_size = sizeof(CinVideoContext), 313 .init = cinvideo_decode_init, 314 .close = cinvideo_decode_end, 315 .decode = cinvideo_decode_frame, 316 .capabilities = CODEC_CAP_DR1, 317}; 318