GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavcodec/dsicinvideo.c Lines: 88 184 47.8 %
Date: 2020-09-28 00:47:38 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
            return AVERROR(ENOMEM);
62
        }
63
    }
64
65
3
    return 0;
66
}
67
68
3
static av_cold int cinvideo_decode_init(AVCodecContext *avctx)
69
{
70
3
    CinVideoContext *cin = avctx->priv_data;
71
72
3
    cin->avctx = avctx;
73
3
    avctx->pix_fmt = AV_PIX_FMT_PAL8;
74
75
3
    cin->frame = av_frame_alloc();
76
3
    if (!cin->frame)
77
        return AVERROR(ENOMEM);
78
79
3
    cin->bitmap_size = avctx->width * avctx->height;
80
3
    if (allocate_buffers(cin))
81
        return AVERROR(ENOMEM);
82
83
3
    return 0;
84
}
85
86
8
static void cin_apply_delta_data(const unsigned char *src, unsigned char *dst,
87
                                 int size)
88
{
89
409608
    while (size--)
90
409600
        *dst++ += *src++;
91
8
}
92
93
static int cin_decode_huffman(const unsigned char *src, int src_size,
94
                              unsigned char *dst, int dst_size)
95
{
96
    int b, huff_code = 0;
97
    unsigned char huff_code_table[15];
98
    unsigned char *dst_cur       = dst;
99
    unsigned char *dst_end       = dst + dst_size;
100
    const unsigned char *src_end = src + src_size;
101
102
    memcpy(huff_code_table, src, 15);
103
    src += 15;
104
105
    while (src < src_end) {
106
        huff_code = *src++;
107
        if ((huff_code >> 4) == 15) {
108
            b          = huff_code << 4;
109
            huff_code  = *src++;
110
            *dst_cur++ = b | (huff_code >> 4);
111
        } else
112
            *dst_cur++ = huff_code_table[huff_code >> 4];
113
        if (dst_cur >= dst_end)
114
            break;
115
116
        huff_code &= 15;
117
        if (huff_code == 15) {
118
            *dst_cur++ = *src++;
119
        } else
120
            *dst_cur++ = huff_code_table[huff_code];
121
        if (dst_cur >= dst_end)
122
            break;
123
    }
124
125
    return dst_cur - dst;
126
}
127
128
92
static int cin_decode_lzss(const unsigned char *src, int src_size,
129
                           unsigned char *dst, int dst_size)
130
{
131
    uint16_t cmd;
132
    int i, sz, offset, code;
133
92
    unsigned char *dst_end       = dst + dst_size, *dst_start = dst;
134
92
    const unsigned char *src_end = src + src_size;
135
136

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

448086
        for (i = 0; i < 8 && src < src_end && dst < dst_end; ++i) {
139
398268
            if (code & (1 << i)) {
140
86707
                *dst++ = *src++;
141
            } else {
142
311561
                cmd    = AV_RL16(src);
143
311561
                src   += 2;
144
311561
                offset = cmd >> 4;
145
311561
                if ((int)(dst - dst_start) < offset + 1)
146
                    return AVERROR_INVALIDDATA;
147
311561
                sz = (cmd & 0xF) + 2;
148
                /* don't use memcpy/memmove here as the decoding routine
149
                 * (ab)uses buffer overlappings to repeat bytes in the
150
                 * destination */
151
311561
                sz = FFMIN(sz, dst_end - dst);
152
4890008
                while (sz--) {
153
4578447
                    *dst = *(dst - offset - 1);
154
4578447
                    ++dst;
155
                }
156
            }
157
        }
158
    }
159
160
92
    if (dst_end - dst > dst_size - dst_size/10)
161
        return AVERROR_INVALIDDATA;
162
163
92
    return 0;
164
}
165
166
static int cin_decode_rle(const unsigned char *src, int src_size,
167
                           unsigned char *dst, int dst_size)
168
{
169
    int len, code;
170
    unsigned char *dst_end       = dst + dst_size;
171
    const unsigned char *src_end = src + src_size;
172
173
    while (src + 1 < src_end && dst < dst_end) {
174
        code = *src++;
175
        if (code & 0x80) {
176
            len = code - 0x7F;
177
            memset(dst, *src++, FFMIN(len, dst_end - dst));
178
        } else {
179
            len = code + 1;
180
            if (len > src_end-src) {
181
                av_log(NULL, AV_LOG_ERROR, "RLE overread\n");
182
                return AVERROR_INVALIDDATA;
183
            }
184
            memcpy(dst, src, FFMIN3(len, dst_end - dst, src_end - src));
185
            src += len;
186
        }
187
        dst += len;
188
    }
189
190
    if (dst_end - dst > dst_size - dst_size/10)
191
        return AVERROR_INVALIDDATA;
192
193
    return 0;
194
}
195
196
92
static int cinvideo_decode_frame(AVCodecContext *avctx,
197
                                 void *data, int *got_frame,
198
                                 AVPacket *avpkt)
199
{
200
92
    const uint8_t *buf   = avpkt->data;
201
92
    int buf_size         = avpkt->size;
202
92
    CinVideoContext *cin = avctx->priv_data;
203
    int i, y, palette_type, palette_colors_count,
204
92
        bitmap_frame_type, bitmap_frame_size, res = 0;
205
206
92
    palette_type         = buf[0];
207
92
    palette_colors_count = AV_RL16(buf + 1);
208
92
    bitmap_frame_type    = buf[3];
209
92
    buf                 += 4;
210
211
92
    bitmap_frame_size = buf_size - 4;
212
213
    /* handle palette */
214

92
    if (bitmap_frame_size < palette_colors_count * (3 + (palette_type != 0)))
215
        return AVERROR_INVALIDDATA;
216
92
    if (palette_type == 0) {
217
92
        if (palette_colors_count > 256)
218
            return AVERROR_INVALIDDATA;
219
11356
        for (i = 0; i < palette_colors_count; ++i) {
220
11264
            cin->palette[i]    = 0xFFU << 24 | bytestream_get_le24(&buf);
221
11264
            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


92
    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
84
    case 38:
275
84
        res = cin_decode_lzss(buf, bitmap_frame_size,
276
84
                              cin->bitmap_table[CIN_CUR_BMP],
277
84
                              cin->bitmap_size);
278
84
        if (res < 0)
279
            return res;
280
84
        break;
281
8
    case 39:
282
8
        res = cin_decode_lzss(buf, bitmap_frame_size,
283
8
                              cin->bitmap_table[CIN_CUR_BMP],
284
8
                              cin->bitmap_size);
285
8
        if (res < 0)
286
            return res;
287
8
        cin_apply_delta_data(cin->bitmap_table[CIN_PRE_BMP],
288
8
                             cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size);
289
8
        break;
290
    }
291
292
92
    if ((res = ff_reget_buffer(avctx, cin->frame, 0)) < 0)
293
        return res;
294
295
92
    memcpy(cin->frame->data[1], cin->palette, sizeof(cin->palette));
296
92
    cin->frame->palette_has_changed = 1;
297
14812
    for (y = 0; y < cin->avctx->height; ++y)
298
14720
        memcpy(cin->frame->data[0] + (cin->avctx->height - 1 - y) * cin->frame->linesize[0],
299
14720
               cin->bitmap_table[CIN_CUR_BMP] + y * cin->avctx->width,
300
14720
               cin->avctx->width);
301
302
92
    FFSWAP(uint8_t *, cin->bitmap_table[CIN_CUR_BMP],
303
                      cin->bitmap_table[CIN_PRE_BMP]);
304
305
92
    if ((res = av_frame_ref(data, cin->frame)) < 0)
306
        return res;
307
308
92
    *got_frame = 1;
309
310
92
    return buf_size;
311
}
312
313
3
static av_cold int cinvideo_decode_end(AVCodecContext *avctx)
314
{
315
3
    CinVideoContext *cin = avctx->priv_data;
316
317
3
    av_frame_free(&cin->frame);
318
319
3
    destroy_buffers(cin);
320
321
3
    return 0;
322
}
323
324
AVCodec ff_dsicinvideo_decoder = {
325
    .name           = "dsicinvideo",
326
    .long_name      = NULL_IF_CONFIG_SMALL("Delphine Software International CIN video"),
327
    .type           = AVMEDIA_TYPE_VIDEO,
328
    .id             = AV_CODEC_ID_DSICINVIDEO,
329
    .priv_data_size = sizeof(CinVideoContext),
330
    .init           = cinvideo_decode_init,
331
    .close          = cinvideo_decode_end,
332
    .decode         = cinvideo_decode_frame,
333
    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
334
    .capabilities   = AV_CODEC_CAP_DR1,
335
};