GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavcodec/qpeg.c Lines: 164 190 86.3 %
Date: 2021-04-22 14:24:15 Branches: 92 120 76.7 %

Line Branch Exec 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 "decode.h"
30
#include "internal.h"
31
32
typedef struct QpegContext{
33
    AVCodecContext *avctx;
34
    AVFrame *ref;
35
    uint32_t pal[256];
36
    GetByteContext buffer;
37
} QpegContext;
38
39
1
static void qpeg_decode_intra(QpegContext *qctx, uint8_t *dst,
40
                              int stride, int width, int height)
41
{
42
    int i;
43
    int code;
44
    int c0, c1;
45
    int run, copy;
46
1
    int filled = 0;
47
    int rows_to_go;
48
49
1
    rows_to_go = height;
50
1
    height--;
51
1
    dst = dst + height * stride;
52
53

10407
    while ((bytestream2_get_bytes_left(&qctx->buffer) > 0) && (rows_to_go > 0)) {
54
10406
        code = bytestream2_get_byte(&qctx->buffer);
55
10406
        run = copy = 0;
56
10406
        if(code == 0xFC) /* end-of-picture code */
57
            break;
58
10406
        if(code >= 0xF8) { /* very long run */
59
            c0 = bytestream2_get_byte(&qctx->buffer);
60
            c1 = bytestream2_get_byte(&qctx->buffer);
61
            run = ((code & 0x7) << 16) + (c0 << 8) + c1 + 2;
62
10406
        } else if (code >= 0xF0) { /* long run */
63
21
            c0 = bytestream2_get_byte(&qctx->buffer);
64
21
            run = ((code & 0xF) << 8) + c0 + 2;
65
10385
        } else if (code >= 0xE0) { /* short run */
66
5687
            run = (code & 0x1F) + 2;
67
4698
        } else if (code >= 0xC0) { /* very long copy */
68
            c0 = bytestream2_get_byte(&qctx->buffer);
69
            c1 = bytestream2_get_byte(&qctx->buffer);
70
            copy = ((code & 0x3F) << 16) + (c0 << 8) + c1 + 1;
71
4698
        } else if (code >= 0x80) { /* long copy */
72
            c0 = bytestream2_get_byte(&qctx->buffer);
73
            copy = ((code & 0x7F) << 8) + c0 + 1;
74
        } else { /* short copy */
75
4698
            copy = code + 1;
76
        }
77
78
        /* perform actual run or copy */
79
10406
        if(run) {
80
            int p;
81
82
5708
            p = bytestream2_get_byte(&qctx->buffer);
83
11416
            for(i = 0; i < run; i++) {
84
5708
                int step = FFMIN(run - i, width - filled);
85
5708
                memset(dst+filled, p, step);
86
5708
                filled += step;
87
5708
                i      += step - 1;
88
5708
                if (filled >= width) {
89
30
                    filled = 0;
90
30
                    dst -= stride;
91
30
                    rows_to_go--;
92

30
                    while (run - i > width && rows_to_go > 0) {
93
                        memset(dst, p, width);
94
                        dst -= stride;
95
                        rows_to_go--;
96
                        i += width;
97
                    }
98
30
                    if(rows_to_go <= 0)
99
                        break;
100
                }
101
            }
102
        } else {
103
4698
            if (bytestream2_get_bytes_left(&qctx->buffer) < copy)
104
                copy = bytestream2_get_bytes_left(&qctx->buffer);
105
9588
            while (copy > 0) {
106
4891
                int step = FFMIN(copy, width - filled);
107
4891
                bytestream2_get_bufferu(&qctx->buffer, dst + filled, step);
108
4891
                filled += step;
109
4891
                copy -= step;
110
4891
                if (filled >= width) {
111
210
                    filled = 0;
112
210
                    dst -= stride;
113
210
                    rows_to_go--;
114
210
                    if(rows_to_go <= 0)
115
1
                        break;
116
                }
117
            }
118
        }
119
    }
120
1
}
121
122
static const uint8_t qpeg_table_h[16] =
123
 { 0x00, 0x20, 0x20, 0x20, 0x18, 0x10, 0x10, 0x20, 0x10, 0x08, 0x18, 0x08, 0x08, 0x18, 0x10, 0x04};
124
static const uint8_t qpeg_table_w[16] =
125
 { 0x00, 0x20, 0x18, 0x08, 0x18, 0x10, 0x20, 0x10, 0x08, 0x10, 0x20, 0x20, 0x08, 0x10, 0x18, 0x04};
126
127
/* Decodes delta frames */
128
99
static void av_noinline qpeg_decode_inter(QpegContext *qctx, uint8_t *dst,
129
                              int stride, int width, int height,
130
                              int delta, const uint8_t *ctable,
131
                              uint8_t *refdata)
132
{
133
    int i, j;
134
    int code;
135
99
    int filled = 0;
136
    int orig_height;
137
138
99
    if (refdata) {
139
        /* copy prev frame */
140
23859
        for (i = 0; i < height; i++)
141
23760
            memcpy(dst + (i * stride), refdata + (i * stride), width);
142
    } else {
143
        refdata = dst;
144
    }
145
146
99
    orig_height = height;
147
99
    height--;
148
99
    dst = dst + height * stride;
149
150

731786
    while ((bytestream2_get_bytes_left(&qctx->buffer) > 0) && (height >= 0)) {
151
731779
        code = bytestream2_get_byte(&qctx->buffer);
152
153
731779
        if(delta) {
154
            /* motion compensation */
155

751186
            while(bytestream2_get_bytes_left(&qctx->buffer) > 0 && (code & 0xF0) == 0xF0) {
156
19407
                if(delta == 1) {
157
                    int me_idx;
158
                    int me_w, me_h, me_x, me_y;
159
                    uint8_t *me_plane;
160
                    int corr, val;
161
162
                    /* get block size by index */
163
19407
                    me_idx = code & 0xF;
164
19407
                    me_w = qpeg_table_w[me_idx];
165
19407
                    me_h = qpeg_table_h[me_idx];
166
167
                    /* extract motion vector */
168
19407
                    corr = bytestream2_get_byte(&qctx->buffer);
169
170
19407
                    val = corr >> 4;
171
19407
                    if(val > 7)
172
8637
                        val -= 16;
173
19407
                    me_x = val;
174
175
19407
                    val = corr & 0xF;
176
19407
                    if(val > 7)
177
9623
                        val -= 16;
178
19407
                    me_y = val;
179
180
                    /* check motion vector */
181

19407
                    if ((me_x + filled < 0) || (me_x + me_w + filled > width) ||
182

19407
                       (height - me_y - me_h < 0) || (height - me_y >= orig_height) ||
183

19407
                       (filled + me_w > width) || (height - me_h < 0))
184
                        av_log(qctx->avctx, AV_LOG_ERROR, "Bogus motion vector (%i,%i), block size %ix%i at %i,%i\n",
185
                               me_x, me_y, me_w, me_h, filled, height);
186
                    else {
187
                        /* do motion compensation */
188
19407
                        me_plane = refdata + (filled + me_x) + (height - me_y) * stride;
189
177719
                        for(j = 0; j < me_h; j++) {
190
1454952
                            for(i = 0; i < me_w; i++)
191
1296640
                                dst[filled + i - (j * stride)] = me_plane[i - (j * stride)];
192
                        }
193
                    }
194
                }
195
19407
                code = bytestream2_get_byte(&qctx->buffer);
196
            }
197
        }
198
199
731779
        if(code == 0xE0) /* end-of-picture code */
200
92
            break;
201
731687
        if(code > 0xE0) { /* run code: 0xE1..0xFF */
202
            int p;
203
204
96361
            code &= 0x1F;
205
96361
            p = bytestream2_get_byte(&qctx->buffer);
206
359528
            for(i = 0; i <= code; i++) {
207
263167
                dst[filled++] = p;
208
263167
                if(filled >= width) {
209
72
                    filled = 0;
210
72
                    dst -= stride;
211
72
                    height--;
212
72
                    if (height < 0)
213
                        break;
214
                }
215
            }
216
635326
        } else if(code >= 0xC0) { /* copy code: 0xC0..0xDF */
217
214471
            code &= 0x1F;
218
219
214471
            if(code + 1 > bytestream2_get_bytes_left(&qctx->buffer))
220
                break;
221
222
957914
            for(i = 0; i <= code; i++) {
223
743443
                dst[filled++] = bytestream2_get_byte(&qctx->buffer);
224
743443
                if(filled >= width) {
225
16
                    filled = 0;
226
16
                    dst -= stride;
227
16
                    height--;
228
16
                    if (height < 0)
229
                        break;
230
                }
231
            }
232
420855
        } else if(code >= 0x80) { /* skip code: 0x80..0xBF */
233
            int skip;
234
235
249130
            code &= 0x3F;
236
            /* codes 0x80 and 0x81 are actually escape codes,
237
               skip value minus constant is in the next byte */
238
249130
            if(!code)
239
29191
                skip = bytestream2_get_byte(&qctx->buffer) +  64;
240
219939
            else if(code == 1)
241
273
                skip = bytestream2_get_byte(&qctx->buffer) + 320;
242
            else
243
219666
                skip = code;
244
249130
            filled += skip;
245
272528
            while( filled >= width) {
246
23398
                filled -= width;
247
23398
                dst -= stride;
248
23398
                height--;
249
23398
                if(height < 0)
250
                    break;
251
            }
252
        } else {
253
            /* zero code treated as one-pixel skip */
254
171725
            if(code) {
255
124870
                dst[filled++] = ctable[code & 0x7F];
256
            }
257
            else
258
46855
                filled++;
259
171725
            if(filled >= width) {
260
182
                filled = 0;
261
182
                dst -= stride;
262
182
                height--;
263
            }
264
        }
265
    }
266
99
}
267
268
100
static int decode_frame(AVCodecContext *avctx,
269
                        void *data, int *got_frame,
270
                        AVPacket *avpkt)
271
{
272
    uint8_t ctable[128];
273
100
    QpegContext * const a = avctx->priv_data;
274
100
    AVFrame * const p = data;
275
100
    AVFrame * const ref = a->ref;
276
    uint8_t* outdata;
277
    int delta, intra, ret;
278
279
100
    if (avpkt->size < 0x86) {
280
        av_log(avctx, AV_LOG_ERROR, "Packet is too small\n");
281
        return AVERROR_INVALIDDATA;
282
    }
283
284
100
    bytestream2_init(&a->buffer, avpkt->data, avpkt->size);
285
286
100
    if ((ret = ff_get_buffer(avctx, p, AV_GET_BUFFER_FLAG_REF)) < 0)
287
        return ret;
288
100
    outdata = p->data[0];
289
100
    bytestream2_skip(&a->buffer, 4);
290
100
    bytestream2_get_buffer(&a->buffer, ctable, 128);
291
100
    bytestream2_skip(&a->buffer, 1);
292
293
100
    delta = bytestream2_get_byte(&a->buffer);
294
100
    intra = delta == 0x10;
295
100
    if (intra) {
296
1
        qpeg_decode_intra(a, outdata, p->linesize[0], avctx->width, avctx->height);
297
    } else {
298
99
        qpeg_decode_inter(a, outdata, p->linesize[0], avctx->width, avctx->height, delta, ctable, ref->data[0]);
299
    }
300
301
    /* make the palette available on the way out */
302
100
    p->palette_has_changed = ff_copy_palette(a->pal, avpkt, avctx);
303
100
    memcpy(p->data[1], a->pal, AVPALETTE_SIZE);
304
305
100
    av_frame_unref(ref);
306
100
    if ((ret = av_frame_ref(ref, p)) < 0)
307
        return ret;
308
309
100
    p->key_frame = intra;
310
100
    p->pict_type = intra ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
311
312
100
    *got_frame      = 1;
313
314
100
    return avpkt->size;
315
}
316
317
2
static void decode_flush(AVCodecContext *avctx){
318
2
    QpegContext * const a = avctx->priv_data;
319
    int i, pal_size;
320
    const uint8_t *pal_src;
321
322
2
    av_frame_unref(a->ref);
323
324
2
    pal_size = FFMIN(1024U, avctx->extradata_size);
325
2
    pal_src = avctx->extradata + avctx->extradata_size - pal_size;
326
327
514
    for (i=0; i<pal_size/4; i++)
328
512
        a->pal[i] = 0xFFU<<24 | AV_RL32(pal_src+4*i);
329
2
}
330
331
2
static av_cold int decode_end(AVCodecContext *avctx)
332
{
333
2
    QpegContext * const a = avctx->priv_data;
334
335
2
    av_frame_free(&a->ref);
336
337
2
    return 0;
338
}
339
340
2
static av_cold int decode_init(AVCodecContext *avctx){
341
2
    QpegContext * const a = avctx->priv_data;
342
343
2
    a->avctx = avctx;
344
2
    avctx->pix_fmt= AV_PIX_FMT_PAL8;
345
346
2
    a->ref = av_frame_alloc();
347
2
    if (!a->ref)
348
        return AVERROR(ENOMEM);
349
350
2
    decode_flush(avctx);
351
352
2
    return 0;
353
}
354
355
AVCodec ff_qpeg_decoder = {
356
    .name           = "qpeg",
357
    .long_name      = NULL_IF_CONFIG_SMALL("Q-team QPEG"),
358
    .type           = AVMEDIA_TYPE_VIDEO,
359
    .id             = AV_CODEC_ID_QPEG,
360
    .priv_data_size = sizeof(QpegContext),
361
    .init           = decode_init,
362
    .close          = decode_end,
363
    .decode         = decode_frame,
364
    .flush          = decode_flush,
365
    .capabilities   = AV_CODEC_CAP_DR1,
366
    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE |
367
                      FF_CODEC_CAP_INIT_CLEANUP,
368
};