Coverage Report

Created: 2025-12-31 07:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/dxa.c
Line
Count
Source
1
/*
2
 * Feeble Files/ScummVM DXA decoder
3
 * Copyright (c) 2007 Konstantin Shishkov
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
 * DXA Video decoder
25
 */
26
27
#include "libavutil/intreadwrite.h"
28
#include "libavutil/mem.h"
29
#include "bytestream.h"
30
#include "avcodec.h"
31
#include "codec_internal.h"
32
#include "decode.h"
33
34
#include <zlib.h>
35
36
/*
37
 * Decoder context
38
 */
39
typedef struct DxaDecContext {
40
    AVFrame *prev;
41
42
    int dsize;
43
6.97k
#define DECOMP_BUF_PADDING 16
44
    uint8_t *decomp_buf;
45
    uint32_t pal[256];
46
} DxaDecContext;
47
48
static const uint8_t shift1[6] = { 0, 8, 8, 8, 4, 4 };
49
static const uint8_t shift2[6] = { 0, 0, 8, 4, 0, 4 };
50
51
static int decode_13(AVCodecContext *avctx, DxaDecContext *c, uint8_t* dst,
52
                     int stride, uint8_t *src, int srcsize, uint8_t *ref)
53
831
{
54
831
    uint8_t *code, *data, *mv, *msk, *tmp, *tmp2;
55
831
    uint8_t *src_end = src + srcsize;
56
831
    int i, j, k;
57
831
    int type, x, y, d, d2;
58
831
    uint32_t mask;
59
60
831
    if (12ULL  + ((avctx->width * avctx->height) >> 4) + AV_RB32(src + 0) + AV_RB32(src + 4) > srcsize)
61
802
        return AVERROR_INVALIDDATA;
62
63
29
    code = src  + 12;
64
29
    data = code + ((avctx->width * avctx->height) >> 4);
65
29
    mv   = data + AV_RB32(src + 0);
66
29
    msk  = mv   + AV_RB32(src + 4);
67
68
285
    for(j = 0; j < avctx->height; j += 4){
69
530
        for(i = 0; i < avctx->width; i += 4){
70
274
            if (data > src_end || mv > src_end || msk > src_end)
71
0
                return AVERROR_INVALIDDATA;
72
274
            tmp  = dst + i;
73
274
            tmp2 = ref + i;
74
274
            type = *code++;
75
274
            switch(type){
76
0
            case 4: // motion compensation
77
0
                x = (*mv) >> 4;    if(x & 8) x = 8 - x;
78
0
                y = (*mv++) & 0xF; if(y & 8) y = 8 - y;
79
0
                if (i < -x || avctx->width  - i - 4 < x ||
80
0
                    j < -y || avctx->height - j - 4 < y) {
81
0
                    av_log(avctx, AV_LOG_ERROR, "MV %d %d out of bounds\n", x,y);
82
0
                    return AVERROR_INVALIDDATA;
83
0
                }
84
0
                tmp2 += x + y*stride;
85
274
            case 0: // skip
86
274
            case 5: // skip in method 12
87
1.37k
                for(y = 0; y < 4; y++){
88
1.09k
                    memcpy(tmp, tmp2, 4);
89
1.09k
                    tmp  += stride;
90
1.09k
                    tmp2 += stride;
91
1.09k
                }
92
274
                break;
93
0
            case 1:  // masked change
94
0
            case 10: // masked change with only half of pixels changed
95
0
            case 11: // cases 10-15 are for method 12 only
96
0
            case 12:
97
0
            case 13:
98
0
            case 14:
99
0
            case 15:
100
0
                if(type == 1){
101
0
                    mask = AV_RB16(msk);
102
0
                    msk += 2;
103
0
                }else{
104
0
                    type -= 10;
105
0
                    mask = ((msk[0] & 0xF0) << shift1[type]) | ((msk[0] & 0xF) << shift2[type]);
106
0
                    msk++;
107
0
                }
108
0
                for(y = 0; y < 4; y++){
109
0
                    for(x = 0; x < 4; x++){
110
0
                        tmp[x] = (mask & 0x8000) ? *data++ : tmp2[x];
111
0
                        mask <<= 1;
112
0
                    }
113
0
                    tmp  += stride;
114
0
                    tmp2 += stride;
115
0
                }
116
0
                break;
117
0
            case 2: // fill block
118
0
                for(y = 0; y < 4; y++){
119
0
                    memset(tmp, data[0], 4);
120
0
                    tmp += stride;
121
0
                }
122
0
                data++;
123
0
                break;
124
0
            case 3: // raw block
125
0
                for(y = 0; y < 4; y++){
126
0
                    memcpy(tmp, data, 4);
127
0
                    data += 4;
128
0
                    tmp  += stride;
129
0
                }
130
0
                break;
131
0
            case 8: // subblocks - method 13 only
132
0
                mask = *msk++;
133
0
                for(k = 0; k < 4; k++){
134
0
                    d  = ((k & 1) << 1) + ((k & 2) * stride);
135
0
                    d2 = ((k & 1) << 1) + ((k & 2) * stride);
136
0
                    tmp2 = ref + i + d2;
137
0
                    switch(mask & 0xC0){
138
0
                    case 0x80: // motion compensation
139
0
                        x = (*mv) >> 4;    if(x & 8) x = 8 - x;
140
0
                        y = (*mv++) & 0xF; if(y & 8) y = 8 - y;
141
0
                        if (i + 2*(k & 1) < -x || avctx->width  - i - 2*(k & 1) - 2 < x ||
142
0
                            j +   (k & 2) < -y || avctx->height - j -   (k & 2) - 2 < y) {
143
0
                            av_log(avctx, AV_LOG_ERROR, "MV %d %d out of bounds\n", x,y);
144
0
                            return AVERROR_INVALIDDATA;
145
0
                        }
146
0
                        tmp2 += x + y*stride;
147
0
                    case 0x00: // skip
148
0
                        tmp[d + 0         ] = tmp2[0];
149
0
                        tmp[d + 1         ] = tmp2[1];
150
0
                        tmp[d + 0 + stride] = tmp2[0 + stride];
151
0
                        tmp[d + 1 + stride] = tmp2[1 + stride];
152
0
                        break;
153
0
                    case 0x40: // fill
154
0
                        tmp[d + 0         ] = data[0];
155
0
                        tmp[d + 1         ] = data[0];
156
0
                        tmp[d + 0 + stride] = data[0];
157
0
                        tmp[d + 1 + stride] = data[0];
158
0
                        data++;
159
0
                        break;
160
0
                    case 0xC0: // raw
161
0
                        tmp[d + 0         ] = *data++;
162
0
                        tmp[d + 1         ] = *data++;
163
0
                        tmp[d + 0 + stride] = *data++;
164
0
                        tmp[d + 1 + stride] = *data++;
165
0
                        break;
166
0
                    }
167
0
                    mask <<= 2;
168
0
                }
169
0
                break;
170
0
            case 32: // vector quantization - 2 colors
171
0
                mask = AV_RB16(msk);
172
0
                msk += 2;
173
0
                for(y = 0; y < 4; y++){
174
0
                    for(x = 0; x < 4; x++){
175
0
                        tmp[x] = data[mask & 1];
176
0
                        mask >>= 1;
177
0
                    }
178
0
                    tmp  += stride;
179
0
                    tmp2 += stride;
180
0
                }
181
0
                data += 2;
182
0
                break;
183
0
            case 33: // vector quantization - 3 or 4 colors
184
0
            case 34:
185
0
                mask = AV_RB32(msk);
186
0
                msk += 4;
187
0
                for(y = 0; y < 4; y++){
188
0
                    for(x = 0; x < 4; x++){
189
0
                        tmp[x] = data[mask & 3];
190
0
                        mask >>= 2;
191
0
                    }
192
0
                    tmp  += stride;
193
0
                    tmp2 += stride;
194
0
                }
195
0
                data += type - 30;
196
0
                break;
197
0
            default:
198
0
                av_log(avctx, AV_LOG_ERROR, "Unknown opcode %d\n", type);
199
0
                return AVERROR_INVALIDDATA;
200
274
            }
201
274
        }
202
256
        dst += stride * 4;
203
256
        ref += stride * 4;
204
256
    }
205
29
    return 0;
206
29
}
207
208
static int decode_frame(AVCodecContext *avctx, AVFrame *frame,
209
                        int *got_frame, AVPacket *avpkt)
210
143k
{
211
143k
    DxaDecContext * const c = avctx->priv_data;
212
143k
    uint8_t *outptr, *srcptr, *tmpptr;
213
143k
    unsigned long dsize;
214
143k
    int i, j, compr, ret;
215
143k
    int stride;
216
143k
    GetByteContext gb;
217
218
143k
    bytestream2_init(&gb, avpkt->data, avpkt->size);
219
220
    /* make the palette available on the way out */
221
143k
    if (bytestream2_peek_le32(&gb) == MKTAG('C','M','A','P')) {
222
2.97k
        bytestream2_skip(&gb, 4);
223
765k
        for(i = 0; i < 256; i++){
224
762k
            c->pal[i] = 0xFFU << 24 | bytestream2_get_be24(&gb);
225
762k
        }
226
2.97k
    }
227
228
143k
    if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
229
13.0k
        return ret;
230
130k
    memcpy(frame->data[1], c->pal, AVPALETTE_SIZE);
231
232
130k
    outptr = frame->data[0];
233
130k
    srcptr = c->decomp_buf;
234
130k
    tmpptr = c->prev->data[0];
235
130k
    stride = frame->linesize[0];
236
237
130k
    if (bytestream2_get_le32(&gb) == MKTAG('N','U','L','L'))
238
42.2k
        compr = -1;
239
87.8k
    else
240
87.8k
        compr = bytestream2_get_byte(&gb);
241
242
130k
    dsize = c->dsize;
243
130k
    if (compr != 4 && compr != -1) {
244
75.6k
        bytestream2_skip(&gb, 4);
245
75.6k
        if (uncompress(c->decomp_buf, &dsize, avpkt->data + bytestream2_tell(&gb),
246
75.6k
                       bytestream2_get_bytes_left(&gb)) != Z_OK) {
247
70.1k
            av_log(avctx, AV_LOG_ERROR, "Uncompress failed!\n");
248
70.1k
            return AVERROR_UNKNOWN;
249
70.1k
        }
250
5.51k
        memset(c->decomp_buf + dsize, 0, DECOMP_BUF_PADDING);
251
5.51k
    }
252
253
60.0k
    if (avctx->debug & FF_DEBUG_PICT_INFO)
254
0
        av_log(avctx, AV_LOG_DEBUG, "compr:%2d, dsize:%d\n", compr, (int)dsize);
255
256
60.0k
    switch(compr){
257
42.2k
    case -1:
258
42.2k
        frame->flags &= ~AV_FRAME_FLAG_KEY;
259
42.2k
        frame->pict_type = AV_PICTURE_TYPE_P;
260
42.2k
        if (c->prev->data[0])
261
41.9k
            memcpy(frame->data[0], c->prev->data[0], frame->linesize[0] * avctx->height);
262
317
        else{ // Should happen only when first frame is 'NULL'
263
317
            memset(frame->data[0], 0, frame->linesize[0] * avctx->height);
264
317
            frame->flags |= AV_FRAME_FLAG_KEY;
265
317
            frame->pict_type = AV_PICTURE_TYPE_I;
266
317
        }
267
42.2k
        break;
268
218
    case 2:
269
12.4k
    case 4:
270
12.4k
        frame->flags |= AV_FRAME_FLAG_KEY;
271
12.4k
        frame->pict_type = AV_PICTURE_TYPE_I;
272
44.9M
        for (j = 0; j < avctx->height; j++) {
273
44.9M
                memcpy(outptr, srcptr, avctx->width);
274
44.9M
            outptr += stride;
275
44.9M
            srcptr += avctx->width;
276
44.9M
        }
277
12.4k
        break;
278
2.29k
    case 3:
279
2.82k
    case 5:
280
2.82k
        if (!tmpptr) {
281
1.28k
            av_log(avctx, AV_LOG_ERROR, "Missing reference frame.\n");
282
1.28k
            if (!(avctx->flags2 & AV_CODEC_FLAG2_SHOW_ALL))
283
1.28k
                return AVERROR_INVALIDDATA;
284
1.28k
        }
285
1.54k
        frame->flags &= ~AV_FRAME_FLAG_KEY;
286
1.54k
        frame->pict_type = AV_PICTURE_TYPE_P;
287
5.26M
        for (j = 0; j < avctx->height; j++) {
288
5.26M
            if(tmpptr){
289
5.26G
                for(i = 0; i < avctx->width; i++)
290
5.25G
                    outptr[i] = srcptr[i] ^ tmpptr[i];
291
5.26M
                tmpptr += stride;
292
5.26M
            }else
293
0
                memcpy(outptr, srcptr, avctx->width);
294
5.26M
            outptr += stride;
295
5.26M
            srcptr += avctx->width;
296
5.26M
        }
297
1.54k
        break;
298
298
    case 12: // ScummVM coding
299
1.92k
    case 13:
300
1.92k
        frame->flags &= ~AV_FRAME_FLAG_KEY;
301
1.92k
        frame->pict_type = AV_PICTURE_TYPE_P;
302
1.92k
        if (!c->prev->data[0]) {
303
1.09k
            av_log(avctx, AV_LOG_ERROR, "Missing reference frame\n");
304
1.09k
            return AVERROR_INVALIDDATA;
305
1.09k
        }
306
831
        decode_13(avctx, c, frame->data[0], frame->linesize[0], srcptr, dsize, c->prev->data[0]);
307
831
        break;
308
541
    default:
309
541
        av_log(avctx, AV_LOG_ERROR, "Unknown/unsupported compression type %d\n", compr);
310
541
        return AVERROR_INVALIDDATA;
311
60.0k
    }
312
313
57.0k
    if ((ret = av_frame_replace(c->prev, frame)) < 0)
314
0
        return ret;
315
316
57.0k
    *got_frame = 1;
317
318
    /* always report that the buffer was completely consumed */
319
57.0k
    return avpkt->size;
320
57.0k
}
321
322
static av_cold int decode_init(AVCodecContext *avctx)
323
1.46k
{
324
1.46k
    DxaDecContext * const c = avctx->priv_data;
325
326
1.46k
    if (avctx->width%4 || avctx->height%4) {
327
10
        avpriv_request_sample(avctx, "dimensions are not a multiple of 4");
328
10
        return AVERROR_INVALIDDATA;
329
10
    }
330
331
1.45k
    c->prev = av_frame_alloc();
332
1.45k
    if (!c->prev)
333
0
        return AVERROR(ENOMEM);
334
335
1.45k
    avctx->pix_fmt = AV_PIX_FMT_PAL8;
336
337
1.45k
    c->dsize = avctx->width * avctx->height * 2;
338
1.45k
    c->decomp_buf = av_malloc(c->dsize + DECOMP_BUF_PADDING);
339
1.45k
    if (!c->decomp_buf) {
340
0
        av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n");
341
0
        return AVERROR(ENOMEM);
342
0
    }
343
344
1.45k
    return 0;
345
1.45k
}
346
347
static av_cold int decode_end(AVCodecContext *avctx)
348
1.46k
{
349
1.46k
    DxaDecContext * const c = avctx->priv_data;
350
351
1.46k
    av_freep(&c->decomp_buf);
352
1.46k
    av_frame_free(&c->prev);
353
354
1.46k
    return 0;
355
1.46k
}
356
357
const FFCodec ff_dxa_decoder = {
358
    .p.name         = "dxa",
359
    CODEC_LONG_NAME("Feeble Files/ScummVM DXA"),
360
    .p.type         = AVMEDIA_TYPE_VIDEO,
361
    .p.id           = AV_CODEC_ID_DXA,
362
    .priv_data_size = sizeof(DxaDecContext),
363
    .init           = decode_init,
364
    .close          = decode_end,
365
    FF_CODEC_DECODE_CB(decode_frame),
366
    .p.capabilities = AV_CODEC_CAP_DR1,
367
    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
368
};