2 * Delphine Software International CIN video decoder
3 * Copyright (c) 2006 Gregory Montoir (cyx@users.sourceforge.net)
5 * This file is part of Libav.
7 * Libav 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.
12 * Libav 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.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 * Delphine Software International CIN video decoder
28 #include "bytestream.h"
31 typedef enum CinVideoBitmapIndex
{
32 CIN_CUR_BMP
= 0, /* current */
33 CIN_PRE_BMP
= 1, /* previous */
34 CIN_INT_BMP
= 2 /* intermediate */
35 } CinVideoBitmapIndex
;
37 typedef struct CinVideoContext
{
38 AVCodecContext
*avctx
;
40 unsigned int bitmap_size
;
41 uint32_t palette
[256];
42 uint8_t *bitmap_table
[3];
45 static av_cold
int cinvideo_decode_init(AVCodecContext
*avctx
)
47 CinVideoContext
*cin
= avctx
->priv_data
;
51 avctx
->pix_fmt
= AV_PIX_FMT_PAL8
;
53 cin
->frame
= av_frame_alloc();
55 return AVERROR(ENOMEM
);
57 cin
->bitmap_size
= avctx
->width
* avctx
->height
;
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(avctx
, AV_LOG_ERROR
, "Can't allocate bitmap buffers.\n");
67 static void cin_apply_delta_data(const unsigned char *src
, unsigned char *dst
,
74 static int cin_decode_huffman(const unsigned char *src
, int src_size
,
75 unsigned char *dst
, int dst_size
)
78 unsigned char huff_code_table
[15];
79 unsigned char *dst_cur
= dst
;
80 unsigned char *dst_end
= dst
+ dst_size
;
81 const unsigned char *src_end
= src
+ src_size
;
83 memcpy(huff_code_table
, src
, 15);
86 while (src
< src_end
) {
88 if ((huff_code
>> 4) == 15) {
91 *dst_cur
++ = b
| (huff_code
>> 4);
93 *dst_cur
++ = huff_code_table
[huff_code
>> 4];
94 if (dst_cur
>= dst_end
)
98 if (huff_code
== 15) {
101 *dst_cur
++ = huff_code_table
[huff_code
];
102 if (dst_cur
>= dst_end
)
106 return dst_cur
- dst
;
109 static int cin_decode_lzss(const unsigned char *src
, int src_size
,
110 unsigned char *dst
, int dst_size
)
113 int i
, sz
, offset
, code
;
114 unsigned char *dst_end
= dst
+ dst_size
, *dst_start
= dst
;
115 const unsigned char *src_end
= src
+ src_size
;
117 while (src
< src_end
&& dst
< dst_end
) {
119 for (i
= 0; i
< 8 && src
< src_end
&& dst
< dst_end
; ++i
) {
120 if (code
& (1 << i
)) {
126 if ((int)(dst
- dst_start
) < offset
+ 1)
127 return AVERROR_INVALIDDATA
;
128 sz
= (cmd
& 0xF) + 2;
129 /* don't use memcpy/memmove here as the decoding routine
130 * (ab)uses buffer overlappings to repeat bytes in the
132 sz
= FFMIN(sz
, dst_end
- dst
);
134 *dst
= *(dst
- offset
- 1);
144 static void cin_decode_rle(const unsigned char *src
, int src_size
,
145 unsigned char *dst
, int dst_size
)
148 unsigned char *dst_end
= dst
+ dst_size
;
149 const unsigned char *src_end
= src
+ src_size
;
151 while (src
< src_end
&& dst
< dst_end
) {
157 memset(dst
, *src
++, FFMIN(len
, dst_end
- dst
));
160 memcpy(dst
, src
, FFMIN3(len
, dst_end
- dst
, src_end
- src
));
167 static int cinvideo_decode_frame(AVCodecContext
*avctx
,
168 void *data
, int *got_frame
,
171 const uint8_t *buf
= avpkt
->data
;
172 int buf_size
= avpkt
->size
;
173 CinVideoContext
*cin
= avctx
->priv_data
;
174 int i
, y
, palette_type
, palette_colors_count
,
175 bitmap_frame_type
, bitmap_frame_size
, res
= 0;
177 palette_type
= buf
[0];
178 palette_colors_count
= AV_RL16(buf
+ 1);
179 bitmap_frame_type
= buf
[3];
182 bitmap_frame_size
= buf_size
- 4;
185 if (bitmap_frame_size
< palette_colors_count
* (3 + (palette_type
!= 0)))
186 return AVERROR_INVALIDDATA
;
187 if (palette_type
== 0) {
188 if (palette_colors_count
> 256)
189 return AVERROR_INVALIDDATA
;
190 for (i
= 0; i
< palette_colors_count
; ++i
) {
191 cin
->palette
[i
] = bytestream_get_le24(&buf
);
192 bitmap_frame_size
-= 3;
195 for (i
= 0; i
< palette_colors_count
; ++i
) {
196 cin
->palette
[buf
[0]] = AV_RL24(buf
+ 1);
198 bitmap_frame_size
-= 4;
202 bitmap_frame_size
= FFMIN(cin
->bitmap_size
, bitmap_frame_size
);
204 /* note: the decoding routines below assumes that
205 * surface.width = surface.pitch */
206 switch (bitmap_frame_type
) {
208 cin_decode_rle(buf
, bitmap_frame_size
,
209 cin
->bitmap_table
[CIN_CUR_BMP
], cin
->bitmap_size
);
212 cin_decode_rle(buf
, bitmap_frame_size
,
213 cin
->bitmap_table
[CIN_CUR_BMP
], cin
->bitmap_size
);
214 cin_apply_delta_data(cin
->bitmap_table
[CIN_PRE_BMP
],
215 cin
->bitmap_table
[CIN_CUR_BMP
], cin
->bitmap_size
);
218 cin_decode_huffman(buf
, bitmap_frame_size
,
219 cin
->bitmap_table
[CIN_INT_BMP
], cin
->bitmap_size
);
220 cin_decode_rle(cin
->bitmap_table
[CIN_INT_BMP
], bitmap_frame_size
,
221 cin
->bitmap_table
[CIN_CUR_BMP
], cin
->bitmap_size
);
224 bitmap_frame_size
= cin_decode_huffman(buf
, bitmap_frame_size
,
225 cin
->bitmap_table
[CIN_INT_BMP
],
227 cin_decode_rle(cin
->bitmap_table
[CIN_INT_BMP
], bitmap_frame_size
,
228 cin
->bitmap_table
[CIN_CUR_BMP
], cin
->bitmap_size
);
229 cin_apply_delta_data(cin
->bitmap_table
[CIN_PRE_BMP
],
230 cin
->bitmap_table
[CIN_CUR_BMP
], cin
->bitmap_size
);
233 cin_decode_huffman(buf
, bitmap_frame_size
,
234 cin
->bitmap_table
[CIN_CUR_BMP
], cin
->bitmap_size
);
237 res
= cin_decode_lzss(buf
, bitmap_frame_size
,
238 cin
->bitmap_table
[CIN_CUR_BMP
],
244 res
= cin_decode_lzss(buf
, bitmap_frame_size
,
245 cin
->bitmap_table
[CIN_CUR_BMP
],
249 cin_apply_delta_data(cin
->bitmap_table
[CIN_PRE_BMP
],
250 cin
->bitmap_table
[CIN_CUR_BMP
], cin
->bitmap_size
);
254 if ((res
= ff_reget_buffer(avctx
, cin
->frame
)) < 0) {
255 av_log(cin
->avctx
, AV_LOG_ERROR
,
256 "delphinecinvideo: reget_buffer() failed to allocate a frame\n");
260 memcpy(cin
->frame
->data
[1], cin
->palette
, sizeof(cin
->palette
));
261 cin
->frame
->palette_has_changed
= 1;
262 for (y
= 0; y
< cin
->avctx
->height
; ++y
)
263 memcpy(cin
->frame
->data
[0] + (cin
->avctx
->height
- 1 - y
) * cin
->frame
->linesize
[0],
264 cin
->bitmap_table
[CIN_CUR_BMP
] + y
* cin
->avctx
->width
,
267 FFSWAP(uint8_t *, cin
->bitmap_table
[CIN_CUR_BMP
],
268 cin
->bitmap_table
[CIN_PRE_BMP
]);
270 if ((res
= av_frame_ref(data
, cin
->frame
)) < 0)
278 static av_cold
int cinvideo_decode_end(AVCodecContext
*avctx
)
280 CinVideoContext
*cin
= avctx
->priv_data
;
283 av_frame_free(&cin
->frame
);
285 for (i
= 0; i
< 3; ++i
)
286 av_free(cin
->bitmap_table
[i
]);
291 AVCodec ff_dsicinvideo_decoder
= {
292 .name
= "dsicinvideo",
293 .long_name
= NULL_IF_CONFIG_SMALL("Delphine Software International CIN video"),
294 .type
= AVMEDIA_TYPE_VIDEO
,
295 .id
= AV_CODEC_ID_DSICINVIDEO
,
296 .priv_data_size
= sizeof(CinVideoContext
),
297 .init
= cinvideo_decode_init
,
298 .close
= cinvideo_decode_end
,
299 .decode
= cinvideo_decode_frame
,
300 .capabilities
= AV_CODEC_CAP_DR1
,