Coverage Report

Created: 2026-05-23 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/eatgq.c
Line
Count
Source
1
/*
2
 * Electronic Arts TGQ Video Decoder
3
 * Copyright (c) 2007-2008 Peter Ross <pross@xvid.org>
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 St, Fifth Floor, Boston, MA  02110-1301  USA
20
 */
21
22
/**
23
 * @file
24
 * Electronic Arts TGQ Video Decoder
25
 * @author Peter Ross <pross@xvid.org>
26
 *
27
 * Technical details here:
28
 * http://wiki.multimedia.cx/index.php?title=Electronic_Arts_TGQ
29
 */
30
31
#include "libavutil/attributes.h"
32
#define BITSTREAM_READER_LE
33
34
#include "libavutil/mem_internal.h"
35
36
#include "aandcttab.h"
37
#include "avcodec.h"
38
#include "bytestream.h"
39
#include "codec_internal.h"
40
#include "copy_block.h"
41
#include "decode.h"
42
#include "eaidct.h"
43
#include "get_bits.h"
44
45
typedef struct TgqContext {
46
    AVCodecContext *avctx;
47
    AVFrame *last_frame;
48
    int width, height;
49
    int qtable[64];
50
    DECLARE_ALIGNED(16, int16_t, block)[6][64];
51
} TgqContext;
52
53
static av_cold int tgq_decode_init(AVCodecContext *avctx)
54
1.75k
{
55
1.75k
    TgqContext *s = avctx->priv_data;
56
1.75k
    s->avctx = avctx;
57
1.75k
    avctx->framerate = (AVRational){ 15, 1 };
58
1.75k
    avctx->pix_fmt   = AV_PIX_FMT_YUV420P;
59
1.75k
    s->last_frame = av_frame_alloc();
60
1.75k
    if (!s->last_frame)
61
0
        return AVERROR(ENOMEM);
62
1.75k
    return 0;
63
1.75k
}
64
65
static int tgq_decode_block(TgqContext *s, int16_t block[64], GetBitContext *gb)
66
567k
{
67
567k
    const uint8_t *scantable = ff_zigzag_direct;
68
567k
    int i, j, value;
69
567k
    block[0] = get_sbits(gb, 8) * s->qtable[0];
70
36.1M
    for (i = 1; i < 64;) {
71
35.6M
        switch (show_bits(gb, 3)) {
72
7.14k
        case 4:
73
7.14k
            if (i >= 63)
74
232
                return AVERROR_INVALIDDATA;
75
6.91k
            block[scantable[i++]] = 0;
76
6.91k
            av_fallthrough;
77
35.4M
        case 0:
78
35.4M
            block[scantable[i++]] = 0;
79
35.4M
            skip_bits(gb, 3);
80
35.4M
            break;
81
4.37k
        case 5:
82
14.6k
        case 1:
83
14.6k
            skip_bits(gb, 2);
84
14.6k
            value = get_bits(gb, 6);
85
14.6k
            if (value > 64 - i)
86
1.01k
                return AVERROR_INVALIDDATA;
87
136k
            for (j = 0; j < value; j++)
88
122k
                block[scantable[i++]] = 0;
89
13.6k
            break;
90
6.86k
        case 6:
91
6.86k
            skip_bits(gb, 3);
92
6.86k
            block[scantable[i]] = -s->qtable[scantable[i]];
93
6.86k
            i++;
94
6.86k
            break;
95
5.80k
        case 2:
96
5.80k
            skip_bits(gb, 3);
97
5.80k
            block[scantable[i]] = s->qtable[scantable[i]];
98
5.80k
            i++;
99
5.80k
            break;
100
126k
        case 7: // 111b
101
161k
        case 3: // 011b
102
161k
            skip_bits(gb, 2);
103
161k
            if (show_bits(gb, 6) == 0x3F) {
104
31.8k
                skip_bits(gb, 6);
105
31.8k
                block[scantable[i]] = get_sbits(gb, 8) * s->qtable[scantable[i]];
106
130k
            } else {
107
130k
                block[scantable[i]] = get_sbits(gb, 6) * s->qtable[scantable[i]];
108
130k
            }
109
161k
            i++;
110
161k
            break;
111
35.6M
        }
112
35.6M
    }
113
566k
    block[0] += 128 << 4;
114
566k
    return 0;
115
567k
}
116
117
static void tgq_idct_put_mb(TgqContext *s, int16_t (*block)[64], AVFrame *frame,
118
                            int mb_x, int mb_y)
119
94.3k
{
120
94.3k
    ptrdiff_t linesize = frame->linesize[0];
121
94.3k
    uint8_t *dest_y  = frame->data[0] + (mb_y * 16 * linesize)           + mb_x * 16;
122
94.3k
    uint8_t *dest_cb = frame->data[1] + (mb_y * 8  * frame->linesize[1]) + mb_x * 8;
123
94.3k
    uint8_t *dest_cr = frame->data[2] + (mb_y * 8  * frame->linesize[2]) + mb_x * 8;
124
125
94.3k
    ff_ea_idct_put_c(dest_y                   , linesize, block[0]);
126
94.3k
    ff_ea_idct_put_c(dest_y                + 8, linesize, block[1]);
127
94.3k
    ff_ea_idct_put_c(dest_y + 8 * linesize    , linesize, block[2]);
128
94.3k
    ff_ea_idct_put_c(dest_y + 8 * linesize + 8, linesize, block[3]);
129
94.3k
    if (!(s->avctx->flags & AV_CODEC_FLAG_GRAY)) {
130
94.3k
         ff_ea_idct_put_c(dest_cb, frame->linesize[1], block[4]);
131
94.3k
         ff_ea_idct_put_c(dest_cr, frame->linesize[2], block[5]);
132
94.3k
    }
133
94.3k
}
134
135
static inline void tgq_dconly(TgqContext *s, unsigned char *dst,
136
                              ptrdiff_t dst_stride, int dc)
137
67.6k
{
138
67.6k
    int level = av_clip_uint8((dc*s->qtable[0] + 2056) >> 4);
139
67.6k
    int j;
140
608k
    for (j = 0; j < 8; j++)
141
541k
        memset(dst + j * dst_stride, level, 8);
142
67.6k
}
143
144
static void tgq_idct_put_mb_dconly(TgqContext *s, AVFrame *frame,
145
                                   int mb_x, int mb_y, const int8_t *dc)
146
11.2k
{
147
11.2k
    ptrdiff_t linesize = frame->linesize[0];
148
11.2k
    uint8_t *dest_y  = frame->data[0] + (mb_y * 16 * linesize)             + mb_x * 16;
149
11.2k
    uint8_t *dest_cb = frame->data[1] + (mb_y * 8  * frame->linesize[1]) + mb_x * 8;
150
11.2k
    uint8_t *dest_cr = frame->data[2] + (mb_y * 8  * frame->linesize[2]) + mb_x * 8;
151
11.2k
    tgq_dconly(s, dest_y,                    linesize, dc[0]);
152
11.2k
    tgq_dconly(s, dest_y                + 8, linesize, dc[1]);
153
11.2k
    tgq_dconly(s, dest_y + 8 * linesize,     linesize, dc[2]);
154
11.2k
    tgq_dconly(s, dest_y + 8 * linesize + 8, linesize, dc[3]);
155
11.2k
    if (!(s->avctx->flags & AV_CODEC_FLAG_GRAY)) {
156
11.2k
        tgq_dconly(s, dest_cb, frame->linesize[1], dc[4]);
157
11.2k
        tgq_dconly(s, dest_cr, frame->linesize[2], dc[5]);
158
11.2k
    }
159
11.2k
}
160
161
static int tgq_decode_mb(TgqContext *s, GetByteContext *gbyte,
162
                         AVFrame *frame, int mb_y, int mb_x)
163
116k
{
164
116k
    int mode;
165
116k
    int i;
166
167
116k
    mode = bytestream2_get_byte(gbyte);
168
116k
    if (mode > 12) {
169
95.5k
        GetBitContext gb;
170
95.5k
        int ret = init_get_bits8(&gb, gbyte->buffer, FFMIN(bytestream2_get_bytes_left(gbyte), mode));
171
95.5k
        if (ret < 0)
172
0
            return ret;
173
174
661k
        for (i = 0; i < 6; i++) {
175
567k
            ret = tgq_decode_block(s, s->block[i], &gb);
176
567k
            if (ret < 0)
177
1.24k
                return ret;
178
567k
        }
179
94.3k
        tgq_idct_put_mb(s, s->block, frame, mb_x, mb_y);
180
94.3k
        bytestream2_skip(gbyte, mode);
181
94.3k
    } else {
182
20.7k
        int8_t dc[6];
183
20.7k
        if (mode == 1) {
184
3.00k
            int x, y;
185
3.00k
            int mv = bytestream2_get_byte(gbyte);
186
3.00k
            int mv_x = mv >> 4;
187
3.00k
            int mv_y = mv & 0x0F;
188
3.00k
            if (!s->last_frame->data[0]) {
189
470
                av_log(s->avctx, AV_LOG_ERROR, "missing reference frame\n");
190
470
                return -1;
191
470
            }
192
2.53k
            if (mv_x >= 8) mv_x -= 16;
193
2.53k
            if (mv_y >= 8) mv_y -= 16;
194
2.53k
            x = mb_x * 16 - mv_x;
195
2.53k
            y = mb_y * 16 - mv_y;
196
2.53k
            if (x < 0 || x + 16 > s->width || y < 0 || y + 16 > s->height) {
197
960
                av_log(s->avctx, AV_LOG_ERROR, "invalid motion vector\n");
198
960
                return -1;
199
960
            }
200
1.57k
            copy_block16(frame->data[0] + (mb_y * 16 * frame->linesize[0]) + mb_x * 16,
201
1.57k
                         s->last_frame->data[0] + y * s->last_frame->linesize[0] + x,
202
1.57k
                         frame->linesize[0], s->last_frame->linesize[0], 16);
203
4.73k
            for (int p = 1; p < 3; p++)
204
3.15k
                copy_block8(frame->data[p] + (mb_y * 8 * frame->linesize[p]) + mb_x * 8,
205
3.15k
                            s->last_frame->data[p] + (y >> 1) * s->last_frame->linesize[p] + (x >> 1),
206
3.15k
                            frame->linesize[p], s->last_frame->linesize[p], 8);
207
1.57k
            frame->flags &= ~AV_FRAME_FLAG_KEY;
208
1.57k
            return 0;
209
17.7k
        } else if (mode == 3) {
210
9.61k
            memset(dc, bytestream2_get_byte(gbyte), 4);
211
9.61k
            dc[4] = bytestream2_get_byte(gbyte);
212
9.61k
            dc[5] = bytestream2_get_byte(gbyte);
213
9.61k
        } else if (mode == 6) {
214
879
            if (bytestream2_get_buffer(gbyte, dc, 6) != 6)
215
214
                return AVERROR_INVALIDDATA;
216
7.26k
        } else if (mode == 12) {
217
6.95k
            for (i = 0; i < 6; i++) {
218
5.95k
                dc[i] = bytestream2_get_byte(gbyte);
219
5.95k
                bytestream2_skip(gbyte, 1);
220
5.95k
            }
221
6.26k
        } else {
222
6.26k
            av_log(s->avctx, AV_LOG_ERROR, "unsupported mb mode %i\n", mode);
223
6.26k
            return -1;
224
6.26k
        }
225
11.2k
        tgq_idct_put_mb_dconly(s, frame, mb_x, mb_y, dc);
226
11.2k
    }
227
105k
    return 0;
228
116k
}
229
230
static void tgq_calculate_qtable(TgqContext *s, int quant)
231
102k
{
232
102k
    int i, j;
233
102k
    const int a = (14 * (100 - quant)) / 100 + 1;
234
102k
    const int b = (11 * (100 - quant)) / 100 + 4;
235
920k
    for (j = 0; j < 8; j++)
236
7.36M
        for (i = 0; i < 8; i++)
237
6.54M
            s->qtable[j * 8 + i] = ((a * (j + i) / (7 + 7) + b) *
238
6.54M
                                    ff_inv_aanscales[j * 8 + i]) >> (14 - 4);
239
102k
}
240
241
static int tgq_decode_frame(AVCodecContext *avctx, AVFrame *frame,
242
                            int *got_frame, AVPacket *avpkt)
243
244k
{
244
244k
    const uint8_t *buf = avpkt->data;
245
244k
    int buf_size       = avpkt->size;
246
244k
    TgqContext *s      = avctx->priv_data;
247
244k
    GetByteContext gbyte;
248
244k
    int x, y, ret;
249
244k
    int big_endian;
250
251
244k
    if (buf_size < 16) {
252
139k
        av_log(avctx, AV_LOG_WARNING, "truncated header\n");
253
139k
        return AVERROR_INVALIDDATA;
254
139k
    }
255
105k
    big_endian = AV_RL32(&buf[4]) > 0x000FFFFF;
256
105k
    bytestream2_init(&gbyte, buf + 8, buf_size - 8);
257
105k
    if (big_endian) {
258
101k
        s->width  = bytestream2_get_be16u(&gbyte);
259
101k
        s->height = bytestream2_get_be16u(&gbyte);
260
101k
    } else {
261
4.31k
        s->width  = bytestream2_get_le16u(&gbyte);
262
4.31k
        s->height = bytestream2_get_le16u(&gbyte);
263
4.31k
    }
264
265
105k
    if (s->avctx->width != s->width || s->avctx->height != s->height) {
266
28.5k
        av_frame_unref(s->last_frame);
267
28.5k
        ret = ff_set_dimensions(s->avctx, s->width, s->height);
268
28.5k
        if (ret < 0)
269
3.11k
            return ret;
270
28.5k
    }
271
272
102k
    tgq_calculate_qtable(s, bytestream2_get_byteu(&gbyte));
273
102k
    bytestream2_skipu(&gbyte, 3);
274
275
102k
    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
276
487
        return ret;
277
278
101k
    frame->flags |= AV_FRAME_FLAG_KEY;
279
196k
    for (y = 0; y < FFALIGN(avctx->height, 16) >> 4; y++)
280
210k
        for (x = 0; x < FFALIGN(avctx->width, 16) >> 4; x++)
281
116k
            if (tgq_decode_mb(s, &gbyte, frame, y, x) < 0)
282
9.15k
                return AVERROR_INVALIDDATA;
283
284
92.6k
    if ((ret = av_frame_replace(s->last_frame, frame)) < 0)
285
0
        return ret;
286
287
92.6k
    *got_frame = 1;
288
289
92.6k
    return avpkt->size;
290
92.6k
}
291
292
static av_cold int tgq_decode_close(AVCodecContext *avctx)
293
1.75k
{
294
1.75k
    TgqContext *s = avctx->priv_data;
295
1.75k
    av_frame_free(&s->last_frame);
296
1.75k
    return 0;
297
1.75k
}
298
299
const FFCodec ff_eatgq_decoder = {
300
    .p.name         = "eatgq",
301
    CODEC_LONG_NAME("Electronic Arts TGQ video"),
302
    .p.type         = AVMEDIA_TYPE_VIDEO,
303
    .p.id           = AV_CODEC_ID_TGQ,
304
    .priv_data_size = sizeof(TgqContext),
305
    .init           = tgq_decode_init,
306
    .close          = tgq_decode_close,
307
    FF_CODEC_DECODE_CB(tgq_decode_frame),
308
    .p.capabilities = AV_CODEC_CAP_DR1,
309
};