Coverage Report

Created: 2025-11-16 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/qpeg.c
Line
Count
Source
1
/*
2
 * QPEG codec
3
 * Copyright (c) 2004 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
 * QPEG codec.
25
 */
26
27
#include "avcodec.h"
28
#include "bytestream.h"
29
#include "codec_internal.h"
30
#include "decode.h"
31
32
#include "libavutil/attributes.h"
33
34
typedef struct QpegContext{
35
    AVCodecContext *avctx;
36
    AVFrame *ref;
37
    uint32_t pal[256];
38
    GetByteContext buffer;
39
} QpegContext;
40
41
static void qpeg_decode_intra(QpegContext *qctx, uint8_t *dst,
42
                              int stride, int width, int height)
43
12.4k
{
44
12.4k
    int i;
45
12.4k
    int code;
46
12.4k
    int c0, c1;
47
12.4k
    int run, copy;
48
12.4k
    int filled = 0;
49
12.4k
    int rows_to_go;
50
51
12.4k
    rows_to_go = height;
52
12.4k
    height--;
53
12.4k
    dst = dst + height * stride;
54
55
34.2k
    while ((bytestream2_get_bytes_left(&qctx->buffer) > 0) && (rows_to_go > 0)) {
56
22.0k
        code = bytestream2_get_byte(&qctx->buffer);
57
22.0k
        run = copy = 0;
58
22.0k
        if(code == 0xFC) /* end-of-picture code */
59
276
            break;
60
21.7k
        if(code >= 0xF8) { /* very long run */
61
1.54k
            c0 = bytestream2_get_byte(&qctx->buffer);
62
1.54k
            c1 = bytestream2_get_byte(&qctx->buffer);
63
1.54k
            run = ((code & 0x7) << 16) + (c0 << 8) + c1 + 2;
64
20.2k
        } else if (code >= 0xF0) { /* long run */
65
732
            c0 = bytestream2_get_byte(&qctx->buffer);
66
732
            run = ((code & 0xF) << 8) + c0 + 2;
67
19.5k
        } else if (code >= 0xE0) { /* short run */
68
450
            run = (code & 0x1F) + 2;
69
19.0k
        } else if (code >= 0xC0) { /* very long copy */
70
2.36k
            c0 = bytestream2_get_byte(&qctx->buffer);
71
2.36k
            c1 = bytestream2_get_byte(&qctx->buffer);
72
2.36k
            copy = ((code & 0x3F) << 16) + (c0 << 8) + c1 + 1;
73
16.6k
        } else if (code >= 0x80) { /* long copy */
74
1.21k
            c0 = bytestream2_get_byte(&qctx->buffer);
75
1.21k
            copy = ((code & 0x7F) << 8) + c0 + 1;
76
15.4k
        } else { /* short copy */
77
15.4k
            copy = code + 1;
78
15.4k
        }
79
80
        /* perform actual run or copy */
81
21.7k
        if(run) {
82
2.72k
            int p;
83
84
2.72k
            p = bytestream2_get_byte(&qctx->buffer);
85
5.95k
            for(i = 0; i < run; i++) {
86
4.02k
                int step = FFMIN(run - i, width - filled);
87
4.02k
                memset(dst+filled, p, step);
88
4.02k
                filled += step;
89
4.02k
                i      += step - 1;
90
4.02k
                if (filled >= width) {
91
2.14k
                    filled = 0;
92
2.14k
                    dst -= stride;
93
2.14k
                    rows_to_go--;
94
6.01M
                    while (run - i > width && rows_to_go > 0) {
95
6.01M
                        memset(dst, p, width);
96
6.01M
                        dst -= stride;
97
6.01M
                        rows_to_go--;
98
6.01M
                        i += width;
99
6.01M
                    }
100
2.14k
                    if(rows_to_go <= 0)
101
796
                        break;
102
2.14k
                }
103
4.02k
            }
104
19.0k
        } else {
105
19.0k
            if (bytestream2_get_bytes_left(&qctx->buffer) < copy)
106
2.65k
                copy = bytestream2_get_bytes_left(&qctx->buffer);
107
70.2k
            while (copy > 0) {
108
51.4k
                int step = FFMIN(copy, width - filled);
109
51.4k
                bytestream2_get_bufferu(&qctx->buffer, dst + filled, step);
110
51.4k
                filled += step;
111
51.4k
                copy -= step;
112
51.4k
                if (filled >= width) {
113
33.8k
                    filled = 0;
114
33.8k
                    dst -= stride;
115
33.8k
                    rows_to_go--;
116
33.8k
                    if(rows_to_go <= 0)
117
220
                        break;
118
33.8k
                }
119
51.4k
            }
120
19.0k
        }
121
21.7k
    }
122
12.4k
}
123
124
static const uint8_t qpeg_table_h[16] =
125
 { 0x00, 0x20, 0x20, 0x20, 0x18, 0x10, 0x10, 0x20, 0x10, 0x08, 0x18, 0x08, 0x08, 0x18, 0x10, 0x04};
126
static const uint8_t qpeg_table_w[16] =
127
 { 0x00, 0x20, 0x18, 0x08, 0x18, 0x10, 0x20, 0x10, 0x08, 0x10, 0x20, 0x20, 0x08, 0x10, 0x18, 0x04};
128
129
/* Decodes delta frames */
130
static void av_noinline qpeg_decode_inter(QpegContext *qctx, uint8_t *dst,
131
                              int stride, int width, int height,
132
                              int delta, const uint8_t *ctable,
133
                              uint8_t *refdata)
134
16.5k
{
135
16.5k
    int i, j;
136
16.5k
    int code;
137
16.5k
    int filled = 0;
138
16.5k
    int orig_height;
139
140
16.5k
    if (refdata) {
141
        /* copy prev frame */
142
246M
        for (i = 0; i < height; i++)
143
246M
            memcpy(dst + (i * stride), refdata + (i * stride), width);
144
10.6k
    } else {
145
10.6k
        refdata = dst;
146
10.6k
    }
147
148
16.5k
    orig_height = height;
149
16.5k
    height--;
150
16.5k
    dst = dst + height * stride;
151
152
2.56M
    while ((bytestream2_get_bytes_left(&qctx->buffer) > 0) && (height >= 0)) {
153
2.55M
        code = bytestream2_get_byte(&qctx->buffer);
154
155
2.55M
        if(delta) {
156
            /* motion compensation */
157
1.56M
            while(bytestream2_get_bytes_left(&qctx->buffer) > 0 && (code & 0xF0) == 0xF0) {
158
136k
                if(delta == 1) {
159
119k
                    int me_idx;
160
119k
                    int me_w, me_h, me_x, me_y;
161
119k
                    uint8_t *me_plane;
162
119k
                    int corr, val;
163
164
                    /* get block size by index */
165
119k
                    me_idx = code & 0xF;
166
119k
                    me_w = qpeg_table_w[me_idx];
167
119k
                    me_h = qpeg_table_h[me_idx];
168
169
                    /* extract motion vector */
170
119k
                    corr = bytestream2_get_byte(&qctx->buffer);
171
172
119k
                    val = corr >> 4;
173
119k
                    if(val > 7)
174
101k
                        val -= 16;
175
119k
                    me_x = val;
176
177
119k
                    val = corr & 0xF;
178
119k
                    if(val > 7)
179
97.2k
                        val -= 16;
180
119k
                    me_y = val;
181
182
                    /* check motion vector */
183
119k
                    if ((me_x + filled < 0) || (me_x + me_w + filled > width) ||
184
112k
                       (height - me_y - me_h < 0) || (height - me_y >= orig_height) ||
185
34.4k
                       (filled + me_w > width) || (height - me_h < 0))
186
86.8k
                        av_log(qctx->avctx, AV_LOG_ERROR, "Bogus motion vector (%i,%i), block size %ix%i at %i,%i\n",
187
86.8k
                               me_x, me_y, me_w, me_h, filled, height);
188
32.9k
                    else {
189
                        /* do motion compensation */
190
32.9k
                        me_plane = refdata + (filled + me_x) + (height - me_y) * stride;
191
218k
                        for(j = 0; j < me_h; j++) {
192
2.04M
                            for(i = 0; i < me_w; i++)
193
1.85M
                                dst[filled + i - (j * stride)] = me_plane[i - (j * stride)];
194
185k
                        }
195
32.9k
                    }
196
119k
                }
197
136k
                code = bytestream2_get_byte(&qctx->buffer);
198
136k
            }
199
1.42M
        }
200
201
2.55M
        if(code == 0xE0) /* end-of-picture code */
202
233
            break;
203
2.55M
        if(code > 0xE0) { /* run code: 0xE1..0xFF */
204
82.4k
            int p;
205
206
82.4k
            code &= 0x1F;
207
82.4k
            p = bytestream2_get_byte(&qctx->buffer);
208
2.30M
            for(i = 0; i <= code; i++) {
209
2.22M
                dst[filled++] = p;
210
2.22M
                if(filled >= width) {
211
27.6k
                    filled = 0;
212
27.6k
                    dst -= stride;
213
27.6k
                    height--;
214
27.6k
                    if (height < 0)
215
1.96k
                        break;
216
27.6k
                }
217
2.22M
            }
218
2.47M
        } else if(code >= 0xC0) { /* copy code: 0xC0..0xDF */
219
29.0k
            code &= 0x1F;
220
221
29.0k
            if(code + 1 > bytestream2_get_bytes_left(&qctx->buffer))
222
278
                break;
223
224
310k
            for(i = 0; i <= code; i++) {
225
282k
                dst[filled++] = bytestream2_get_byte(&qctx->buffer);
226
282k
                if(filled >= width) {
227
3.89k
                    filled = 0;
228
3.89k
                    dst -= stride;
229
3.89k
                    height--;
230
3.89k
                    if (height < 0)
231
198
                        break;
232
3.89k
                }
233
282k
            }
234
2.44M
        } else if(code >= 0x80) { /* skip code: 0x80..0xBF */
235
257k
            int skip;
236
237
257k
            code &= 0x3F;
238
            /* codes 0x80 and 0x81 are actually escape codes,
239
               skip value minus constant is in the next byte */
240
257k
            if(!code)
241
86.4k
                skip = bytestream2_get_byte(&qctx->buffer) +  64;
242
171k
            else if(code == 1)
243
18.7k
                skip = bytestream2_get_byte(&qctx->buffer) + 320;
244
152k
            else
245
152k
                skip = code;
246
257k
            filled += skip;
247
516k
            while( filled >= width) {
248
260k
                filled -= width;
249
260k
                dst -= stride;
250
260k
                height--;
251
260k
                if(height < 0)
252
1.32k
                    break;
253
260k
            }
254
2.18M
        } else {
255
            /* zero code treated as one-pixel skip */
256
2.18M
            if(code) {
257
389k
                dst[filled++] = ctable[code & 0x7F];
258
389k
            }
259
1.79M
            else
260
1.79M
                filled++;
261
2.18M
            if(filled >= width) {
262
27.5k
                filled = 0;
263
27.5k
                dst -= stride;
264
27.5k
                height--;
265
27.5k
            }
266
2.18M
        }
267
2.55M
    }
268
16.5k
}
269
270
static int decode_frame(AVCodecContext *avctx, AVFrame *p,
271
                        int *got_frame, AVPacket *avpkt)
272
58.5k
{
273
58.5k
    uint8_t ctable[128];
274
58.5k
    QpegContext * const a = avctx->priv_data;
275
58.5k
    AVFrame * const ref = a->ref;
276
58.5k
    uint8_t* outdata;
277
58.5k
    int delta, intra, ret;
278
279
58.5k
    if (avpkt->size < 0x86) {
280
28.6k
        av_log(avctx, AV_LOG_ERROR, "Packet is too small\n");
281
28.6k
        return AVERROR_INVALIDDATA;
282
28.6k
    }
283
284
29.9k
    bytestream2_init(&a->buffer, avpkt->data, avpkt->size);
285
286
29.9k
    if ((ret = ff_get_buffer(avctx, p, AV_GET_BUFFER_FLAG_REF)) < 0)
287
1.04k
        return ret;
288
28.9k
    outdata = p->data[0];
289
28.9k
    bytestream2_skip(&a->buffer, 4);
290
28.9k
    bytestream2_get_buffer(&a->buffer, ctable, 128);
291
28.9k
    bytestream2_skip(&a->buffer, 1);
292
293
28.9k
    delta = bytestream2_get_byte(&a->buffer);
294
28.9k
    intra = delta == 0x10;
295
28.9k
    if (intra) {
296
12.4k
        qpeg_decode_intra(a, outdata, p->linesize[0], avctx->width, avctx->height);
297
16.5k
    } else {
298
16.5k
        qpeg_decode_inter(a, outdata, p->linesize[0], avctx->width, avctx->height, delta, ctable, ref->data[0]);
299
16.5k
    }
300
301
    /* make the palette available on the way out */
302
28.9k
    ff_copy_palette(a->pal, avpkt, avctx);
303
28.9k
    memcpy(p->data[1], a->pal, AVPALETTE_SIZE);
304
305
28.9k
    if ((ret = av_frame_replace(ref, p)) < 0)
306
0
        return ret;
307
308
28.9k
    if (intra)
309
12.4k
        p->flags |= AV_FRAME_FLAG_KEY;
310
16.5k
    else
311
16.5k
        p->flags &= ~AV_FRAME_FLAG_KEY;
312
28.9k
    p->pict_type = intra ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
313
314
28.9k
    *got_frame      = 1;
315
316
28.9k
    return avpkt->size;
317
28.9k
}
318
319
static av_cold void decode_flush(AVCodecContext *avctx)
320
23.8k
{
321
23.8k
    QpegContext * const a = avctx->priv_data;
322
23.8k
    int i, pal_size;
323
23.8k
    const uint8_t *pal_src;
324
325
23.8k
    av_frame_unref(a->ref);
326
327
23.8k
    pal_size = FFMIN(1024U, avctx->extradata_size);
328
23.8k
    pal_src = avctx->extradata + avctx->extradata_size - pal_size;
329
330
441k
    for (i=0; i<pal_size/4; i++)
331
417k
        a->pal[i] = 0xFFU<<24 | AV_RL32(pal_src+4*i);
332
23.8k
}
333
334
static av_cold int decode_end(AVCodecContext *avctx)
335
1.04k
{
336
1.04k
    QpegContext * const a = avctx->priv_data;
337
338
1.04k
    av_frame_free(&a->ref);
339
340
1.04k
    return 0;
341
1.04k
}
342
343
1.04k
static av_cold int decode_init(AVCodecContext *avctx){
344
1.04k
    QpegContext * const a = avctx->priv_data;
345
346
1.04k
    a->avctx = avctx;
347
1.04k
    avctx->pix_fmt= AV_PIX_FMT_PAL8;
348
349
1.04k
    a->ref = av_frame_alloc();
350
1.04k
    if (!a->ref)
351
0
        return AVERROR(ENOMEM);
352
353
1.04k
    decode_flush(avctx);
354
355
1.04k
    return 0;
356
1.04k
}
357
358
const FFCodec ff_qpeg_decoder = {
359
    .p.name         = "qpeg",
360
    CODEC_LONG_NAME("Q-team QPEG"),
361
    .p.type         = AVMEDIA_TYPE_VIDEO,
362
    .p.id           = AV_CODEC_ID_QPEG,
363
    .priv_data_size = sizeof(QpegContext),
364
    .init           = decode_init,
365
    .close          = decode_end,
366
    FF_CODEC_DECODE_CB(decode_frame),
367
    .flush          = decode_flush,
368
    .p.capabilities = AV_CODEC_CAP_DR1,
369
    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
370
};