GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavcodec/qpeg.c Lines: 165 192 85.9 %
Date: 2020-08-14 10:39:37 Branches: 96 126 76.2 %

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

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

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

731786
    while ((bytestream2_get_bytes_left(&qctx->buffer) > 0) && (height >= 0)) {
147
731779
        code = bytestream2_get_byte(&qctx->buffer);
148
149
731779
        if(delta) {
150
            /* motion compensation */
151

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

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

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

19407
                       (filled + me_w > width) || (height - me_h < 0))
180
                        av_log(qctx->avctx, AV_LOG_ERROR, "Bogus motion vector (%i,%i), block size %ix%i at %i,%i\n",
181
                               me_x, me_y, me_w, me_h, filled, height);
182
                    else {
183
                        /* do motion compensation */
184
19407
                        me_plane = refdata + (filled + me_x) + (height - me_y) * stride;
185
177719
                        for(j = 0; j < me_h; j++) {
186
1454952
                            for(i = 0; i < me_w; i++)
187
1296640
                                dst[filled + i - (j * stride)] = me_plane[i - (j * stride)];
188
                        }
189
                    }
190
                }
191
19407
                code = bytestream2_get_byte(&qctx->buffer);
192
            }
193
        }
194
195
731779
        if(code == 0xE0) /* end-of-picture code */
196
92
            break;
197
731687
        if(code > 0xE0) { /* run code: 0xE1..0xFF */
198
            int p;
199
200
96361
            code &= 0x1F;
201
96361
            p = bytestream2_get_byte(&qctx->buffer);
202
359528
            for(i = 0; i <= code; i++) {
203
263167
                dst[filled++] = p;
204
263167
                if(filled >= width) {
205
72
                    filled = 0;
206
72
                    dst -= stride;
207
72
                    height--;
208
72
                    if (height < 0)
209
                        break;
210
                }
211
            }
212
635326
        } else if(code >= 0xC0) { /* copy code: 0xC0..0xDF */
213
214471
            code &= 0x1F;
214
215
214471
            if(code + 1 > bytestream2_get_bytes_left(&qctx->buffer))
216
                break;
217
218
957914
            for(i = 0; i <= code; i++) {
219
743443
                dst[filled++] = bytestream2_get_byte(&qctx->buffer);
220
743443
                if(filled >= width) {
221
16
                    filled = 0;
222
16
                    dst -= stride;
223
16
                    height--;
224
16
                    if (height < 0)
225
                        break;
226
                }
227
            }
228
420855
        } else if(code >= 0x80) { /* skip code: 0x80..0xBF */
229
            int skip;
230
231
249130
            code &= 0x3F;
232
            /* codes 0x80 and 0x81 are actually escape codes,
233
               skip value minus constant is in the next byte */
234
249130
            if(!code)
235
29191
                skip = bytestream2_get_byte(&qctx->buffer) +  64;
236
219939
            else if(code == 1)
237
273
                skip = bytestream2_get_byte(&qctx->buffer) + 320;
238
            else
239
219666
                skip = code;
240
249130
            filled += skip;
241
272528
            while( filled >= width) {
242
23398
                filled -= width;
243
23398
                dst -= stride;
244
23398
                height--;
245
23398
                if(height < 0)
246
                    break;
247
            }
248
        } else {
249
            /* zero code treated as one-pixel skip */
250
171725
            if(code) {
251
124870
                dst[filled++] = ctable[code & 0x7F];
252
            }
253
            else
254
46855
                filled++;
255
171725
            if(filled >= width) {
256
182
                filled = 0;
257
182
                dst -= stride;
258
182
                height--;
259
            }
260
        }
261
    }
262
99
}
263
264
100
static int decode_frame(AVCodecContext *avctx,
265
                        void *data, int *got_frame,
266
                        AVPacket *avpkt)
267
{
268
    uint8_t ctable[128];
269
100
    QpegContext * const a = avctx->priv_data;
270
100
    AVFrame * const p = data;
271
100
    AVFrame * const ref = a->ref;
272
    uint8_t* outdata;
273
    int delta, intra, ret;
274
    int pal_size;
275
100
    const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, &pal_size);
276
277
100
    if (avpkt->size < 0x86) {
278
        av_log(avctx, AV_LOG_ERROR, "Packet is too small\n");
279
        return AVERROR_INVALIDDATA;
280
    }
281
282
100
    bytestream2_init(&a->buffer, avpkt->data, avpkt->size);
283
284
100
    if ((ret = ff_get_buffer(avctx, p, AV_GET_BUFFER_FLAG_REF)) < 0)
285
        return ret;
286
100
    outdata = p->data[0];
287
100
    bytestream2_skip(&a->buffer, 4);
288
100
    bytestream2_get_buffer(&a->buffer, ctable, 128);
289
100
    bytestream2_skip(&a->buffer, 1);
290
291
100
    delta = bytestream2_get_byte(&a->buffer);
292
100
    intra = delta == 0x10;
293
100
    if (intra) {
294
1
        qpeg_decode_intra(a, outdata, p->linesize[0], avctx->width, avctx->height);
295
    } else {
296
99
        qpeg_decode_inter(a, outdata, p->linesize[0], avctx->width, avctx->height, delta, ctable, ref->data[0]);
297
    }
298
299
    /* make the palette available on the way out */
300

100
    if (pal && pal_size == AVPALETTE_SIZE) {
301
1
        p->palette_has_changed = 1;
302
1
        memcpy(a->pal, pal, AVPALETTE_SIZE);
303
99
    } else if (pal) {
304
        av_log(avctx, AV_LOG_ERROR, "Palette size %d is wrong\n", pal_size);
305
    }
306
100
    memcpy(p->data[1], a->pal, AVPALETTE_SIZE);
307
308
100
    av_frame_unref(ref);
309
100
    if ((ret = av_frame_ref(ref, p)) < 0)
310
        return ret;
311
312
100
    p->key_frame = intra;
313
100
    p->pict_type = intra ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
314
315
100
    *got_frame      = 1;
316
317
100
    return avpkt->size;
318
}
319
320
2
static void decode_flush(AVCodecContext *avctx){
321
2
    QpegContext * const a = avctx->priv_data;
322
    int i, pal_size;
323
    const uint8_t *pal_src;
324
325
2
    av_frame_unref(a->ref);
326
327
2
    pal_size = FFMIN(1024U, avctx->extradata_size);
328
2
    pal_src = avctx->extradata + avctx->extradata_size - pal_size;
329
330
514
    for (i=0; i<pal_size/4; i++)
331
512
        a->pal[i] = 0xFFU<<24 | AV_RL32(pal_src+4*i);
332
2
}
333
334
2
static av_cold int decode_end(AVCodecContext *avctx)
335
{
336
2
    QpegContext * const a = avctx->priv_data;
337
338
2
    av_frame_free(&a->ref);
339
340
2
    return 0;
341
}
342
343
2
static av_cold int decode_init(AVCodecContext *avctx){
344
2
    QpegContext * const a = avctx->priv_data;
345
346
2
    a->avctx = avctx;
347
2
    avctx->pix_fmt= AV_PIX_FMT_PAL8;
348
349
2
    a->ref = av_frame_alloc();
350
2
    if (!a->ref)
351
        return AVERROR(ENOMEM);
352
353
2
    decode_flush(avctx);
354
355
2
    return 0;
356
}
357
358
AVCodec ff_qpeg_decoder = {
359
    .name           = "qpeg",
360
    .long_name      = NULL_IF_CONFIG_SMALL("Q-team QPEG"),
361
    .type           = AVMEDIA_TYPE_VIDEO,
362
    .id             = AV_CODEC_ID_QPEG,
363
    .priv_data_size = sizeof(QpegContext),
364
    .init           = decode_init,
365
    .close          = decode_end,
366
    .decode         = decode_frame,
367
    .flush          = decode_flush,
368
    .capabilities   = AV_CODEC_CAP_DR1,
369
    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE |
370
                      FF_CODEC_CAP_INIT_CLEANUP,
371
};