GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavcodec/roqvideodec.c Lines: 130 138 94.2 %
Date: 2020-10-23 17:01:47 Branches: 61 74 82.4 %

Line Branch Exec Source
1
/*
2
 * Copyright (C) 2003 The FFmpeg project
3
 *
4
 * This file is part of FFmpeg.
5
 *
6
 * FFmpeg is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
10
 *
11
 * FFmpeg is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with FFmpeg; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
 */
20
21
/**
22
 * @file
23
 * id RoQ Video Decoder by Dr. Tim Ferguson
24
 * For more information about the id RoQ format, visit:
25
 *   http://www.csse.monash.edu.au/~timf/
26
 */
27
28
#include "libavutil/avassert.h"
29
#include "libavutil/imgutils.h"
30
31
#include "avcodec.h"
32
#include "bytestream.h"
33
#include "internal.h"
34
#include "roqvideo.h"
35
36
225
static void roqvideo_decode_frame(RoqContext *ri, GetByteContext *gb)
37
{
38
225
    unsigned int chunk_id = 0, chunk_arg = 0;
39
225
    unsigned long chunk_size = 0;
40
225
    int i, j, k, nv1, nv2, vqflg = 0, vqflg_pos = -1;
41
    int vqid, xpos, ypos, xp, yp, x, y, mx, my;
42
    roq_qcell *qcell;
43
    int64_t chunk_start;
44
45
428
    while (bytestream2_get_bytes_left(gb) >= 8) {
46
428
        chunk_id   = bytestream2_get_le16(gb);
47
428
        chunk_size = bytestream2_get_le32(gb);
48
428
        chunk_arg  = bytestream2_get_le16(gb);
49
50
428
        if(chunk_id == RoQ_QUAD_VQ)
51
225
            break;
52
203
        if(chunk_id == RoQ_QUAD_CODEBOOK) {
53
203
            if((nv1 = chunk_arg >> 8) == 0)
54
67
                nv1 = 256;
55

203
            if((nv2 = chunk_arg & 0xff) == 0 && nv1 * 6 < chunk_size)
56
1
                nv2 = 256;
57
51102
            for(i = 0; i < nv1; i++) {
58
50899
                ri->cb2x2[i].y[0] = bytestream2_get_byte(gb);
59
50899
                ri->cb2x2[i].y[1] = bytestream2_get_byte(gb);
60
50899
                ri->cb2x2[i].y[2] = bytestream2_get_byte(gb);
61
50899
                ri->cb2x2[i].y[3] = bytestream2_get_byte(gb);
62
50899
                ri->cb2x2[i].u    = bytestream2_get_byte(gb);
63
50899
                ri->cb2x2[i].v    = bytestream2_get_byte(gb);
64
            }
65
17934
            for(i = 0; i < nv2; i++)
66
88655
                for(j = 0; j < 4; j++)
67
70924
                    ri->cb4x4[i].idx[j] = bytestream2_get_byte(gb);
68
        }
69
    }
70
71
225
    chunk_start = bytestream2_tell(gb);
72
225
    xpos = ypos = 0;
73
74
225
    if (chunk_size > bytestream2_get_bytes_left(gb)) {
75
        av_log(ri->avctx, AV_LOG_ERROR, "Chunk does not fit in input buffer\n");
76
        chunk_size = bytestream2_get_bytes_left(gb);
77
    }
78
79
113460
    while (bytestream2_tell(gb) < chunk_start + chunk_size) {
80
340342
        for (yp = ypos; yp < ypos + 16; yp += 8)
81
680707
            for (xp = xpos; xp < xpos + 16; xp += 8) {
82
453825
                if (bytestream2_tell(gb) >= chunk_start + chunk_size) {
83
4
                    av_log(ri->avctx, AV_LOG_VERBOSE, "Chunk is too short\n");
84
4
                    return;
85
                }
86
453821
                if (vqflg_pos < 0) {
87
56771
                    vqflg = bytestream2_get_le16(gb);
88
56771
                    vqflg_pos = 7;
89
                }
90
453821
                vqid = (vqflg >> (vqflg_pos * 2)) & 0x3;
91
453821
                vqflg_pos--;
92
93

453821
                switch(vqid) {
94
121738
                case RoQ_ID_MOT:
95
121738
                    break;
96
9277
                case RoQ_ID_FCC: {
97
9277
                    int byte = bytestream2_get_byte(gb);
98
9277
                    mx = 8 - (byte >> 4) - ((signed char) (chunk_arg >> 8));
99
9277
                    my = 8 - (byte & 0xf) - ((signed char) chunk_arg);
100
9277
                    ff_apply_motion_8x8(ri, xp, yp, mx, my);
101
9277
                    break;
102
                }
103
7001
                case RoQ_ID_SLD:
104
7001
                    qcell = ri->cb4x4 + bytestream2_get_byte(gb);
105
7001
                    ff_apply_vector_4x4(ri, xp,     yp,     ri->cb2x2 + qcell->idx[0]);
106
7001
                    ff_apply_vector_4x4(ri, xp + 4, yp,     ri->cb2x2 + qcell->idx[1]);
107
7001
                    ff_apply_vector_4x4(ri, xp,     yp + 4, ri->cb2x2 + qcell->idx[2]);
108
7001
                    ff_apply_vector_4x4(ri, xp + 4, yp + 4, ri->cb2x2 + qcell->idx[3]);
109
7001
                    break;
110
315805
                case RoQ_ID_CCC:
111
1578984
                    for (k = 0; k < 4; k++) {
112
1263209
                        x = xp; y = yp;
113
1263209
                        if(k & 0x01) x += 4;
114
1263209
                        if(k & 0x02) y += 4;
115
116
1263209
                        if (bytestream2_tell(gb) >= chunk_start + chunk_size) {
117
30
                            av_log(ri->avctx, AV_LOG_VERBOSE, "Chunk is too short\n");
118
30
                            return;
119
                        }
120
1263179
                        if (vqflg_pos < 0) {
121
157911
                            vqflg = bytestream2_get_le16(gb);
122
157911
                            vqflg_pos = 7;
123
                        }
124
1263179
                        vqid = (vqflg >> (vqflg_pos * 2)) & 0x3;
125

1263179
                        vqflg_pos--;
126
                        switch(vqid) {
127
259115
                        case RoQ_ID_MOT:
128
259115
                            break;
129
521989
                        case RoQ_ID_FCC: {
130
521989
                            int byte = bytestream2_get_byte(gb);
131
521989
                            mx = 8 - (byte >> 4) - ((signed char) (chunk_arg >> 8));
132
521989
                            my = 8 - (byte & 0xf) - ((signed char) chunk_arg);
133
521989
                            ff_apply_motion_4x4(ri, x, y, mx, my);
134
521989
                            break;
135
                        }
136
116817
                        case RoQ_ID_SLD:
137
116817
                            qcell = ri->cb4x4 + bytestream2_get_byte(gb);
138
116817
                            ff_apply_vector_2x2(ri, x,     y,     ri->cb2x2 + qcell->idx[0]);
139
116817
                            ff_apply_vector_2x2(ri, x + 2, y,     ri->cb2x2 + qcell->idx[1]);
140
116817
                            ff_apply_vector_2x2(ri, x,     y + 2, ri->cb2x2 + qcell->idx[2]);
141
116817
                            ff_apply_vector_2x2(ri, x + 2, y + 2, ri->cb2x2 + qcell->idx[3]);
142
116817
                            break;
143
365258
                        case RoQ_ID_CCC:
144
365258
                            ff_apply_vector_2x2(ri, x,     y,     ri->cb2x2 + bytestream2_get_byte(gb));
145
365258
                            ff_apply_vector_2x2(ri, x + 2, y,     ri->cb2x2 + bytestream2_get_byte(gb));
146
365258
                            ff_apply_vector_2x2(ri, x,     y + 2, ri->cb2x2 + bytestream2_get_byte(gb));
147
365258
                            ff_apply_vector_2x2(ri, x + 2, y + 2, ri->cb2x2 + bytestream2_get_byte(gb));
148
365258
                            break;
149
                        }
150
1263179
                    }
151
315775
                    break;
152
453791
                default:
153
                    av_assert2(0);
154
            }
155
        }
156
157
113426
        xpos += 16;
158
113426
        if (xpos >= ri->width) {
159
3596
            xpos -= ri->width;
160
3596
            ypos += 16;
161
        }
162
113426
        if(ypos >= ri->height)
163
191
            break;
164
    }
165
}
166
167
168
10
static av_cold int roq_decode_init(AVCodecContext *avctx)
169
{
170
10
    RoqContext *s = avctx->priv_data;
171
172
10
    s->avctx = avctx;
173
174

10
    if (avctx->width % 16 || avctx->height % 16) {
175
        avpriv_request_sample(avctx, "Dimensions not being a multiple of 16");
176
        return AVERROR_PATCHWELCOME;
177
    }
178
179
10
    s->width = avctx->width;
180
10
    s->height = avctx->height;
181
182
10
    s->last_frame    = av_frame_alloc();
183
10
    s->current_frame = av_frame_alloc();
184

10
    if (!s->current_frame || !s->last_frame)
185
        return AVERROR(ENOMEM);
186
187
10
    avctx->pix_fmt = AV_PIX_FMT_YUVJ444P;
188
10
    avctx->color_range = AVCOL_RANGE_JPEG;
189
190
10
    return 0;
191
}
192
193
225
static int roq_decode_frame(AVCodecContext *avctx,
194
                            void *data, int *got_frame,
195
                            AVPacket *avpkt)
196
{
197
225
    const uint8_t *buf = avpkt->data;
198
225
    int buf_size = avpkt->size;
199
225
    RoqContext *s = avctx->priv_data;
200

225
    int copy = !s->current_frame->data[0] && s->last_frame->data[0];
201
    GetByteContext gb;
202
    int ret;
203
204
225
    if ((ret = ff_reget_buffer(avctx, s->current_frame, 0)) < 0)
205
        return ret;
206
207
225
    if (copy) {
208
4
        ret = av_frame_copy(s->current_frame, s->last_frame);
209
4
        if (ret < 0)
210
            return ret;
211
    }
212
213
225
    bytestream2_init(&gb, buf, buf_size);
214
225
    roqvideo_decode_frame(s, &gb);
215
216
225
    if ((ret = av_frame_ref(data, s->current_frame)) < 0)
217
        return ret;
218
225
    *got_frame      = 1;
219
220
    /* shuffle frames */
221
225
    FFSWAP(AVFrame *, s->current_frame, s->last_frame);
222
223
225
    return buf_size;
224
}
225
226
10
static av_cold int roq_decode_end(AVCodecContext *avctx)
227
{
228
10
    RoqContext *s = avctx->priv_data;
229
230
10
    av_frame_free(&s->current_frame);
231
10
    av_frame_free(&s->last_frame);
232
233
10
    return 0;
234
}
235
236
AVCodec ff_roq_decoder = {
237
    .name           = "roqvideo",
238
    .long_name      = NULL_IF_CONFIG_SMALL("id RoQ video"),
239
    .type           = AVMEDIA_TYPE_VIDEO,
240
    .id             = AV_CODEC_ID_ROQ,
241
    .priv_data_size = sizeof(RoqContext),
242
    .init           = roq_decode_init,
243
    .close          = roq_decode_end,
244
    .decode         = roq_decode_frame,
245
    .capabilities   = AV_CODEC_CAP_DR1,
246
    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
247
};