Coverage Report

Created: 2026-07-25 07:52

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
9.91k
{
44
9.91k
    int i;
45
9.91k
    int code;
46
9.91k
    int c0, c1;
47
9.91k
    int run, copy;
48
9.91k
    int filled = 0;
49
9.91k
    int rows_to_go;
50
51
9.91k
    rows_to_go = height;
52
9.91k
    height--;
53
9.91k
    dst = dst + height * stride;
54
55
28.4k
    while ((bytestream2_get_bytes_left(&qctx->buffer) > 0) && (rows_to_go > 0)) {
56
18.7k
        code = bytestream2_get_byte(&qctx->buffer);
57
18.7k
        run = copy = 0;
58
18.7k
        if(code == 0xFC) /* end-of-picture code */
59
197
            break;
60
18.5k
        if(code >= 0xF8) { /* very long run */
61
1.29k
            c0 = bytestream2_get_byte(&qctx->buffer);
62
1.29k
            c1 = bytestream2_get_byte(&qctx->buffer);
63
1.29k
            run = ((code & 0x7) << 16) + (c0 << 8) + c1 + 2;
64
17.2k
        } else if (code >= 0xF0) { /* long run */
65
1.09k
            c0 = bytestream2_get_byte(&qctx->buffer);
66
1.09k
            run = ((code & 0xF) << 8) + c0 + 2;
67
16.1k
        } else if (code >= 0xE0) { /* short run */
68
516
            run = (code & 0x1F) + 2;
69
15.6k
        } else if (code >= 0xC0) { /* very long copy */
70
1.13k
            c0 = bytestream2_get_byte(&qctx->buffer);
71
1.13k
            c1 = bytestream2_get_byte(&qctx->buffer);
72
1.13k
            copy = ((code & 0x3F) << 16) + (c0 << 8) + c1 + 1;
73
14.5k
        } else if (code >= 0x80) { /* long copy */
74
1.32k
            c0 = bytestream2_get_byte(&qctx->buffer);
75
1.32k
            copy = ((code & 0x7F) << 8) + c0 + 1;
76
13.2k
        } else { /* short copy */
77
13.2k
            copy = code + 1;
78
13.2k
        }
79
80
        /* perform actual run or copy */
81
18.5k
        if(run) {
82
2.90k
            int p;
83
84
2.90k
            p = bytestream2_get_byte(&qctx->buffer);
85
7.24k
            for(i = 0; i < run; i++) {
86
4.74k
                int step = FFMIN(run - i, width - filled);
87
4.74k
                memset(dst+filled, p, step);
88
4.74k
                filled += step;
89
4.74k
                i      += step - 1;
90
4.74k
                if (filled >= width) {
91
2.30k
                    filled = 0;
92
2.30k
                    dst -= stride;
93
2.30k
                    rows_to_go--;
94
7.61M
                    while (run - i > width && rows_to_go > 0) {
95
7.60M
                        memset(dst, p, width);
96
7.60M
                        dst -= stride;
97
7.60M
                        rows_to_go--;
98
7.60M
                        i += width;
99
7.60M
                    }
100
2.30k
                    if(rows_to_go <= 0)
101
411
                        break;
102
2.30k
                }
103
4.74k
            }
104
15.6k
        } else {
105
15.6k
            if (bytestream2_get_bytes_left(&qctx->buffer) < copy)
106
1.05k
                copy = bytestream2_get_bytes_left(&qctx->buffer);
107
82.3k
            while (copy > 0) {
108
66.8k
                int step = FFMIN(copy, width - filled);
109
66.8k
                bytestream2_get_bufferu(&qctx->buffer, dst + filled, step);
110
66.8k
                filled += step;
111
66.8k
                copy -= step;
112
66.8k
                if (filled >= width) {
113
52.4k
                    filled = 0;
114
52.4k
                    dst -= stride;
115
52.4k
                    rows_to_go--;
116
52.4k
                    if(rows_to_go <= 0)
117
223
                        break;
118
52.4k
                }
119
66.8k
            }
120
15.6k
        }
121
18.5k
    }
122
9.91k
}
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
14.7k
{
135
14.7k
    int i, j;
136
14.7k
    int code;
137
14.7k
    int filled = 0;
138
14.7k
    int orig_height;
139
140
14.7k
    if (refdata) {
141
        /* copy prev frame */
142
273M
        for (i = 0; i < height; i++)
143
273M
            memcpy(dst + (i * stride), refdata + (i * stride), width);
144
8.04k
    } else {
145
8.04k
        refdata = dst;
146
8.04k
    }
147
148
14.7k
    orig_height = height;
149
14.7k
    height--;
150
14.7k
    dst = dst + height * stride;
151
152
1.39M
    while ((bytestream2_get_bytes_left(&qctx->buffer) > 0) && (height >= 0)) {
153
1.38M
        code = bytestream2_get_byte(&qctx->buffer);
154
155
1.38M
        if(delta) {
156
            /* motion compensation */
157
831k
            while(bytestream2_get_bytes_left(&qctx->buffer) > 0 && (code & 0xF0) == 0xF0) {
158
88.0k
                if(delta == 1) {
159
62.5k
                    int me_idx;
160
62.5k
                    int me_w, me_h, me_x, me_y;
161
62.5k
                    uint8_t *me_plane;
162
62.5k
                    int corr, val;
163
164
                    /* get block size by index */
165
62.5k
                    me_idx = code & 0xF;
166
62.5k
                    me_w = qpeg_table_w[me_idx];
167
62.5k
                    me_h = qpeg_table_h[me_idx];
168
169
                    /* extract motion vector */
170
62.5k
                    corr = bytestream2_get_byte(&qctx->buffer);
171
172
62.5k
                    val = corr >> 4;
173
62.5k
                    if(val > 7)
174
53.4k
                        val -= 16;
175
62.5k
                    me_x = val;
176
177
62.5k
                    val = corr & 0xF;
178
62.5k
                    if(val > 7)
179
49.3k
                        val -= 16;
180
62.5k
                    me_y = val;
181
182
                    /* check motion vector */
183
62.5k
                    if ((me_x + filled < 0) || (me_x + me_w + filled > width) ||
184
57.5k
                       (height - me_y - me_h < 0) || (height - me_y >= orig_height) ||
185
34.6k
                       (filled + me_w > width) || (height - me_h < 0))
186
28.9k
                        av_log(qctx->avctx, AV_LOG_ERROR, "Bogus motion vector (%i,%i), block size %ix%i at %i,%i\n",
187
28.9k
                               me_x, me_y, me_w, me_h, filled, height);
188
33.6k
                    else {
189
                        /* do motion compensation */
190
33.6k
                        me_plane = refdata + (filled + me_x) + (height - me_y) * stride;
191
268k
                        for(j = 0; j < me_h; j++) {
192
3.07M
                            for(i = 0; i < me_w; i++)
193
2.84M
                                dst[filled + i - (j * stride)] = me_plane[i - (j * stride)];
194
234k
                        }
195
33.6k
                    }
196
62.5k
                }
197
88.0k
                code = bytestream2_get_byte(&qctx->buffer);
198
88.0k
            }
199
743k
        }
200
201
1.38M
        if(code == 0xE0) /* end-of-picture code */
202
245
            break;
203
1.38M
        if(code > 0xE0) { /* run code: 0xE1..0xFF */
204
54.6k
            int p;
205
206
54.6k
            code &= 0x1F;
207
54.6k
            p = bytestream2_get_byte(&qctx->buffer);
208
1.39M
            for(i = 0; i <= code; i++) {
209
1.34M
                dst[filled++] = p;
210
1.34M
                if(filled >= width) {
211
66.9k
                    filled = 0;
212
66.9k
                    dst -= stride;
213
66.9k
                    height--;
214
66.9k
                    if (height < 0)
215
1.59k
                        break;
216
66.9k
                }
217
1.34M
            }
218
1.32M
        } else if(code >= 0xC0) { /* copy code: 0xC0..0xDF */
219
16.8k
            code &= 0x1F;
220
221
16.8k
            if(code + 1 > bytestream2_get_bytes_left(&qctx->buffer))
222
290
                break;
223
224
222k
            for(i = 0; i <= code; i++) {
225
205k
                dst[filled++] = bytestream2_get_byte(&qctx->buffer);
226
205k
                if(filled >= width) {
227
6.10k
                    filled = 0;
228
6.10k
                    dst -= stride;
229
6.10k
                    height--;
230
6.10k
                    if (height < 0)
231
201
                        break;
232
6.10k
                }
233
205k
            }
234
1.30M
        } else if(code >= 0x80) { /* skip code: 0x80..0xBF */
235
143k
            int skip;
236
237
143k
            code &= 0x3F;
238
            /* codes 0x80 and 0x81 are actually escape codes,
239
               skip value minus constant is in the next byte */
240
143k
            if(!code)
241
68.3k
                skip = bytestream2_get_byte(&qctx->buffer) +  64;
242
75.0k
            else if(code == 1)
243
13.6k
                skip = bytestream2_get_byte(&qctx->buffer) + 320;
244
61.3k
            else
245
61.3k
                skip = code;
246
143k
            filled += skip;
247
523k
            while( filled >= width) {
248
380k
                filled -= width;
249
380k
                dst -= stride;
250
380k
                height--;
251
380k
                if(height < 0)
252
315
                    break;
253
380k
            }
254
1.16M
        } else {
255
            /* zero code treated as one-pixel skip */
256
1.16M
            if(code) {
257
217k
                dst[filled++] = ctable[code & 0x7F];
258
217k
            }
259
948k
            else
260
948k
                filled++;
261
1.16M
            if(filled >= width) {
262
38.0k
                filled = 0;
263
38.0k
                dst -= stride;
264
38.0k
                height--;
265
38.0k
            }
266
1.16M
        }
267
1.38M
    }
268
14.7k
}
269
270
static int decode_frame(AVCodecContext *avctx, AVFrame *p,
271
                        int *got_frame, AVPacket *avpkt)
272
37.5k
{
273
37.5k
    uint8_t ctable[128];
274
37.5k
    QpegContext * const a = avctx->priv_data;
275
37.5k
    AVFrame * const ref = a->ref;
276
37.5k
    uint8_t* outdata;
277
37.5k
    int delta, intra, ret;
278
279
37.5k
    if (avpkt->size < 0x86) {
280
10.2k
        av_log(avctx, AV_LOG_ERROR, "Packet is too small\n");
281
10.2k
        return AVERROR_INVALIDDATA;
282
10.2k
    }
283
284
27.2k
    bytestream2_init(&a->buffer, avpkt->data, avpkt->size);
285
286
27.2k
    if ((ret = ff_get_buffer(avctx, p, AV_GET_BUFFER_FLAG_REF)) < 0)
287
2.63k
        return ret;
288
24.6k
    outdata = p->data[0];
289
24.6k
    bytestream2_skip(&a->buffer, 4);
290
24.6k
    bytestream2_get_buffer(&a->buffer, ctable, 128);
291
24.6k
    bytestream2_skip(&a->buffer, 1);
292
293
24.6k
    delta = bytestream2_get_byte(&a->buffer);
294
24.6k
    intra = delta == 0x10;
295
24.6k
    if (intra) {
296
9.91k
        qpeg_decode_intra(a, outdata, p->linesize[0], avctx->width, avctx->height);
297
14.7k
    } else {
298
14.7k
        qpeg_decode_inter(a, outdata, p->linesize[0], avctx->width, avctx->height, delta, ctable, ref->data[0]);
299
14.7k
    }
300
301
    /* make the palette available on the way out */
302
24.6k
    ff_copy_palette(a->pal, avpkt, avctx);
303
24.6k
    memcpy(p->data[1], a->pal, AVPALETTE_SIZE);
304
305
24.6k
    if ((ret = av_frame_replace(ref, p)) < 0)
306
0
        return ret;
307
308
24.6k
    if (intra)
309
9.91k
        p->flags |= AV_FRAME_FLAG_KEY;
310
14.7k
    else
311
14.7k
        p->flags &= ~AV_FRAME_FLAG_KEY;
312
24.6k
    p->pict_type = intra ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
313
314
24.6k
    *got_frame      = 1;
315
316
24.6k
    return avpkt->size;
317
24.6k
}
318
319
static av_cold void decode_flush(AVCodecContext *avctx)
320
18.3k
{
321
18.3k
    QpegContext * const a = avctx->priv_data;
322
18.3k
    int i, pal_size;
323
18.3k
    const uint8_t *pal_src;
324
325
18.3k
    av_frame_unref(a->ref);
326
327
18.3k
    pal_size = FFMIN(1024U, avctx->extradata_size);
328
18.3k
    pal_src = avctx->extradata + avctx->extradata_size - pal_size;
329
330
340k
    for (i=0; i<pal_size/4; i++)
331
321k
        a->pal[i] = 0xFFU<<24 | AV_RL32(pal_src+4*i);
332
18.3k
}
333
334
static av_cold int decode_end(AVCodecContext *avctx)
335
1.01k
{
336
1.01k
    QpegContext * const a = avctx->priv_data;
337
338
1.01k
    av_frame_free(&a->ref);
339
340
1.01k
    return 0;
341
1.01k
}
342
343
1.01k
static av_cold int decode_init(AVCodecContext *avctx){
344
1.01k
    QpegContext * const a = avctx->priv_data;
345
346
1.01k
    a->avctx = avctx;
347
1.01k
    avctx->pix_fmt= AV_PIX_FMT_PAL8;
348
349
1.01k
    a->ref = av_frame_alloc();
350
1.01k
    if (!a->ref)
351
0
        return AVERROR(ENOMEM);
352
353
1.01k
    decode_flush(avctx);
354
355
1.01k
    return 0;
356
1.01k
}
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
};