Coverage Report

Created: 2025-12-31 07:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/cinepak.c
Line
Count
Source
1
/*
2
 * Cinepak Video Decoder
3
 * Copyright (C) 2003 The FFmpeg project
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
 * Cinepak video decoder
25
 * @author Ewald Snel <ewald@rambo.its.tudelft.nl>
26
 *
27
 * @see For more information on the Cinepak algorithm, visit:
28
 *   http://www.csse.monash.edu.au/~timf/
29
 * @see For more information on the quirky data inside Sega FILM/CPK files, visit:
30
 *   http://wiki.multimedia.cx/index.php?title=Sega_FILM
31
 *
32
 * Cinepak colorspace support (c) 2013 Rl, Aetey Global Technologies AB
33
 * @author Cinepak colorspace, Rl, Aetey Global Technologies AB
34
 */
35
36
#include <stdio.h>
37
#include <string.h>
38
39
#include "libavutil/common.h"
40
#include "libavutil/intreadwrite.h"
41
#include "avcodec.h"
42
#include "codec_internal.h"
43
#include "decode.h"
44
45
46
typedef uint8_t cvid_codebook[12];
47
48
#define MAX_STRIPS      32
49
50
typedef struct cvid_strip {
51
    uint16_t          id;
52
    uint16_t          x1, y1;
53
    uint16_t          x2, y2;
54
    cvid_codebook     v4_codebook[256];
55
    cvid_codebook     v1_codebook[256];
56
} cvid_strip;
57
58
typedef struct CinepakContext {
59
60
    AVCodecContext *avctx;
61
    AVFrame *frame;
62
63
    const unsigned char *data;
64
    int size;
65
66
    int width, height;
67
68
    int palette_video;
69
    cvid_strip strips[MAX_STRIPS];
70
71
    int sega_film_skip_bytes;
72
73
    uint32_t pal[256];
74
} CinepakContext;
75
76
static void cinepak_decode_codebook (cvid_codebook *codebook,
77
                                     int chunk_id, int size, const uint8_t *data)
78
3.09k
{
79
3.09k
    const uint8_t *eod = (data + size);
80
3.09k
    uint32_t flag, mask;
81
3.09k
    int      i, n;
82
3.09k
    uint8_t *p;
83
84
    /* check if this chunk contains 4- or 6-element vectors */
85
3.09k
    n    = (chunk_id & 0x04) ? 4 : 6;
86
3.09k
    flag = 0;
87
3.09k
    mask = 0;
88
89
3.09k
    p = codebook[0];
90
201k
    for (i=0; i < 256; i++) {
91
201k
        if ((chunk_id & 0x01) && !(mask >>= 1)) {
92
6.97k
            if ((data + 4) > eod)
93
870
                break;
94
95
6.10k
            flag  = AV_RB32 (data);
96
6.10k
            data += 4;
97
6.10k
            mask  = 0x80000000;
98
6.10k
        }
99
100
200k
        if (!(chunk_id & 0x01) || (flag & mask)) {
101
29.4k
            int k, kk;
102
103
29.4k
            if ((data + n) > eod)
104
1.77k
                break;
105
106
138k
            for (k = 0; k < 4; ++k) {
107
110k
                int r = *data++;
108
442k
                for (kk = 0; kk < 3; ++kk)
109
331k
                    *p++ = r;
110
110k
            }
111
27.6k
            if (n == 6) {
112
14.7k
                int r, g, b, u, v;
113
14.7k
                u = *(int8_t *)data++;
114
14.7k
                v = *(int8_t *)data++;
115
14.7k
                p -= 12;
116
73.8k
                for(k=0; k<4; ++k) {
117
59.0k
                    r = *p++ + v*2;
118
59.0k
                    g = *p++ - (u/2) - v;
119
59.0k
                    b = *p   + u*2;
120
59.0k
                    p -= 2;
121
59.0k
                    *p++ = av_clip_uint8(r);
122
59.0k
                    *p++ = av_clip_uint8(g);
123
59.0k
                    *p++ = av_clip_uint8(b);
124
59.0k
                }
125
14.7k
            }
126
170k
        } else {
127
170k
            p += 12;
128
170k
        }
129
200k
    }
130
3.09k
}
131
132
static int cinepak_decode_vectors (CinepakContext *s, cvid_strip *strip,
133
                                   int chunk_id, int size, const uint8_t *data)
134
4.92k
{
135
4.92k
    const uint8_t   *eod = (data + size);
136
4.92k
    uint32_t         flag, mask;
137
4.92k
    uint8_t         *cb0, *cb1, *cb2, *cb3;
138
4.92k
    int             x, y;
139
4.92k
    char            *ip0, *ip1, *ip2, *ip3;
140
141
4.92k
    flag = 0;
142
4.92k
    mask = 0;
143
144
12.2k
    for (y=strip->y1; y < strip->y2; y+=4) {
145
146
/* take care of y dimension not being multiple of 4, such streams exist */
147
10.1k
        ip0 = ip1 = ip2 = ip3 = s->frame->data[0] +
148
10.1k
          (s->palette_video?strip->x1:strip->x1*3) + (y * s->frame->linesize[0]);
149
10.1k
        if(s->avctx->height - y > 1) {
150
8.93k
            ip1 = ip0 + s->frame->linesize[0];
151
8.93k
            if(s->avctx->height - y > 2) {
152
8.70k
                ip2 = ip1 + s->frame->linesize[0];
153
8.70k
                if(s->avctx->height - y > 3) {
154
7.25k
                    ip3 = ip2 + s->frame->linesize[0];
155
7.25k
                }
156
8.70k
            }
157
8.93k
        }
158
/* to get the correct picture for not-multiple-of-4 cases let us fill each
159
 * block from the bottom up, thus possibly overwriting the bottommost line
160
 * more than once but ending with the correct data in place
161
 * (instead of in-loop checking) */
162
163
113k
        for (x=strip->x1; x < strip->x2; x+=4) {
164
106k
            if ((chunk_id & 0x01) && !(mask >>= 1)) {
165
1.74k
                if ((data + 4) > eod)
166
776
                    return AVERROR_INVALIDDATA;
167
168
970
                flag  = AV_RB32 (data);
169
970
                data += 4;
170
970
                mask  = 0x80000000;
171
970
            }
172
173
105k
            if (!(chunk_id & 0x01) || (flag & mask)) {
174
86.5k
                if (!(chunk_id & 0x02) && !(mask >>= 1)) {
175
3.86k
                    if ((data + 4) > eod)
176
498
                        return AVERROR_INVALIDDATA;
177
178
3.36k
                    flag  = AV_RB32 (data);
179
3.36k
                    data += 4;
180
3.36k
                    mask  = 0x80000000;
181
3.36k
                }
182
183
86.0k
                if ((chunk_id & 0x02) || (~flag & mask)) {
184
67.9k
                    uint8_t *p;
185
67.9k
                    if (data >= eod)
186
661
                        return AVERROR_INVALIDDATA;
187
188
67.3k
                    p = strip->v1_codebook[*data++];
189
67.3k
                    if (s->palette_video) {
190
8.04k
                        ip3[0] = ip3[1] = ip2[0] = ip2[1] = p[6];
191
8.04k
                        ip3[2] = ip3[3] = ip2[2] = ip2[3] = p[9];
192
8.04k
                        ip1[0] = ip1[1] = ip0[0] = ip0[1] = p[0];
193
8.04k
                        ip1[2] = ip1[3] = ip0[2] = ip0[3] = p[3];
194
59.2k
                    } else {
195
59.2k
                        p += 6;
196
59.2k
                        memcpy(ip3 + 0, p, 3); memcpy(ip3 + 3, p, 3);
197
59.2k
                        memcpy(ip2 + 0, p, 3); memcpy(ip2 + 3, p, 3);
198
59.2k
                        p += 3; /* ... + 9 */
199
59.2k
                        memcpy(ip3 + 6, p, 3); memcpy(ip3 + 9, p, 3);
200
59.2k
                        memcpy(ip2 + 6, p, 3); memcpy(ip2 + 9, p, 3);
201
59.2k
                        p -= 9; /* ... + 0 */
202
59.2k
                        memcpy(ip1 + 0, p, 3); memcpy(ip1 + 3, p, 3);
203
59.2k
                        memcpy(ip0 + 0, p, 3); memcpy(ip0 + 3, p, 3);
204
59.2k
                        p += 3; /* ... + 3 */
205
59.2k
                        memcpy(ip1 + 6, p, 3); memcpy(ip1 + 9, p, 3);
206
59.2k
                        memcpy(ip0 + 6, p, 3); memcpy(ip0 + 9, p, 3);
207
59.2k
                    }
208
209
67.3k
                } else if (flag & mask) {
210
18.0k
                    if ((data + 4) > eod)
211
898
                        return AVERROR_INVALIDDATA;
212
213
17.1k
                    cb0 = strip->v4_codebook[*data++];
214
17.1k
                    cb1 = strip->v4_codebook[*data++];
215
17.1k
                    cb2 = strip->v4_codebook[*data++];
216
17.1k
                    cb3 = strip->v4_codebook[*data++];
217
17.1k
                    if (s->palette_video) {
218
3.32k
                        uint8_t *p;
219
3.32k
                        p = ip3;
220
3.32k
                        *p++ = cb2[6];
221
3.32k
                        *p++ = cb2[9];
222
3.32k
                        *p++ = cb3[6];
223
3.32k
                        *p   = cb3[9];
224
3.32k
                        p = ip2;
225
3.32k
                        *p++ = cb2[0];
226
3.32k
                        *p++ = cb2[3];
227
3.32k
                        *p++ = cb3[0];
228
3.32k
                        *p   = cb3[3];
229
3.32k
                        p = ip1;
230
3.32k
                        *p++ = cb0[6];
231
3.32k
                        *p++ = cb0[9];
232
3.32k
                        *p++ = cb1[6];
233
3.32k
                        *p   = cb1[9];
234
3.32k
                        p = ip0;
235
3.32k
                        *p++ = cb0[0];
236
3.32k
                        *p++ = cb0[3];
237
3.32k
                        *p++ = cb1[0];
238
3.32k
                        *p   = cb1[3];
239
13.8k
                    } else {
240
13.8k
                        memcpy(ip3 + 0, cb2 + 6, 6);
241
13.8k
                        memcpy(ip3 + 6, cb3 + 6, 6);
242
13.8k
                        memcpy(ip2 + 0, cb2 + 0, 6);
243
13.8k
                        memcpy(ip2 + 6, cb3 + 0, 6);
244
13.8k
                        memcpy(ip1 + 0, cb0 + 6, 6);
245
13.8k
                        memcpy(ip1 + 6, cb1 + 6, 6);
246
13.8k
                        memcpy(ip0 + 0, cb0 + 0, 6);
247
13.8k
                        memcpy(ip0 + 6, cb1 + 0, 6);
248
13.8k
                    }
249
250
17.1k
                }
251
86.0k
            }
252
253
103k
            if (s->palette_video) {
254
12.1k
                ip0 += 4;  ip1 += 4;
255
12.1k
                ip2 += 4;  ip3 += 4;
256
91.2k
            } else {
257
91.2k
                ip0 += 12;  ip1 += 12;
258
91.2k
                ip2 += 12;  ip3 += 12;
259
91.2k
            }
260
103k
        }
261
10.1k
    }
262
263
2.09k
    return 0;
264
4.92k
}
265
266
static int cinepak_decode_strip (CinepakContext *s,
267
                                 cvid_strip *strip, const uint8_t *data, int size)
268
16.2k
{
269
16.2k
    const uint8_t *eod = (data + size);
270
16.2k
    int      chunk_id, chunk_size;
271
272
    /* coordinate sanity checks */
273
16.2k
    if (strip->x2 > s->width   ||
274
14.9k
        strip->y2 > s->height  ||
275
8.91k
        strip->x1 >= strip->x2 || strip->y1 >= strip->y2)
276
8.17k
        return AVERROR_INVALIDDATA;
277
278
11.6k
    while ((data + 4) <= eod) {
279
8.89k
        chunk_id   = data[0];
280
8.89k
        chunk_size = AV_RB24 (&data[1]) - 4;
281
8.89k
        if(chunk_size < 0)
282
340
            return AVERROR_INVALIDDATA;
283
284
8.55k
        data      += 4;
285
8.55k
        chunk_size = ((data + chunk_size) > eod) ? (eod - data) : chunk_size;
286
287
8.55k
        switch (chunk_id) {
288
289
214
        case 0x20:
290
564
        case 0x21:
291
858
        case 0x24:
292
1.13k
        case 0x25:
293
1.13k
            cinepak_decode_codebook (strip->v4_codebook, chunk_id,
294
1.13k
                chunk_size, data);
295
1.13k
            break;
296
297
232
        case 0x22:
298
655
        case 0x23:
299
854
        case 0x26:
300
1.96k
        case 0x27:
301
1.96k
            cinepak_decode_codebook (strip->v1_codebook, chunk_id,
302
1.96k
                chunk_size, data);
303
1.96k
            break;
304
305
2.62k
        case 0x30:
306
3.73k
        case 0x31:
307
4.92k
        case 0x32:
308
4.92k
            return cinepak_decode_vectors (s, strip, chunk_id,
309
4.92k
                chunk_size, data);
310
8.55k
        }
311
312
3.63k
        data += chunk_size;
313
3.63k
    }
314
315
2.78k
    return AVERROR_INVALIDDATA;
316
8.04k
}
317
318
static int cinepak_predecode_check (CinepakContext *s)
319
24.3k
{
320
24.3k
    int           num_strips;
321
24.3k
    int           encoded_buf_size;
322
323
24.3k
    num_strips  = AV_RB16 (&s->data[8]);
324
24.3k
    encoded_buf_size = AV_RB24(&s->data[1]);
325
326
24.3k
    if (s->size < encoded_buf_size * (int64_t)(100 - s->avctx->discard_damaged_percentage) / 100)
327
4.49k
        return AVERROR_INVALIDDATA;
328
329
    /* if this is the first frame, check for deviant Sega FILM data */
330
19.8k
    if (s->sega_film_skip_bytes == -1) {
331
1.15k
        if (!encoded_buf_size) {
332
347
            avpriv_request_sample(s->avctx, "encoded_buf_size 0");
333
347
            return AVERROR_PATCHWELCOME;
334
347
        }
335
803
        if (encoded_buf_size != s->size && (s->size % encoded_buf_size) != 0) {
336
            /* If the encoded frame size differs from the frame size as indicated
337
             * by the container file, this data likely comes from a Sega FILM/CPK file.
338
             * If the frame header is followed by the bytes FE 00 00 06 00 00 then
339
             * this is probably one of the two known files that have 6 extra bytes
340
             * after the frame header. Else, assume 2 extra bytes. The container
341
             * size also cannot be a multiple of the encoded size. */
342
695
            if (s->size >= 16 &&
343
652
                (s->data[10] == 0xFE) &&
344
76
                (s->data[11] == 0x00) &&
345
51
                (s->data[12] == 0x00) &&
346
43
                (s->data[13] == 0x06) &&
347
21
                (s->data[14] == 0x00) &&
348
13
                (s->data[15] == 0x00))
349
4
                s->sega_film_skip_bytes = 6;
350
691
            else
351
691
                s->sega_film_skip_bytes = 2;
352
695
        } else
353
108
            s->sega_film_skip_bytes = 0;
354
803
    }
355
356
19.5k
    if (s->size < 10 + s->sega_film_skip_bytes + num_strips * 12)
357
1.97k
        return AVERROR_INVALIDDATA;
358
359
17.5k
    if (num_strips) {
360
17.5k
        const uint8_t *data = s->data + 10 + s->sega_film_skip_bytes;
361
17.5k
        int strip_size = AV_RB24 (data + 1);
362
17.5k
        if (strip_size < 12 || strip_size > encoded_buf_size)
363
1.28k
            return AVERROR_INVALIDDATA;
364
17.5k
    }
365
366
16.2k
    return 0;
367
17.5k
}
368
369
static int cinepak_decode (CinepakContext *s)
370
15.5k
{
371
15.5k
    const uint8_t  *eod = (s->data + s->size);
372
15.5k
    int           i, result, strip_size, frame_flags, num_strips;
373
15.5k
    int           y0 = 0;
374
375
15.5k
    frame_flags = s->data[0];
376
15.5k
    num_strips  = AV_RB16 (&s->data[8]);
377
378
15.5k
    s->data += 10 + s->sega_film_skip_bytes;
379
380
15.5k
    num_strips = FFMIN(num_strips, MAX_STRIPS);
381
382
15.5k
    s->frame->flags &= ~AV_FRAME_FLAG_KEY;
383
384
17.6k
    for (i=0; i < num_strips; i++) {
385
16.8k
        if ((s->data + 12) > eod)
386
439
            return AVERROR_INVALIDDATA;
387
388
16.4k
        s->strips[i].id = s->data[0];
389
/* zero y1 means "relative to the previous stripe" */
390
16.4k
        if (!(s->strips[i].y1 = AV_RB16 (&s->data[4])))
391
6.79k
            s->strips[i].y2 = (s->strips[i].y1 = y0) + AV_RB16 (&s->data[8]);
392
9.62k
        else
393
9.62k
            s->strips[i].y2 = AV_RB16 (&s->data[8]);
394
16.4k
        s->strips[i].x1 = AV_RB16 (&s->data[6]);
395
16.4k
        s->strips[i].x2 = AV_RB16 (&s->data[10]);
396
397
16.4k
        if (s->strips[i].id == 0x10)
398
203
            s->frame->flags |= AV_FRAME_FLAG_KEY;
399
400
16.4k
        strip_size = AV_RB24 (&s->data[1]) - 12;
401
16.4k
        if (strip_size < 0)
402
205
            return AVERROR_INVALIDDATA;
403
16.2k
        s->data   += 12;
404
16.2k
        strip_size = ((s->data + strip_size) > eod) ? (eod - s->data) : strip_size;
405
406
16.2k
        if ((i > 0) && !(frame_flags & 0x01)) {
407
434
            memcpy (s->strips[i].v4_codebook, s->strips[i-1].v4_codebook,
408
434
                sizeof(s->strips[i].v4_codebook));
409
434
            memcpy (s->strips[i].v1_codebook, s->strips[i-1].v1_codebook,
410
434
                sizeof(s->strips[i].v1_codebook));
411
434
        }
412
413
16.2k
        result = cinepak_decode_strip (s, &s->strips[i], s->data, strip_size);
414
415
16.2k
        if (result != 0)
416
14.1k
            return result;
417
418
2.09k
        s->data += strip_size;
419
2.09k
        y0    = s->strips[i].y2;
420
2.09k
    }
421
803
    return 0;
422
15.5k
}
423
424
static av_cold int cinepak_decode_init(AVCodecContext *avctx)
425
1.33k
{
426
1.33k
    CinepakContext *s = avctx->priv_data;
427
428
1.33k
    s->avctx = avctx;
429
1.33k
    s->width = (avctx->width + 3) & ~3;
430
1.33k
    s->height = (avctx->height + 3) & ~3;
431
432
1.33k
    s->sega_film_skip_bytes = -1;  /* uninitialized state */
433
434
    // check for paletted data
435
1.33k
    if (avctx->bits_per_coded_sample != 8) {
436
1.28k
        s->palette_video = 0;
437
1.28k
        avctx->pix_fmt = AV_PIX_FMT_RGB24;
438
1.28k
    } else {
439
52
        s->palette_video = 1;
440
52
        avctx->pix_fmt = AV_PIX_FMT_PAL8;
441
52
    }
442
443
1.33k
    s->frame = av_frame_alloc();
444
1.33k
    if (!s->frame)
445
0
        return AVERROR(ENOMEM);
446
447
1.33k
    return 0;
448
1.33k
}
449
450
static int cinepak_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
451
                                int *got_frame, AVPacket *avpkt)
452
118k
{
453
118k
    const uint8_t *buf = avpkt->data;
454
118k
    int ret = 0, buf_size = avpkt->size;
455
118k
    CinepakContext *s = avctx->priv_data;
456
118k
    int num_strips;
457
458
118k
    s->data = buf;
459
118k
    s->size = buf_size;
460
461
118k
    if (s->size < 10)
462
9.47k
        return AVERROR_INVALIDDATA;
463
464
108k
    num_strips = AV_RB16 (&s->data[8]);
465
466
    //Empty frame, do not waste time
467
108k
    if (!num_strips && (!s->palette_video || !av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, NULL)))
468
84.4k
        return buf_size;
469
470
24.3k
    if ((ret = cinepak_predecode_check(s)) < 0) {
471
8.09k
        av_log(avctx, AV_LOG_ERROR, "cinepak_predecode_check failed\n");
472
8.09k
        return ret;
473
8.09k
    }
474
475
16.2k
    if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0)
476
704
        return ret;
477
478
15.5k
    if (s->palette_video) {
479
1.86k
        ff_copy_palette(s->pal, avpkt, avctx);
480
1.86k
    }
481
482
15.5k
    if ((ret = cinepak_decode(s)) < 0) {
483
14.7k
        av_log(avctx, AV_LOG_ERROR, "cinepak_decode failed\n");
484
14.7k
    }
485
486
15.5k
    if (s->palette_video)
487
1.86k
        memcpy (s->frame->data[1], s->pal, AVPALETTE_SIZE);
488
489
15.5k
    if ((ret = av_frame_ref(rframe, s->frame)) < 0)
490
0
        return ret;
491
492
15.5k
    *got_frame = 1;
493
494
    /* report that the buffer was completely consumed */
495
15.5k
    return buf_size;
496
15.5k
}
497
498
static av_cold int cinepak_decode_end(AVCodecContext *avctx)
499
1.33k
{
500
1.33k
    CinepakContext *s = avctx->priv_data;
501
502
1.33k
    av_frame_free(&s->frame);
503
504
1.33k
    return 0;
505
1.33k
}
506
507
const FFCodec ff_cinepak_decoder = {
508
    .p.name         = "cinepak",
509
    CODEC_LONG_NAME("Cinepak"),
510
    .p.type         = AVMEDIA_TYPE_VIDEO,
511
    .p.id           = AV_CODEC_ID_CINEPAK,
512
    .priv_data_size = sizeof(CinepakContext),
513
    .init           = cinepak_decode_init,
514
    .close          = cinepak_decode_end,
515
    FF_CODEC_DECODE_CB(cinepak_decode_frame),
516
    .p.capabilities = AV_CODEC_CAP_DR1,
517
};