GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavcodec/cdxl.c Lines: 158 192 82.3 %
Date: 2021-04-20 15:25:36 Branches: 66 110 60.0 %

Line Branch Exec Source
1
/*
2
 * CDXL video decoder
3
 * Copyright (c) 2011-2012 Paul B Mahol
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
 * Commodore CDXL video decoder
25
 * @author Paul B Mahol
26
 */
27
28
#define UNCHECKED_BITSTREAM_READER 1
29
30
#include "libavutil/intreadwrite.h"
31
#include "libavutil/imgutils.h"
32
#include "avcodec.h"
33
#include "bytestream.h"
34
#include "get_bits.h"
35
#include "internal.h"
36
37
#define BIT_PLANAR   0x00
38
#define CHUNKY       0x20
39
#define BYTE_PLANAR  0x40
40
#define BIT_LINE     0x80
41
#define BYTE_LINE    0xC0
42
43
typedef struct CDXLVideoContext {
44
    AVCodecContext *avctx;
45
    int            bpp;
46
    int            type;
47
    int            format;
48
    int            padded_bits;
49
    const uint8_t  *palette;
50
    int            palette_size;
51
    const uint8_t  *video;
52
    int            video_size;
53
    uint8_t        *new_video;
54
    int            new_video_size;
55
} CDXLVideoContext;
56
57
11
static av_cold int cdxl_decode_init(AVCodecContext *avctx)
58
{
59
11
    CDXLVideoContext *c = avctx->priv_data;
60
61
11
    c->new_video_size = 0;
62
11
    c->avctx          = avctx;
63
64
11
    return 0;
65
}
66
67
90
static void import_palette(CDXLVideoContext *c, uint32_t *new_palette)
68
{
69
90
    if (c->type == 1) {
70
4554
        for (int i = 0; i < c->palette_size / 2; i++) {
71
4464
            unsigned rgb = AV_RB16(&c->palette[i * 2]);
72
4464
            unsigned r   = ((rgb >> 8) & 0xF) * 0x11;
73
4464
            unsigned g   = ((rgb >> 4) & 0xF) * 0x11;
74
4464
            unsigned b   =  (rgb       & 0xF) * 0x11;
75
4464
            AV_WN32(&new_palette[i], (0xFFU << 24) | (r << 16) | (g << 8) | b);
76
        }
77
    } else {
78
        for (int i = 0; i < c->palette_size / 3; i++) {
79
            unsigned rgb = AV_RB24(&c->palette[i * 3]);
80
            AV_WN32(&new_palette[i], (0xFFU << 24) | rgb);
81
        }
82
    }
83
90
}
84
85
79
static void bitplanar2chunky(CDXLVideoContext *c, int linesize, uint8_t *out)
86
{
87
    GetBitContext gb;
88
    int x, y, plane;
89
90
79
    if (init_get_bits8(&gb, c->video, c->video_size) < 0)
91
        return;
92
489
    for (plane = 0; plane < c->bpp; plane++) {
93
43050
        for (y = 0; y < c->avctx->height; y++) {
94
6629520
            for (x = 0; x < c->avctx->width; x++)
95
6586880
                out[linesize * y + x] |= get_bits1(&gb) << plane;
96
42640
            skip_bits(&gb, c->padded_bits);
97
        }
98
    }
99
}
100
101
11
static void bitline2chunky(CDXLVideoContext *c, int linesize, uint8_t *out)
102
{
103
    GetBitContext  gb;
104
    int x, y, plane;
105
106
11
    if (init_get_bits8(&gb, c->video, c->video_size) < 0)
107
        return;
108
1441
    for (y = 0; y < c->avctx->height; y++) {
109
10010
        for (plane = 0; plane < c->bpp; plane++) {
110
1398540
            for (x = 0; x < c->avctx->width; x++)
111
1389960
                out[linesize * y + x] |= get_bits1(&gb) << plane;
112
8580
            skip_bits(&gb, c->padded_bits);
113
        }
114
    }
115
}
116
117
static void chunky2chunky(CDXLVideoContext *c, int linesize, uint8_t *out)
118
{
119
    GetByteContext gb;
120
    int y;
121
122
    bytestream2_init(&gb, c->video, c->video_size);
123
    for (y = 0; y < c->avctx->height; y++) {
124
        bytestream2_get_buffer(&gb, out + linesize * y, c->avctx->width * 3);
125
    }
126
}
127
128
90
static void import_format(CDXLVideoContext *c, int linesize, uint8_t *out)
129
{
130
90
    memset(out, 0, linesize * c->avctx->height);
131
132

90
    switch (c->format) {
133
79
    case BIT_PLANAR:
134
79
        bitplanar2chunky(c, linesize, out);
135
79
        break;
136
11
    case BIT_LINE:
137
11
        bitline2chunky(c, linesize, out);
138
11
        break;
139
    case CHUNKY:
140
        chunky2chunky(c, linesize, out);
141
        break;
142
    }
143
90
}
144
145
59
static void cdxl_decode_rgb(CDXLVideoContext *c, AVFrame *frame)
146
{
147
59
    uint32_t *new_palette = (uint32_t *)frame->data[1];
148
149
59
    memset(frame->data[1], 0, AVPALETTE_SIZE);
150
59
    import_palette(c, new_palette);
151
59
    import_format(c, frame->linesize[0], frame->data[0]);
152
59
}
153
154
static void cdxl_decode_raw(CDXLVideoContext *c, AVFrame *frame)
155
{
156
    import_format(c, frame->linesize[0], frame->data[0]);
157
}
158
159
28
static void cdxl_decode_ham6(CDXLVideoContext *c, AVFrame *frame)
160
{
161
28
    AVCodecContext *avctx = c->avctx;
162
    uint32_t new_palette[16], r, g, b;
163
    uint8_t *ptr, *out, index, op;
164
    int x, y;
165
166
28
    ptr = c->new_video;
167
28
    out = frame->data[0];
168
169
28
    import_palette(c, new_palette);
170
28
    import_format(c, avctx->width, c->new_video);
171
172
3498
    for (y = 0; y < avctx->height; y++) {
173
3470
        r = new_palette[0] & 0xFF0000;
174
3470
        g = new_palette[0] & 0xFF00;
175
3470
        b = new_palette[0] & 0xFF;
176
561530
        for (x = 0; x < avctx->width; x++) {
177
558060
            index  = *ptr++;
178
558060
            op     = index >> 4;
179
558060
            index &= 15;
180

558060
            switch (op) {
181
131279
            case 0:
182
131279
                r = new_palette[index] & 0xFF0000;
183
131279
                g = new_palette[index] & 0xFF00;
184
131279
                b = new_palette[index] & 0xFF;
185
131279
                break;
186
108493
            case 1:
187
108493
                b = index * 0x11;
188
108493
                break;
189
212370
            case 2:
190
212370
                r = index * 0x11 << 16;
191
212370
                break;
192
105918
            case 3:
193
105918
                g = index * 0x11 << 8;
194
105918
                break;
195
            }
196
558060
            AV_WL24(out + x * 3, r | g | b);
197
        }
198
3470
        out += frame->linesize[0];
199
    }
200
28
}
201
202
3
static void cdxl_decode_ham8(CDXLVideoContext *c, AVFrame *frame)
203
{
204
3
    AVCodecContext *avctx = c->avctx;
205
    uint32_t new_palette[64], r, g, b;
206
    uint8_t *ptr, *out, index, op;
207
    int x, y;
208
209
3
    ptr = c->new_video;
210
3
    out = frame->data[0];
211
212
3
    import_palette(c, new_palette);
213
3
    import_format(c, avctx->width, c->new_video);
214
215
387
    for (y = 0; y < avctx->height; y++) {
216
384
        r = new_palette[0] & 0xFF0000;
217
384
        g = new_palette[0] & 0xFF00;
218
384
        b = new_palette[0] & 0xFF;
219
67968
        for (x = 0; x < avctx->width; x++) {
220
67584
            index  = *ptr++;
221
67584
            op     = index >> 6;
222
67584
            index &= 63;
223

67584
            switch (op) {
224
3417
            case 0:
225
3417
                r = new_palette[index] & 0xFF0000;
226
3417
                g = new_palette[index] & 0xFF00;
227
3417
                b = new_palette[index] & 0xFF;
228
3417
                break;
229
627
            case 1:
230
627
                b = (index <<  2) | (b & 3);
231
627
                break;
232
1122
            case 2:
233
1122
                r = (index << 18) | (r & (3 << 16));
234
1122
                break;
235
62418
            case 3:
236
62418
                g = (index << 10) | (g & (3 << 8));
237
62418
                break;
238
            }
239
67584
            AV_WL24(out + x * 3, r | g | b);
240
        }
241
384
        out += frame->linesize[0];
242
    }
243
3
}
244
245
90
static int cdxl_decode_frame(AVCodecContext *avctx, void *data,
246
                             int *got_frame, AVPacket *pkt)
247
{
248
90
    CDXLVideoContext *c = avctx->priv_data;
249
90
    AVFrame * const p = data;
250
90
    int ret, w, h, encoding, aligned_width, buf_size = pkt->size;
251
90
    const uint8_t *buf = pkt->data;
252
253
90
    if (buf_size < 32)
254
        return AVERROR_INVALIDDATA;
255
90
    c->type         = buf[0];
256
90
    encoding        = buf[1] & 7;
257
90
    c->format       = buf[1] & 0xE0;
258
90
    w               = AV_RB16(&buf[14]);
259
90
    h               = AV_RB16(&buf[16]);
260
90
    c->bpp          = buf[19];
261
90
    c->palette_size = AV_RB16(&buf[20]);
262
90
    c->palette      = buf + 32;
263
90
    c->video        = c->palette + c->palette_size;
264
90
    c->video_size   = buf_size - c->palette_size - 32;
265
266
90
    if (c->type > 1)
267
        return AVERROR_INVALIDDATA;
268

90
    if (c->type == 1 && c->palette_size > 512)
269
        return AVERROR_INVALIDDATA;
270

90
    if (c->type == 0 && c->palette_size > 768)
271
        return AVERROR_INVALIDDATA;
272
90
    if (buf_size < c->palette_size + 32)
273
        return AVERROR_INVALIDDATA;
274
90
    if (c->bpp < 1)
275
        return AVERROR_INVALIDDATA;
276

90
    if (c->format != BIT_PLANAR && c->format != BIT_LINE && c->format != CHUNKY) {
277
        avpriv_request_sample(avctx, "Pixel format 0x%0x", c->format);
278
        return AVERROR_PATCHWELCOME;
279
    }
280
281
90
    if ((ret = ff_set_dimensions(avctx, w, h)) < 0)
282
        return ret;
283
284
90
    if (c->format == CHUNKY)
285
        aligned_width = avctx->width;
286
    else
287
90
        aligned_width = FFALIGN(c->avctx->width, 16);
288
90
    c->padded_bits  = aligned_width - c->avctx->width;
289
90
    if (c->video_size < aligned_width * avctx->height * (int64_t)c->bpp / 8)
290
        return AVERROR_INVALIDDATA;
291


90
    if (!encoding && c->palette_size && c->bpp <= 8 && c->format != CHUNKY) {
292
59
        avctx->pix_fmt = AV_PIX_FMT_PAL8;
293


31
    } else if (encoding == 1 && (c->bpp == 6 || c->bpp == 8) && c->format != CHUNKY) {
294
31
        if (c->palette_size != (1 << (c->bpp - 1)))
295
            return AVERROR_INVALIDDATA;
296
31
        avctx->pix_fmt = AV_PIX_FMT_BGR24;
297
    } else if (!encoding && c->bpp == 24 && c->format == CHUNKY &&
298
               !c->palette_size) {
299
        avctx->pix_fmt = AV_PIX_FMT_RGB24;
300
    } else {
301
        avpriv_request_sample(avctx, "Encoding %d, bpp %d and format 0x%x",
302
                              encoding, c->bpp, c->format);
303
        return AVERROR_PATCHWELCOME;
304
    }
305
306
90
    if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
307
        return ret;
308
90
    p->pict_type = AV_PICTURE_TYPE_I;
309
90
    p->key_frame = 1;
310
311
90
    if (encoding) {
312
31
        av_fast_padded_malloc(&c->new_video, &c->new_video_size,
313
31
                              h * w + AV_INPUT_BUFFER_PADDING_SIZE);
314
31
        if (!c->new_video)
315
            return AVERROR(ENOMEM);
316
31
        if (c->bpp == 8)
317
3
            cdxl_decode_ham8(c, p);
318
        else
319
28
            cdxl_decode_ham6(c, p);
320
59
    } else if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
321
59
        cdxl_decode_rgb(c, p);
322
    } else {
323
        cdxl_decode_raw(c, p);
324
    }
325
90
    *got_frame = 1;
326
327
90
    return buf_size;
328
}
329
330
11
static av_cold int cdxl_decode_end(AVCodecContext *avctx)
331
{
332
11
    CDXLVideoContext *c = avctx->priv_data;
333
334
11
    av_freep(&c->new_video);
335
336
11
    return 0;
337
}
338
339
AVCodec ff_cdxl_decoder = {
340
    .name           = "cdxl",
341
    .long_name      = NULL_IF_CONFIG_SMALL("Commodore CDXL video"),
342
    .type           = AVMEDIA_TYPE_VIDEO,
343
    .id             = AV_CODEC_ID_CDXL,
344
    .priv_data_size = sizeof(CDXLVideoContext),
345
    .init           = cdxl_decode_init,
346
    .close          = cdxl_decode_end,
347
    .decode         = cdxl_decode_frame,
348
    .capabilities   = AV_CODEC_CAP_DR1,
349
    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
350
};