GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavcodec/dsicinvideo.c Lines: 88 185 47.6 %
Date: 2019-11-18 18:00:01 Branches: 37 90 41.1 %

Line Branch Exec Source
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
31
typedef enum CinVideoBitmapIndex {
32
    CIN_CUR_BMP = 0, /* current */
33
    CIN_PRE_BMP = 1, /* previous */
34
    CIN_INT_BMP = 2  /* intermediate */
35
} CinVideoBitmapIndex;
36
37
typedef 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
45
3
static av_cold void destroy_buffers(CinVideoContext *cin)
46
{
47
    int i;
48
49
12
    for (i = 0; i < 3; ++i)
50
9
        av_freep(&cin->bitmap_table[i]);
51
3
}
52
53
3
static av_cold int allocate_buffers(CinVideoContext *cin)
54
{
55
    int i;
56
57
12
    for (i = 0; i < 3; ++i) {
58
9
        cin->bitmap_table[i] = av_mallocz(cin->bitmap_size);
59
9
        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
3
    return 0;
67
}
68
69
3
static av_cold int cinvideo_decode_init(AVCodecContext *avctx)
70
{
71
3
    CinVideoContext *cin = avctx->priv_data;
72
73
3
    cin->avctx = avctx;
74
3
    avctx->pix_fmt = AV_PIX_FMT_PAL8;
75
76
3
    cin->frame = av_frame_alloc();
77
3
    if (!cin->frame)
78
        return AVERROR(ENOMEM);
79
80
3
    cin->bitmap_size = avctx->width * avctx->height;
81
3
    if (allocate_buffers(cin))
82
        return AVERROR(ENOMEM);
83
84
3
    return 0;
85
}
86
87
8
static void cin_apply_delta_data(const unsigned char *src, unsigned char *dst,
88
                                 int size)
89
{
90
409608
    while (size--)
91
409600
        *dst++ += *src++;
92
8
}
93
94
static 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
129
92
static 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
92
    unsigned char *dst_end       = dst + dst_size, *dst_start = dst;
135
92
    const unsigned char *src_end = src + src_size;
136
137

49910
    while (src < src_end && dst < dst_end) {
138
49818
        code = *src++;
139

448086
        for (i = 0; i < 8 && src < src_end && dst < dst_end; ++i) {
140
398268
            if (code & (1 << i)) {
141
86707
                *dst++ = *src++;
142
            } else {
143
311561
                cmd    = AV_RL16(src);
144
311561
                src   += 2;
145
311561
                offset = cmd >> 4;
146
311561
                if ((int)(dst - dst_start) < offset + 1)
147
                    return AVERROR_INVALIDDATA;
148
311561
                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
311561
                sz = FFMIN(sz, dst_end - dst);
153
4890008
                while (sz--) {
154
4578447
                    *dst = *(dst - offset - 1);
155
4578447
                    ++dst;
156
                }
157
            }
158
        }
159
    }
160
161
92
    if (dst_end - dst > dst_size - dst_size/10)
162
        return AVERROR_INVALIDDATA;
163
164
92
    return 0;
165
}
166
167
static 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
197
92
static int cinvideo_decode_frame(AVCodecContext *avctx,
198
                                 void *data, int *got_frame,
199
                                 AVPacket *avpkt)
200
{
201
92
    const uint8_t *buf   = avpkt->data;
202
92
    int buf_size         = avpkt->size;
203
92
    CinVideoContext *cin = avctx->priv_data;
204
    int i, y, palette_type, palette_colors_count,
205
92
        bitmap_frame_type, bitmap_frame_size, res = 0;
206
207
92
    palette_type         = buf[0];
208
92
    palette_colors_count = AV_RL16(buf + 1);
209
92
    bitmap_frame_type    = buf[3];
210
92
    buf                 += 4;
211
212
92
    bitmap_frame_size = buf_size - 4;
213
214
    /* handle palette */
215

92
    if (bitmap_frame_size < palette_colors_count * (3 + (palette_type != 0)))
216
        return AVERROR_INVALIDDATA;
217
92
    if (palette_type == 0) {
218
92
        if (palette_colors_count > 256)
219
            return AVERROR_INVALIDDATA;
220
11356
        for (i = 0; i < palette_colors_count; ++i) {
221
11264
            cin->palette[i]    = 0xFFU << 24 | bytestream_get_le24(&buf);
222
11264
            bitmap_frame_size -= 3;
223
        }
224
    } else {
225
        for (i = 0; i < palette_colors_count; ++i) {
226
            cin->palette[buf[0]] = 0xFFU << 24 | AV_RL24(buf + 1);
227
            buf                 += 4;
228
            bitmap_frame_size   -= 4;
229
        }
230
    }
231
232
    /* note: the decoding routines below assumes that
233
     * surface.width = surface.pitch */
234


92
    switch (bitmap_frame_type) {
235
    case 9:
236
        res =  cin_decode_rle(buf, bitmap_frame_size,
237
                       cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size);
238
        if (res < 0)
239
            return res;
240
        break;
241
    case 34:
242
        res =  cin_decode_rle(buf, bitmap_frame_size,
243
                       cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size);
244
        if (res < 0)
245
            return res;
246
        cin_apply_delta_data(cin->bitmap_table[CIN_PRE_BMP],
247
                             cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size);
248
        break;
249
    case 35:
250
        bitmap_frame_size = cin_decode_huffman(buf, bitmap_frame_size,
251
                           cin->bitmap_table[CIN_INT_BMP], cin->bitmap_size);
252
        res =  cin_decode_rle(cin->bitmap_table[CIN_INT_BMP], bitmap_frame_size,
253
                       cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size);
254
        if (res < 0)
255
            return res;
256
        break;
257
    case 36:
258
        bitmap_frame_size = cin_decode_huffman(buf, bitmap_frame_size,
259
                                               cin->bitmap_table[CIN_INT_BMP],
260
                                               cin->bitmap_size);
261
        res = cin_decode_rle(cin->bitmap_table[CIN_INT_BMP], bitmap_frame_size,
262
                       cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size);
263
        if (res < 0)
264
            return res;
265
        cin_apply_delta_data(cin->bitmap_table[CIN_PRE_BMP],
266
                             cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size);
267
        break;
268
    case 37:
269
        res = cin_decode_huffman(buf, bitmap_frame_size,
270
                           cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size);
271
272
        if (cin->bitmap_size - avctx->discard_damaged_percentage*cin->bitmap_size/100 > res)
273
            return AVERROR_INVALIDDATA;
274
        break;
275
84
    case 38:
276
84
        res = cin_decode_lzss(buf, bitmap_frame_size,
277
84
                              cin->bitmap_table[CIN_CUR_BMP],
278
84
                              cin->bitmap_size);
279
84
        if (res < 0)
280
            return res;
281
84
        break;
282
8
    case 39:
283
8
        res = cin_decode_lzss(buf, bitmap_frame_size,
284
8
                              cin->bitmap_table[CIN_CUR_BMP],
285
8
                              cin->bitmap_size);
286
8
        if (res < 0)
287
            return res;
288
8
        cin_apply_delta_data(cin->bitmap_table[CIN_PRE_BMP],
289
8
                             cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size);
290
8
        break;
291
    }
292
293
92
    if ((res = ff_reget_buffer(avctx, cin->frame, 0)) < 0)
294
        return res;
295
296
92
    memcpy(cin->frame->data[1], cin->palette, sizeof(cin->palette));
297
92
    cin->frame->palette_has_changed = 1;
298
14812
    for (y = 0; y < cin->avctx->height; ++y)
299
14720
        memcpy(cin->frame->data[0] + (cin->avctx->height - 1 - y) * cin->frame->linesize[0],
300
14720
               cin->bitmap_table[CIN_CUR_BMP] + y * cin->avctx->width,
301
14720
               cin->avctx->width);
302
303
92
    FFSWAP(uint8_t *, cin->bitmap_table[CIN_CUR_BMP],
304
                      cin->bitmap_table[CIN_PRE_BMP]);
305
306
92
    if ((res = av_frame_ref(data, cin->frame)) < 0)
307
        return res;
308
309
92
    *got_frame = 1;
310
311
92
    return buf_size;
312
}
313
314
3
static av_cold int cinvideo_decode_end(AVCodecContext *avctx)
315
{
316
3
    CinVideoContext *cin = avctx->priv_data;
317
318
3
    av_frame_free(&cin->frame);
319
320
3
    destroy_buffers(cin);
321
322
3
    return 0;
323
}
324
325
AVCodec ff_dsicinvideo_decoder = {
326
    .name           = "dsicinvideo",
327
    .long_name      = NULL_IF_CONFIG_SMALL("Delphine Software International CIN video"),
328
    .type           = AVMEDIA_TYPE_VIDEO,
329
    .id             = AV_CODEC_ID_DSICINVIDEO,
330
    .priv_data_size = sizeof(CinVideoContext),
331
    .init           = cinvideo_decode_init,
332
    .close          = cinvideo_decode_end,
333
    .decode         = cinvideo_decode_frame,
334
    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
335
    .capabilities   = AV_CODEC_CAP_DR1,
336
};