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