Coverage Report

Created: 2026-07-25 07:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/motionpixels.c
Line
Count
Source
1
/*
2
 * Motion Pixels Video Decoder
3
 * Copyright (c) 2008 Gregory Montoir (cyx@users.sourceforge.net)
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
#include "libavutil/mem.h"
23
#include "libavutil/thread.h"
24
25
#include "config.h"
26
27
#include "avcodec.h"
28
#include "get_bits.h"
29
#include "bswapdsp.h"
30
#include "codec_internal.h"
31
#include "decode.h"
32
33
#define MAX_HUFF_CODES 16
34
35
#include "motionpixels_tablegen.h"
36
37
typedef struct HuffCode {
38
    uint8_t size;
39
    uint8_t delta;
40
} HuffCode;
41
42
typedef struct MotionPixelsContext {
43
    AVCodecContext *avctx;
44
    AVFrame *frame;
45
    BswapDSPContext bdsp;
46
    uint8_t *changes_map;
47
    int offset_bits_len;
48
    int codes_count, current_codes_count;
49
    int max_codes_bits;
50
    HuffCode codes[MAX_HUFF_CODES];
51
    VLC vlc;
52
    YuvPixel *vpt, *hpt;
53
    uint8_t gradient_scale[3];
54
    uint8_t *bswapbuf;
55
    int bswapbuf_size;
56
} MotionPixelsContext;
57
58
static av_cold int mp_decode_end(AVCodecContext *avctx)
59
935
{
60
935
    MotionPixelsContext *mp = avctx->priv_data;
61
62
935
    av_freep(&mp->changes_map);
63
935
    av_freep(&mp->vpt);
64
935
    av_freep(&mp->hpt);
65
935
    av_freep(&mp->bswapbuf);
66
935
    av_frame_free(&mp->frame);
67
68
935
    return 0;
69
935
}
70
71
static av_cold int mp_decode_init(AVCodecContext *avctx)
72
935
{
73
935
    MotionPixelsContext *mp = avctx->priv_data;
74
935
    int w4 = (avctx->width  + 3) & ~3;
75
935
    int h4 = (avctx->height + 3) & ~3;
76
77
935
    if(avctx->extradata_size < 2){
78
179
        av_log(avctx, AV_LOG_ERROR, "extradata too small\n");
79
179
        return AVERROR_INVALIDDATA;
80
179
    }
81
82
756
    mp->avctx = avctx;
83
756
    ff_bswapdsp_init(&mp->bdsp);
84
756
    mp->changes_map = av_calloc(avctx->width, h4);
85
756
    mp->offset_bits_len = av_log2(avctx->width * avctx->height) + 1;
86
756
    mp->vpt = av_calloc(avctx->height, sizeof(*mp->vpt));
87
756
    mp->hpt = av_calloc(h4 / 4, w4 / 4 * sizeof(*mp->hpt));
88
756
    if (!mp->changes_map || !mp->vpt || !mp->hpt)
89
0
        return AVERROR(ENOMEM);
90
756
    avctx->pix_fmt = AV_PIX_FMT_RGB555;
91
92
756
    mp->frame = av_frame_alloc();
93
756
    if (!mp->frame)
94
0
        return AVERROR(ENOMEM);
95
96
756
#if !CONFIG_HARDCODED_TABLES
97
756
    static AVOnce init_static_once = AV_ONCE_INIT;
98
756
    ff_thread_once(&init_static_once, motionpixels_tableinit);
99
756
#endif
100
101
756
    return 0;
102
756
}
103
104
static void mp_read_changes_map(MotionPixelsContext *mp, GetBitContext *gb, int count, int bits_len, int read_color)
105
273k
{
106
273k
    uint16_t *pixels;
107
273k
    int offset, w, h, color = 0, x, y, i;
108
109
73.0M
    while (count--) {
110
72.8M
        offset = get_bits_long(gb, mp->offset_bits_len);
111
72.8M
        w      = get_bits(gb, bits_len) + 1;
112
72.8M
        h      = get_bits(gb, bits_len) + 1;
113
72.8M
        if (read_color)
114
42.7M
            color = get_bits(gb, 15);
115
72.8M
        x = offset % mp->avctx->width;
116
72.8M
        y = offset / mp->avctx->width;
117
72.8M
        if (y >= mp->avctx->height)
118
129k
            continue;
119
72.6M
        w = FFMIN(w, mp->avctx->width  - x);
120
72.6M
        h = FFMIN(h, mp->avctx->height - y);
121
72.6M
        pixels = (uint16_t *)&mp->frame->data[0][y * mp->frame->linesize[0] + x * 2];
122
163M
        while (h--) {
123
91.2M
            mp->changes_map[offset] = w;
124
91.2M
            if (read_color)
125
814M
                for (i = 0; i < w; ++i)
126
761M
                    pixels[i] = color;
127
91.2M
            offset += mp->avctx->width;
128
91.2M
            pixels += mp->frame->linesize[0] / 2;
129
91.2M
        }
130
72.6M
    }
131
273k
}
132
133
static int mp_get_code(MotionPixelsContext *mp, GetBitContext *gb, int size)
134
11.8k
{
135
16.8k
    while (get_bits1(gb)) {
136
9.05k
        ++size;
137
9.05k
        if (size > mp->max_codes_bits) {
138
361
            av_log(mp->avctx, AV_LOG_ERROR, "invalid code size %d/%d\n", size, mp->max_codes_bits);
139
361
            return AVERROR_INVALIDDATA;
140
361
        }
141
8.69k
        if (mp_get_code(mp, gb, size) < 0)
142
3.68k
            return AVERROR_INVALIDDATA;
143
8.69k
    }
144
7.76k
    if (mp->current_codes_count >= mp->codes_count) {
145
354
        av_log(mp->avctx, AV_LOG_ERROR, "too many codes\n");
146
354
        return AVERROR_INVALIDDATA;
147
354
    }
148
149
7.41k
    mp->codes[mp->current_codes_count++].size = size;
150
7.41k
    return 0;
151
7.76k
}
152
153
static int mp_read_codes_table(MotionPixelsContext *mp, GetBitContext *gb)
154
5.31k
{
155
5.31k
    if (mp->codes_count == 1) {
156
2.20k
        mp->codes[0].delta = get_bits(gb, 4);
157
3.10k
    } else {
158
3.10k
        int i;
159
3.10k
        int ret;
160
161
3.10k
        mp->max_codes_bits = get_bits(gb, 4);
162
20.7k
        for (i = 0; i < mp->codes_count; ++i)
163
17.6k
            mp->codes[i].delta = get_bits(gb, 4);
164
3.10k
        mp->current_codes_count = 0;
165
3.10k
        if ((ret = mp_get_code(mp, gb, 0)) < 0)
166
715
            return ret;
167
2.39k
        if (mp->current_codes_count < mp->codes_count) {
168
1.30k
            av_log(mp->avctx, AV_LOG_ERROR, "too few codes\n");
169
1.30k
            return AVERROR_INVALIDDATA;
170
1.30k
        }
171
2.39k
   }
172
3.29k
   return 0;
173
5.31k
}
174
175
static av_always_inline int mp_gradient(MotionPixelsContext *mp, int component, int v)
176
712M
{
177
712M
    int delta;
178
179
712M
    delta = (v - 7) * mp->gradient_scale[component];
180
712M
    mp->gradient_scale[component] = (v == 0 || v == 14) ? 2 : 1;
181
712M
    return delta;
182
712M
}
183
184
static YuvPixel mp_get_yuv_from_rgb(MotionPixelsContext *mp, int x, int y)
185
1.01M
{
186
1.01M
    int color;
187
188
1.01M
    color = *(uint16_t *)&mp->frame->data[0][y * mp->frame->linesize[0] + x * 2];
189
1.01M
    return mp_rgb_yuv_table[color & 0x7FFF];
190
1.01M
}
191
192
static void mp_set_rgb_from_yuv(MotionPixelsContext *mp, int x, int y, const YuvPixel *p)
193
625M
{
194
625M
    int color;
195
196
625M
    color = mp_yuv_to_rgb(p->y, p->v, p->u, 1);
197
625M
    *(uint16_t *)&mp->frame->data[0][y * mp->frame->linesize[0] + x * 2] = color;
198
625M
}
199
200
static av_always_inline int mp_get_vlc(MotionPixelsContext *mp, GetBitContext *gb)
201
712M
{
202
712M
    return mp->vlc.table ? get_vlc2(gb, mp->vlc.table, mp->max_codes_bits, 1)
203
712M
                         : mp->codes[0].delta;
204
712M
}
205
206
static void mp_decode_line(MotionPixelsContext *mp, GetBitContext *gb, int y)
207
10.2M
{
208
10.2M
    YuvPixel p;
209
10.2M
    const int y0 = y * mp->avctx->width;
210
10.2M
    int w, i, x = 0;
211
212
10.2M
    p = mp->vpt[y];
213
10.2M
    if (mp->changes_map[y0 + x] == 0) {
214
10.1M
        memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale));
215
10.1M
        ++x;
216
10.1M
    }
217
626M
    while (x < mp->avctx->width) {
218
616M
        w = mp->changes_map[y0 + x];
219
616M
        if (w != 0) {
220
811k
            if ((y & 3) == 0) {
221
205k
                if (mp->changes_map[y0 + x + mp->avctx->width] < w ||
222
198k
                    mp->changes_map[y0 + x + mp->avctx->width * 2] < w ||
223
195k
                    mp->changes_map[y0 + x + mp->avctx->width * 3] < w) {
224
106k
                    for (i = (x + 3) & ~3; i < x + w; i += 4) {
225
93.5k
                        mp->hpt[((y / 4) * mp->avctx->width + i) / 4] = mp_get_yuv_from_rgb(mp, i, y);
226
93.5k
                    }
227
13.2k
                }
228
205k
            }
229
811k
            x += w;
230
811k
            memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale));
231
811k
            p = mp_get_yuv_from_rgb(mp, x - 1, y);
232
615M
        } else {
233
615M
            p.y += mp_gradient(mp, 0, mp_get_vlc(mp, gb));
234
615M
            p.y = av_clip_uintp2(p.y, 5);
235
615M
            if ((x & 3) == 0) {
236
151M
                if ((y & 3) == 0) {
237
40.8M
                    p.v += mp_gradient(mp, 1, mp_get_vlc(mp, gb));
238
40.8M
                    p.v = av_clip_intp2(p.v, 5);
239
40.8M
                    p.u += mp_gradient(mp, 2, mp_get_vlc(mp, gb));
240
40.8M
                    p.u = av_clip_intp2(p.u, 5);
241
40.8M
                    mp->hpt[((y / 4) * mp->avctx->width + x) / 4] = p;
242
110M
                } else {
243
110M
                    p.v = mp->hpt[((y / 4) * mp->avctx->width + x) / 4].v;
244
110M
                    p.u = mp->hpt[((y / 4) * mp->avctx->width + x) / 4].u;
245
110M
                }
246
151M
            }
247
615M
            mp_set_rgb_from_yuv(mp, x, y, &p);
248
615M
            ++x;
249
615M
        }
250
616M
    }
251
10.2M
}
252
253
static void mp_decode_frame_helper(MotionPixelsContext *mp, GetBitContext *gb)
254
2.53k
{
255
2.53k
    YuvPixel p;
256
2.53k
    int y, y0;
257
258
2.53k
    av_assert1(mp->changes_map[0]);
259
260
10.2M
    for (y = 0; y < mp->avctx->height; ++y) {
261
10.2M
        if (mp->changes_map[y * mp->avctx->width] != 0) {
262
109k
            memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale));
263
109k
            p = mp_get_yuv_from_rgb(mp, 0, y);
264
10.1M
        } else {
265
10.1M
            p.y += mp_gradient(mp, 0, mp_get_vlc(mp, gb));
266
10.1M
            p.y = av_clip_uintp2(p.y, 5);
267
10.1M
            if ((y & 3) == 0) {
268
2.53M
                p.v += mp_gradient(mp, 1, mp_get_vlc(mp, gb));
269
2.53M
                p.v = av_clip_intp2(p.v, 5);
270
2.53M
                p.u += mp_gradient(mp, 2, mp_get_vlc(mp, gb));
271
2.53M
                p.u = av_clip_intp2(p.u, 5);
272
2.53M
            }
273
10.1M
            mp->vpt[y] = p;
274
10.1M
            mp_set_rgb_from_yuv(mp, 0, y, &p);
275
10.1M
        }
276
10.2M
    }
277
7.59k
    for (y0 = 0; y0 < 2; ++y0)
278
10.2M
        for (y = y0; y < mp->avctx->height; y += 2)
279
10.2M
            mp_decode_line(mp, gb, y);
280
2.53k
}
281
282
static int mp_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
283
                           int *got_frame, AVPacket *avpkt)
284
364k
{
285
364k
    const uint8_t *buf = avpkt->data;
286
364k
    int buf_size = avpkt->size;
287
364k
    MotionPixelsContext *mp = avctx->priv_data;
288
364k
    GetBitContext gb;
289
364k
    int i, count1, count2, sz, ret;
290
291
364k
    if ((ret = ff_reget_buffer(avctx, mp->frame, 0)) < 0)
292
266k
        return ret;
293
294
    /* le32 bitstream msb first */
295
97.8k
    av_fast_padded_malloc(&mp->bswapbuf, &mp->bswapbuf_size, buf_size);
296
97.8k
    if (!mp->bswapbuf)
297
0
        return AVERROR(ENOMEM);
298
97.8k
    mp->bdsp.bswap_buf((uint32_t *) mp->bswapbuf, (const uint32_t *) buf,
299
97.8k
                       buf_size / 4);
300
97.8k
    if (buf_size & 3)
301
93.4k
        memcpy(mp->bswapbuf + (buf_size & ~3), buf + (buf_size & ~3), buf_size & 3);
302
97.8k
    init_get_bits(&gb, mp->bswapbuf, buf_size * 8);
303
304
97.8k
    memset(mp->changes_map, 0, avctx->width * avctx->height);
305
234k
    for (i = !(avctx->extradata[1] & 2); i < 2; ++i) {
306
136k
        count1 = get_bits(&gb, 12);
307
136k
        count2 = get_bits(&gb, 12);
308
136k
        mp_read_changes_map(mp, &gb, count1, 8, i);
309
136k
        mp_read_changes_map(mp, &gb, count2, 4, i);
310
136k
    }
311
312
97.8k
    mp->codes_count = get_bits(&gb, 4);
313
97.8k
    if (mp->codes_count == 0)
314
92.5k
        goto end;
315
316
5.31k
    if (mp->changes_map[0] == 0) {
317
4.96k
        *(uint16_t *)mp->frame->data[0] = get_bits(&gb, 15);
318
4.96k
        mp->changes_map[0] = 1;
319
4.96k
    }
320
5.31k
    if (mp_read_codes_table(mp, &gb) < 0)
321
2.02k
        goto end;
322
323
3.29k
    sz = get_bits(&gb, 18);
324
3.29k
    if (avctx->extradata[0] != 5)
325
2.82k
        sz += get_bits(&gb, 18);
326
3.29k
    if (sz == 0)
327
764
        goto end;
328
329
2.53k
    if (mp->codes_count > 1) {
330
        /* The entries of the mp->codes array are sorted from right to left
331
         * in the Huffman tree, hence -(int)sizeof(HuffCode). */
332
1.07k
        ret = ff_vlc_init_from_lengths(&mp->vlc, mp->max_codes_bits, mp->codes_count,
333
1.07k
                                       &mp->codes[mp->codes_count - 1].size,  -(int)sizeof(HuffCode),
334
1.07k
                                       &mp->codes[mp->codes_count - 1].delta, -(int)sizeof(HuffCode), 1,
335
1.07k
                                       0, 0, avctx);
336
1.07k
        if (ret < 0)
337
0
            goto end;
338
1.07k
    }
339
2.53k
    mp_decode_frame_helper(mp, &gb);
340
2.53k
    ff_vlc_free(&mp->vlc);
341
342
97.8k
end:
343
97.8k
    if ((ret = av_frame_ref(rframe, mp->frame)) < 0)
344
0
        return ret;
345
97.8k
    *got_frame       = 1;
346
97.8k
    return buf_size;
347
97.8k
}
348
349
const FFCodec ff_motionpixels_decoder = {
350
    .p.name         = "motionpixels",
351
    CODEC_LONG_NAME("Motion Pixels video"),
352
    .p.type         = AVMEDIA_TYPE_VIDEO,
353
    .p.id           = AV_CODEC_ID_MOTIONPIXELS,
354
    .priv_data_size = sizeof(MotionPixelsContext),
355
    .init           = mp_decode_init,
356
    .close          = mp_decode_end,
357
    FF_CODEC_DECODE_CB(mp_decode_frame),
358
    .p.capabilities = AV_CODEC_CAP_DR1,
359
    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
360
};