GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavcodec/dfa.c Lines: 137 251 54.6 %
Date: 2019-11-18 18:00:01 Branches: 72 158 45.6 %

Line Branch Exec Source
1
/*
2
 * Chronomaster DFA Video Decoder
3
 * Copyright (c) 2011 Konstantin Shishkov
4
 * based on work by Vladimir "VAG" Gneushev
5
 *
6
 * This file is part of FFmpeg.
7
 *
8
 * FFmpeg is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public
10
 * License as published by the Free Software Foundation; either
11
 * version 2.1 of the License, or (at your option) any later version.
12
 *
13
 * FFmpeg is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with FFmpeg; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
 */
22
23
#include <inttypes.h>
24
25
#include "avcodec.h"
26
#include "bytestream.h"
27
#include "internal.h"
28
29
#include "libavutil/avassert.h"
30
#include "libavutil/imgutils.h"
31
#include "libavutil/mem.h"
32
33
typedef struct DfaContext {
34
    uint32_t pal[256];
35
    uint8_t *frame_buf;
36
} DfaContext;
37
38
22
static av_cold int dfa_decode_init(AVCodecContext *avctx)
39
{
40
22
    DfaContext *s = avctx->priv_data;
41
42
22
    avctx->pix_fmt = AV_PIX_FMT_PAL8;
43
44

22
    if (!avctx->width || !avctx->height || FFMAX(avctx->width, avctx->height) >= (1<<16))
45
        return AVERROR_INVALIDDATA;
46
47
22
    av_assert0(av_image_check_size(avctx->width, avctx->height, 0, avctx) >= 0);
48
49
22
    s->frame_buf = av_mallocz(avctx->width * avctx->height);
50
22
    if (!s->frame_buf)
51
        return AVERROR(ENOMEM);
52
53
22
    return 0;
54
}
55
56
static int decode_copy(GetByteContext *gb, uint8_t *frame, int width, int height)
57
{
58
    const int size = width * height;
59
60
    if (bytestream2_get_buffer(gb, frame, size) != size)
61
        return AVERROR_INVALIDDATA;
62
    return 0;
63
}
64
65
35
static int decode_tsw1(GetByteContext *gb, uint8_t *frame, int width, int height)
66
{
67
35
    const uint8_t *frame_start = frame;
68
35
    const uint8_t *frame_end   = frame + width * height;
69
35
    int mask = 0x10000, bitbuf = 0;
70
    int v, count;
71
    unsigned segments;
72
    unsigned offset;
73
74
35
    segments = bytestream2_get_le32(gb);
75
35
    offset   = bytestream2_get_le32(gb);
76

35
    if (segments == 0 && offset == frame_end - frame)
77
1
        return 0; // skip frame
78
34
    if (frame_end - frame <= offset)
79
        return AVERROR_INVALIDDATA;
80
34
    frame += offset;
81
566915
    while (segments--) {
82
566883
        if (bytestream2_get_bytes_left(gb) < 2)
83
2
            return AVERROR_INVALIDDATA;
84
566881
        if (mask == 0x10000) {
85
35445
            bitbuf = bytestream2_get_le16u(gb);
86
35445
            mask = 1;
87
        }
88
566881
        if (frame_end - frame < 2)
89
            return AVERROR_INVALIDDATA;
90
566881
        if (bitbuf & mask) {
91
222937
            v = bytestream2_get_le16(gb);
92
222937
            offset = (v & 0x1FFF) << 1;
93
222937
            count = ((v >> 13) + 2) << 1;
94

222937
            if (frame - frame_start < offset || frame_end - frame < count)
95
                return AVERROR_INVALIDDATA;
96
222937
            av_memcpy_backptr(frame, offset, count);
97
222937
            frame += count;
98
        } else {
99
343944
            *frame++ = bytestream2_get_byte(gb);
100
343944
            *frame++ = bytestream2_get_byte(gb);
101
        }
102
566881
        mask <<= 1;
103
    }
104
105
32
    return 0;
106
}
107
108
121
static int decode_dsw1(GetByteContext *gb, uint8_t *frame, int width, int height)
109
{
110
121
    const uint8_t *frame_start = frame;
111
121
    const uint8_t *frame_end   = frame + width * height;
112
121
    int mask = 0x10000, bitbuf = 0;
113
    int v, offset, count, segments;
114
115
121
    segments = bytestream2_get_le16(gb);
116
460962
    while (segments--) {
117
460846
        if (bytestream2_get_bytes_left(gb) < 2)
118
5
            return AVERROR_INVALIDDATA;
119
460841
        if (mask == 0x10000) {
120
57659
            bitbuf = bytestream2_get_le16u(gb);
121
57659
            mask = 1;
122
        }
123
460841
        if (frame_end - frame < 2)
124
            return AVERROR_INVALIDDATA;
125
460841
        if (bitbuf & mask) {
126
124238
            v = bytestream2_get_le16(gb);
127
124238
            offset = (v & 0x1FFF) << 1;
128
124238
            count = ((v >> 13) + 2) << 1;
129

124238
            if (frame - frame_start < offset || frame_end - frame < count)
130
                return AVERROR_INVALIDDATA;
131
124238
            av_memcpy_backptr(frame, offset, count);
132
124238
            frame += count;
133
336603
        } else if (bitbuf & (mask << 1)) {
134
70168
            frame += bytestream2_get_le16(gb);
135
        } else {
136
266435
            *frame++ = bytestream2_get_byte(gb);
137
266435
            *frame++ = bytestream2_get_byte(gb);
138
        }
139
460841
        mask <<= 2;
140
    }
141
142
116
    return 0;
143
}
144
145
static int decode_dds1(GetByteContext *gb, uint8_t *frame, int width, int height)
146
{
147
    const uint8_t *frame_start = frame;
148
    const uint8_t *frame_end   = frame + width * height;
149
    int mask = 0x10000, bitbuf = 0;
150
    int i, v, offset, count, segments;
151
152
    if ((width | height) & 1)
153
        return AVERROR_INVALIDDATA;
154
    segments = bytestream2_get_le16(gb);
155
    while (segments--) {
156
        if (bytestream2_get_bytes_left(gb) < 2)
157
            return AVERROR_INVALIDDATA;
158
        if (mask == 0x10000) {
159
            bitbuf = bytestream2_get_le16u(gb);
160
            mask = 1;
161
        }
162
163
        if (bitbuf & mask) {
164
            v = bytestream2_get_le16(gb);
165
            offset = (v & 0x1FFF) << 2;
166
            count = ((v >> 13) + 2) << 1;
167
            if (frame - frame_start < offset || frame_end - frame < count*2 + width)
168
                return AVERROR_INVALIDDATA;
169
            for (i = 0; i < count; i++) {
170
                frame[0] = frame[1] =
171
                frame[width] = frame[width + 1] = frame[-offset];
172
173
                frame += 2;
174
            }
175
        } else if (bitbuf & (mask << 1)) {
176
            v = bytestream2_get_le16(gb)*2;
177
            if (frame - frame_end < v)
178
                return AVERROR_INVALIDDATA;
179
            frame += v;
180
        } else {
181
            if (width < 4 || frame_end - frame < width + 4)
182
                return AVERROR_INVALIDDATA;
183
            frame[0] = frame[1] =
184
            frame[width] = frame[width + 1] =  bytestream2_get_byte(gb);
185
            frame += 2;
186
            frame[0] = frame[1] =
187
            frame[width] = frame[width + 1] =  bytestream2_get_byte(gb);
188
            frame += 2;
189
        }
190
        mask <<= 2;
191
    }
192
193
    return 0;
194
}
195
196
static int decode_bdlt(GetByteContext *gb, uint8_t *frame, int width, int height)
197
{
198
    uint8_t *line_ptr;
199
    int count, lines, segments;
200
201
    count = bytestream2_get_le16(gb);
202
    if (count >= height)
203
        return AVERROR_INVALIDDATA;
204
    frame += width * count;
205
    lines = bytestream2_get_le16(gb);
206
    if (count + lines > height)
207
        return AVERROR_INVALIDDATA;
208
209
    while (lines--) {
210
        if (bytestream2_get_bytes_left(gb) < 1)
211
            return AVERROR_INVALIDDATA;
212
        line_ptr = frame;
213
        frame += width;
214
        segments = bytestream2_get_byteu(gb);
215
        while (segments--) {
216
            if (frame - line_ptr <= bytestream2_peek_byte(gb))
217
                return AVERROR_INVALIDDATA;
218
            line_ptr += bytestream2_get_byte(gb);
219
            count = (int8_t)bytestream2_get_byte(gb);
220
            if (count >= 0) {
221
                if (frame - line_ptr < count)
222
                    return AVERROR_INVALIDDATA;
223
                if (bytestream2_get_buffer(gb, line_ptr, count) != count)
224
                    return AVERROR_INVALIDDATA;
225
            } else {
226
                count = -count;
227
                if (frame - line_ptr < count)
228
                    return AVERROR_INVALIDDATA;
229
                memset(line_ptr, bytestream2_get_byte(gb), count);
230
            }
231
            line_ptr += count;
232
        }
233
    }
234
235
    return 0;
236
}
237
238
11
static int decode_wdlt(GetByteContext *gb, uint8_t *frame, int width, int height)
239
{
240
11
    const uint8_t *frame_end   = frame + width * height;
241
    uint8_t *line_ptr;
242
    int count, i, v, lines, segments;
243
11
    int y = 0;
244
245
11
    lines = bytestream2_get_le16(gb);
246
11
    if (lines > height)
247
        return AVERROR_INVALIDDATA;
248
249
1448
    while (lines--) {
250
1438
        if (bytestream2_get_bytes_left(gb) < 2)
251
            return AVERROR_INVALIDDATA;
252
1438
        segments = bytestream2_get_le16u(gb);
253
1452
        while ((segments & 0xC000) == 0xC000) {
254
14
            unsigned skip_lines = -(int16_t)segments;
255
14
            int64_t delta = -((int16_t)segments * (int64_t)width);
256

14
            if (frame_end - frame <= delta || y + lines + skip_lines > height)
257
                return AVERROR_INVALIDDATA;
258
14
            frame    += delta;
259
14
            y        += skip_lines;
260
14
            segments = bytestream2_get_le16(gb);
261
        }
262
263
1438
        if (frame_end <= frame)
264
            return AVERROR_INVALIDDATA;
265
1438
        if (segments & 0x8000) {
266
            frame[width - 1] = segments & 0xFF;
267
            segments = bytestream2_get_le16(gb);
268
        }
269
1438
        line_ptr = frame;
270
1438
        if (frame_end - frame < width)
271
            return AVERROR_INVALIDDATA;
272
1438
        frame += width;
273
1438
        y++;
274
6577
        while (segments--) {
275
5140
            if (frame - line_ptr <= bytestream2_peek_byte(gb))
276
                return AVERROR_INVALIDDATA;
277
5140
            line_ptr += bytestream2_get_byte(gb);
278
5140
            count = (int8_t)bytestream2_get_byte(gb);
279
5140
            if (count >= 0) {
280
4691
                if (frame - line_ptr < count * 2)
281
                    return AVERROR_INVALIDDATA;
282
4691
                if (bytestream2_get_buffer(gb, line_ptr, count * 2) != count * 2)
283
1
                    return AVERROR_INVALIDDATA;
284
4690
                line_ptr += count * 2;
285
            } else {
286
449
                count = -count;
287
449
                if (frame - line_ptr < count * 2)
288
                    return AVERROR_INVALIDDATA;
289
449
                v = bytestream2_get_le16(gb);
290
17044
                for (i = 0; i < count; i++)
291
16595
                    bytestream_put_le16(&line_ptr, v);
292
            }
293
        }
294
    }
295
296
10
    return 0;
297
}
298
299
static int decode_tdlt(GetByteContext *gb, uint8_t *frame, int width, int height)
300
{
301
    const uint8_t *frame_end = frame + width * height;
302
    uint32_t segments = bytestream2_get_le32(gb);
303
    int skip, copy;
304
305
    while (segments--) {
306
        if (bytestream2_get_bytes_left(gb) < 2)
307
            return AVERROR_INVALIDDATA;
308
        copy = bytestream2_get_byteu(gb) * 2;
309
        skip = bytestream2_get_byteu(gb) * 2;
310
        if (frame_end - frame < copy + skip ||
311
            bytestream2_get_bytes_left(gb) < copy)
312
            return AVERROR_INVALIDDATA;
313
        frame += skip;
314
        bytestream2_get_buffer(gb, frame, copy);
315
        frame += copy;
316
    }
317
318
    return 0;
319
}
320
321
static int decode_blck(GetByteContext *gb, uint8_t *frame, int width, int height)
322
{
323
    memset(frame, 0, width * height);
324
    return 0;
325
}
326
327
328
typedef int (*chunk_decoder)(GetByteContext *gb, uint8_t *frame, int width, int height);
329
330
static const chunk_decoder decoder[8] = {
331
    decode_copy, decode_tsw1, decode_bdlt, decode_wdlt,
332
    decode_tdlt, decode_dsw1, decode_blck, decode_dds1,
333
};
334
335
static const char * const chunk_name[8] = {
336
    "COPY", "TSW1", "BDLT", "WDLT", "TDLT", "DSW1", "BLCK", "DDS1"
337
};
338
339
172
static int dfa_decode_frame(AVCodecContext *avctx,
340
                            void *data, int *got_frame,
341
                            AVPacket *avpkt)
342
{
343
172
    AVFrame *frame = data;
344
172
    DfaContext *s = avctx->priv_data;
345
    GetByteContext gb;
346
172
    const uint8_t *buf = avpkt->data;
347
    uint32_t chunk_type, chunk_size;
348
    uint8_t *dst;
349
    int ret;
350
    int i, pal_elems;
351
172
    int version = avctx->extradata_size==2 ? AV_RL16(avctx->extradata) : 0;
352
353
172
    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
354
        return ret;
355
356
172
    bytestream2_init(&gb, avpkt->data, avpkt->size);
357
343
    while (bytestream2_get_bytes_left(&gb) > 0) {
358
343
        if (bytestream2_get_bytes_left(&gb) < 12)
359
            return AVERROR_INVALIDDATA;
360
343
        bytestream2_skip(&gb, 4);
361
343
        chunk_size = bytestream2_get_le32(&gb);
362
343
        chunk_type = bytestream2_get_le32(&gb);
363
343
        if (!chunk_type)
364
164
            break;
365
179
        if (chunk_type == 1) {
366
12
            pal_elems = FFMIN(chunk_size / 3, 256);
367
3084
            for (i = 0; i < pal_elems; i++) {
368
3072
                s->pal[i] = bytestream2_get_be24(&gb) << 2;
369
3072
                s->pal[i] |= 0xFFU << 24 | (s->pal[i] >> 6) & 0x30303;
370
            }
371
12
            frame->palette_has_changed = 1;
372
167
        } else if (chunk_type <= 9) {
373
167
            if (decoder[chunk_type - 2](&gb, s->frame_buf, avctx->width, avctx->height)) {
374
8
                av_log(avctx, AV_LOG_ERROR, "Error decoding %s chunk\n",
375
8
                       chunk_name[chunk_type - 2]);
376
8
                return AVERROR_INVALIDDATA;
377
            }
378
        } else {
379
            av_log(avctx, AV_LOG_WARNING,
380
                   "Ignoring unknown chunk type %"PRIu32"\n",
381
                   chunk_type);
382
        }
383
171
        buf += chunk_size;
384
    }
385
386
164
    buf = s->frame_buf;
387
164
    dst = frame->data[0];
388
47294
    for (i = 0; i < avctx->height; i++) {
389
47130
        if(version == 0x100) {
390
            int j;
391
            for(j = 0; j < avctx->width; j++) {
392
                dst[j] = buf[ (i&3)*(avctx->width /4) + (j/4) +
393
                             ((j&3)*(avctx->height/4) + (i/4))*avctx->width];
394
            }
395
        } else {
396
47130
            memcpy(dst, buf, avctx->width);
397
47130
            buf += avctx->width;
398
        }
399
47130
        dst += frame->linesize[0];
400
    }
401
164
    memcpy(frame->data[1], s->pal, sizeof(s->pal));
402
403
164
    *got_frame = 1;
404
405
164
    return avpkt->size;
406
}
407
408
22
static av_cold int dfa_decode_end(AVCodecContext *avctx)
409
{
410
22
    DfaContext *s = avctx->priv_data;
411
412
22
    av_freep(&s->frame_buf);
413
414
22
    return 0;
415
}
416
417
AVCodec ff_dfa_decoder = {
418
    .name           = "dfa",
419
    .long_name      = NULL_IF_CONFIG_SMALL("Chronomaster DFA"),
420
    .type           = AVMEDIA_TYPE_VIDEO,
421
    .id             = AV_CODEC_ID_DFA,
422
    .priv_data_size = sizeof(DfaContext),
423
    .init           = dfa_decode_init,
424
    .close          = dfa_decode_end,
425
    .decode         = dfa_decode_frame,
426
    .capabilities   = AV_CODEC_CAP_DR1,
427
};