Coverage Report

Created: 2025-12-31 07:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/wcmv.c
Line
Count
Source
1
/*
2
 * WinCAM Motion Video decoder
3
 *
4
 * Copyright (c) 2018 Paul B Mahol
5
 *
6
 * This file is part of FFmpeg.
7
 *
8
 * FFmpeg is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public
10
 * License as published by the Free Software Foundation; either
11
 * version 2.1 of the License, or (at your option) any later version.
12
 *
13
 * FFmpeg is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with FFmpeg; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
 */
22
23
#include <stdio.h>
24
25
#include "libavutil/imgutils.h"
26
27
#include "avcodec.h"
28
#include "bytestream.h"
29
#include "codec_internal.h"
30
#include "decode.h"
31
#include "zlib_wrapper.h"
32
33
#include <zlib.h>
34
35
typedef struct WCMVContext {
36
    int         bpp;
37
    FFZStream   zstream;
38
    AVFrame    *prev_frame;
39
    uint8_t     block_data[65536*8];
40
} WCMVContext;
41
42
static int decode_frame(AVCodecContext *avctx, AVFrame *frame,
43
                        int *got_frame, AVPacket *avpkt)
44
174k
{
45
174k
    WCMVContext *s = avctx->priv_data;
46
174k
    z_stream *const zstream = &s->zstream.zstream;
47
174k
    int skip, blocks, zret, ret, intra = 0, flags = 0, bpp = s->bpp;
48
174k
    GetByteContext gb;
49
174k
    uint8_t *dst;
50
51
174k
    ret = inflateReset(zstream);
52
174k
    if (ret != Z_OK) {
53
0
        av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", ret);
54
0
        return AVERROR_EXTERNAL;
55
0
    }
56
57
174k
    bytestream2_init(&gb, avpkt->data, avpkt->size);
58
174k
    blocks = bytestream2_get_le16(&gb);
59
174k
    if (!blocks)
60
130k
        flags |= FF_REGET_BUFFER_FLAG_READONLY;
61
62
174k
    if ((ret = ff_reget_buffer(avctx, s->prev_frame, flags)) < 0)
63
21.1k
        return ret;
64
65
153k
    if (blocks > 5) {
66
26.0k
        GetByteContext bgb;
67
26.0k
        int x = 0, size;
68
69
26.0k
        if (blocks * 8 >= 0xFFFF)
70
4.41k
            size = bytestream2_get_le24(&gb);
71
21.6k
        else if (blocks * 8 >= 0xFF)
72
7.92k
            size = bytestream2_get_le16(&gb);
73
13.7k
        else
74
13.7k
            size = bytestream2_get_byte(&gb);
75
76
26.0k
        skip = bytestream2_tell(&gb);
77
26.0k
        if (size > avpkt->size - skip)
78
6.81k
            return AVERROR_INVALIDDATA;
79
80
19.2k
        zstream->next_in   = avpkt->data + skip;
81
19.2k
        zstream->avail_in  = size;
82
19.2k
        zstream->next_out  = s->block_data;
83
19.2k
        zstream->avail_out = sizeof(s->block_data);
84
85
19.2k
        zret = inflate(zstream, Z_FINISH);
86
19.2k
        if (zret != Z_STREAM_END) {
87
16.7k
            av_log(avctx, AV_LOG_ERROR,
88
16.7k
                   "Inflate failed with return code: %d.\n", zret);
89
16.7k
            return AVERROR_INVALIDDATA;
90
16.7k
        }
91
92
2.53k
        ret = inflateReset(zstream);
93
2.53k
        if (ret != Z_OK) {
94
0
            av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", ret);
95
0
            return AVERROR_EXTERNAL;
96
0
        }
97
98
2.53k
        bytestream2_skip(&gb, size);
99
2.53k
        bytestream2_init(&bgb, s->block_data, blocks * 8);
100
101
440k
        for (int i = 0; i < blocks; i++) {
102
438k
            int w, h;
103
104
438k
            bytestream2_skip(&bgb, 4);
105
438k
            w = bytestream2_get_le16(&bgb);
106
438k
            h = bytestream2_get_le16(&bgb);
107
438k
            if (x + bpp * (int64_t)w * h > INT_MAX)
108
215
                return AVERROR_INVALIDDATA;
109
437k
            x += bpp * w * h;
110
437k
        }
111
112
2.31k
        if (x >= 0xFFFF)
113
585
            bytestream2_skip(&gb, 3);
114
1.73k
        else if (x >= 0xFF)
115
641
            bytestream2_skip(&gb, 2);
116
1.09k
        else
117
1.09k
            bytestream2_skip(&gb, 1);
118
119
2.31k
        skip = bytestream2_tell(&gb);
120
121
2.31k
        zstream->next_in  = avpkt->data + skip;
122
2.31k
        zstream->avail_in = avpkt->size - skip;
123
124
2.31k
        bytestream2_init(&gb, s->block_data, blocks * 8);
125
127k
    } else if (blocks) {
126
14.7k
        int x = 0;
127
128
14.7k
        bytestream2_seek(&gb, 2, SEEK_SET);
129
130
30.4k
        for (int i = 0; i < blocks; i++) {
131
16.1k
            int w, h;
132
133
16.1k
            bytestream2_skip(&gb, 4);
134
16.1k
            w = bytestream2_get_le16(&gb);
135
16.1k
            h = bytestream2_get_le16(&gb);
136
16.1k
            if (x + bpp * (int64_t)w * h > INT_MAX)
137
449
                return AVERROR_INVALIDDATA;
138
15.7k
            x += bpp * w * h;
139
15.7k
        }
140
141
14.2k
        if (x >= 0xFFFF)
142
1.75k
            bytestream2_skip(&gb, 3);
143
12.5k
        else if (x >= 0xFF)
144
3.72k
            bytestream2_skip(&gb, 2);
145
8.80k
        else
146
8.80k
            bytestream2_skip(&gb, 1);
147
148
14.2k
        skip = bytestream2_tell(&gb);
149
150
14.2k
        zstream->next_in  = avpkt->data + skip;
151
14.2k
        zstream->avail_in = avpkt->size - skip;
152
153
14.2k
        bytestream2_seek(&gb, 2, SEEK_SET);
154
14.2k
    }
155
156
129k
    if (bytestream2_get_bytes_left(&gb) < 8LL * blocks)
157
1.11k
        return AVERROR_INVALIDDATA;
158
159
128k
    if (!avctx->frame_num) {
160
9.41k
        ptrdiff_t linesize[4] = { s->prev_frame->linesize[0], 0, 0, 0 };
161
9.41k
        av_image_fill_black(s->prev_frame->data, linesize, avctx->pix_fmt, 0,
162
9.41k
                            avctx->width, avctx->height);
163
9.41k
    }
164
165
544k
    for (int block = 0; block < blocks; block++) {
166
425k
        int x, y, w, h;
167
168
425k
        x = bytestream2_get_le16(&gb);
169
425k
        y = bytestream2_get_le16(&gb);
170
425k
        w = bytestream2_get_le16(&gb);
171
425k
        h = bytestream2_get_le16(&gb);
172
173
425k
        if (blocks == 1 && x == 0 && y == 0 && w == avctx->width && h == avctx->height)
174
755
            intra = 1;
175
176
425k
        if (x + w > avctx->width || y + h > avctx->height)
177
4.12k
            return AVERROR_INVALIDDATA;
178
179
421k
        if (w > avctx->width || h > avctx->height)
180
0
            return AVERROR_INVALIDDATA;
181
182
421k
        dst = s->prev_frame->data[0] + (avctx->height - y - 1) * s->prev_frame->linesize[0] + x * bpp;
183
800k
        for (int i = 0; i < h; i++) {
184
384k
            zstream->next_out  = dst;
185
384k
            zstream->avail_out = w * bpp;
186
187
384k
            zret = inflate(zstream, Z_SYNC_FLUSH);
188
384k
            if (zret != Z_OK && zret != Z_STREAM_END) {
189
6.02k
                av_log(avctx, AV_LOG_ERROR,
190
6.02k
                       "Inflate failed with return code: %d.\n", zret);
191
6.02k
                return AVERROR_INVALIDDATA;
192
6.02k
            }
193
194
378k
            dst -= s->prev_frame->linesize[0];
195
378k
        }
196
421k
    }
197
198
118k
    if (intra)
199
251
        s->prev_frame->flags |= AV_FRAME_FLAG_KEY;
200
118k
    else
201
118k
        s->prev_frame->flags &= ~AV_FRAME_FLAG_KEY;
202
118k
    s->prev_frame->pict_type = intra ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
203
204
118k
    if ((ret = av_frame_ref(frame, s->prev_frame)) < 0)
205
0
        return ret;
206
207
118k
    *got_frame = 1;
208
209
118k
    return avpkt->size;
210
118k
}
211
212
static av_cold int decode_init(AVCodecContext *avctx)
213
1.43k
{
214
1.43k
    WCMVContext *s = avctx->priv_data;
215
216
1.43k
    switch (avctx->bits_per_coded_sample) {
217
785
    case 16: avctx->pix_fmt = AV_PIX_FMT_RGB565LE; break;
218
142
    case 24: avctx->pix_fmt = AV_PIX_FMT_BGR24;  break;
219
389
    case 32: avctx->pix_fmt = AV_PIX_FMT_BGRA;   break;
220
121
    default: av_log(avctx, AV_LOG_ERROR, "Unsupported bits_per_coded_sample: %d\n",
221
121
                    avctx->bits_per_coded_sample);
222
121
             return AVERROR_PATCHWELCOME;
223
1.43k
    }
224
225
1.31k
    s->bpp = avctx->bits_per_coded_sample >> 3;
226
227
1.31k
    s->prev_frame = av_frame_alloc();
228
1.31k
    if (!s->prev_frame)
229
0
        return AVERROR(ENOMEM);
230
231
1.31k
    return ff_inflate_init(&s->zstream, avctx);
232
1.31k
}
233
234
static av_cold int decode_close(AVCodecContext *avctx)
235
1.43k
{
236
1.43k
    WCMVContext *s = avctx->priv_data;
237
238
1.43k
    av_frame_free(&s->prev_frame);
239
1.43k
    ff_inflate_end(&s->zstream);
240
241
1.43k
    return 0;
242
1.43k
}
243
244
const FFCodec ff_wcmv_decoder = {
245
    .p.name           = "wcmv",
246
    CODEC_LONG_NAME("WinCAM Motion Video"),
247
    .p.type           = AVMEDIA_TYPE_VIDEO,
248
    .p.id             = AV_CODEC_ID_WCMV,
249
    .priv_data_size   = sizeof(WCMVContext),
250
    .init             = decode_init,
251
    .close            = decode_close,
252
    FF_CODEC_DECODE_CB(decode_frame),
253
    .p.capabilities   = AV_CODEC_CAP_DR1,
254
    .caps_internal    = FF_CODEC_CAP_INIT_CLEANUP,
255
};