GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavcodec/rscc.c Lines: 120 178 67.4 %
Date: 2021-04-22 14:24:15 Branches: 51 83 61.4 %

Line Branch Exec Source
1
/*
2
 * innoHeim/Rsupport Screen Capture Codec
3
 * Copyright (C) 2015 Vittorio Giovara <vittorio.giovara@gmail.com>
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
 * innoHeim/Rsupport Screen Capture Codec decoder
25
 *
26
 * Fourcc: ISCC, RSCC
27
 *
28
 * Lossless codec, data stored in tiles, with optional deflate compression.
29
 *
30
 * Header contains the number of tiles in a frame with the tile coordinates,
31
 * and it can be deflated or not. Similarly, pixel data comes after the header
32
 * and a variable size value, and it can be deflated or just raw.
33
 *
34
 * Supports: PAL8, BGRA, BGR24, RGB555
35
 */
36
37
#include <stdint.h>
38
#include <string.h>
39
#include <zlib.h>
40
41
#include "libavutil/imgutils.h"
42
#include "libavutil/internal.h"
43
44
#include "avcodec.h"
45
#include "bytestream.h"
46
#include "decode.h"
47
#include "internal.h"
48
49
#define TILE_SIZE 8
50
51
typedef struct Tile {
52
    int x, y;
53
    int w, h;
54
} Tile;
55
56
typedef struct RsccContext {
57
    GetByteContext gbc;
58
    AVFrame *reference;
59
    Tile *tiles;
60
    unsigned int tiles_size;
61
    int component_size;
62
63
    uint8_t palette[AVPALETTE_SIZE];
64
65
    /* zlib interaction */
66
    uint8_t *inflated_buf;
67
    uLongf inflated_size;
68
    int valid_pixels;
69
} RsccContext;
70
71
10
static av_cold int rscc_init(AVCodecContext *avctx)
72
{
73
10
    RsccContext *ctx = avctx->priv_data;
74
75
    /* These needs to be set to estimate uncompressed buffer */
76
10
    int ret = av_image_check_size(avctx->width, avctx->height, 0, avctx);
77
10
    if (ret < 0) {
78
        av_log(avctx, AV_LOG_ERROR, "Invalid image size %dx%d.\n",
79
               avctx->width, avctx->height);
80
        return ret;
81
    }
82
83
    /* Allocate reference frame */
84
10
    ctx->reference = av_frame_alloc();
85
10
    if (!ctx->reference)
86
        return AVERROR(ENOMEM);
87
88
    /* Get pixel format and the size of the pixel */
89
10
    if (avctx->codec_tag == MKTAG('I', 'S', 'C', 'C')) {
90

2
        if (avctx->extradata && avctx->extradata_size == 4) {
91
2
            if ((avctx->extradata[0] >> 1) & 1) {
92
2
                avctx->pix_fmt = AV_PIX_FMT_BGRA;
93
2
                ctx->component_size = 4;
94
            } else {
95
                avctx->pix_fmt = AV_PIX_FMT_BGR24;
96
                ctx->component_size = 3;
97
            }
98
        } else {
99
            avctx->pix_fmt = AV_PIX_FMT_BGRA;
100
            ctx->component_size = 4;
101
        }
102
8
    } else if (avctx->codec_tag == MKTAG('R', 'S', 'C', 'C')) {
103
8
        ctx->component_size = avctx->bits_per_coded_sample / 8;
104

8
        switch (avctx->bits_per_coded_sample) {
105
2
        case 8:
106
2
            avctx->pix_fmt = AV_PIX_FMT_PAL8;
107
2
            break;
108
2
        case 16:
109
2
            avctx->pix_fmt = AV_PIX_FMT_RGB555LE;
110
2
            break;
111
2
        case 24:
112
2
            avctx->pix_fmt = AV_PIX_FMT_BGR24;
113
2
            break;
114
2
        case 32:
115
2
            avctx->pix_fmt = AV_PIX_FMT_BGR0;
116
2
            break;
117
        default:
118
            av_log(avctx, AV_LOG_ERROR, "Invalid bits per pixel value (%d)\n",
119
                   avctx->bits_per_coded_sample);
120
            return AVERROR_INVALIDDATA;
121
        }
122
    } else {
123
        avctx->pix_fmt = AV_PIX_FMT_BGR0;
124
        ctx->component_size = 4;
125
        av_log(avctx, AV_LOG_WARNING, "Invalid codec tag\n");
126
    }
127
128
    /* Store the value to check for keyframes */
129
10
    ctx->inflated_size = avctx->width * avctx->height * ctx->component_size;
130
131
    /* Allocate maximum size possible, a full frame */
132
10
    ctx->inflated_buf = av_malloc(ctx->inflated_size);
133
10
    if (!ctx->inflated_buf)
134
        return AVERROR(ENOMEM);
135
136
10
    return 0;
137
}
138
139
10
static av_cold int rscc_close(AVCodecContext *avctx)
140
{
141
10
    RsccContext *ctx = avctx->priv_data;
142
143
10
    av_freep(&ctx->tiles);
144
10
    av_freep(&ctx->inflated_buf);
145
10
    av_frame_free(&ctx->reference);
146
147
10
    return 0;
148
}
149
150
32
static int rscc_decode_frame(AVCodecContext *avctx, void *data,
151
                                     int *got_frame, AVPacket *avpkt)
152
{
153
32
    RsccContext *ctx = avctx->priv_data;
154
32
    GetByteContext *gbc = &ctx->gbc;
155
    GetByteContext tiles_gbc;
156
32
    AVFrame *frame = data;
157
    const uint8_t *pixels, *raw;
158
32
    uint8_t *inflated_tiles = NULL;
159
32
    int tiles_nb, packed_size, pixel_size = 0;
160
32
    int i, ret = 0;
161
162
32
    bytestream2_init(gbc, avpkt->data, avpkt->size);
163
164
    /* Size check */
165
32
    if (bytestream2_get_bytes_left(gbc) < 12) {
166
        av_log(avctx, AV_LOG_ERROR, "Packet too small (%d)\n", avpkt->size);
167
        return AVERROR_INVALIDDATA;
168
    }
169
170
    /* Read number of tiles, and allocate the array */
171
32
    tiles_nb = bytestream2_get_le16(gbc);
172
173
32
    if (tiles_nb == 0) {
174
        av_log(avctx, AV_LOG_DEBUG, "no tiles\n");
175
        return avpkt->size;
176
    }
177
178
32
    av_fast_malloc(&ctx->tiles, &ctx->tiles_size,
179
                   tiles_nb * sizeof(*ctx->tiles));
180
32
    if (!ctx->tiles) {
181
        ret = AVERROR(ENOMEM);
182
        goto end;
183
    }
184
185
32
    av_log(avctx, AV_LOG_DEBUG, "Frame with %d tiles.\n", tiles_nb);
186
187
    /* When there are more than 5 tiles, they are packed together with
188
     * a size header. When that size does not match the number of tiles
189
     * times the tile size, it means it needs to be inflated as well */
190
32
    if (tiles_nb > 5) {
191
        uLongf packed_tiles_size;
192
193
24
        if (tiles_nb < 32)
194
17
            packed_tiles_size = bytestream2_get_byte(gbc);
195
        else
196
7
            packed_tiles_size = bytestream2_get_le16(gbc);
197
198
        ff_dlog(avctx, "packed tiles of size %lu.\n", packed_tiles_size);
199
200
        /* If necessary, uncompress tiles, and hijack the bytestream reader */
201
24
        if (packed_tiles_size != tiles_nb * TILE_SIZE) {
202
24
            uLongf length = tiles_nb * TILE_SIZE;
203
204
24
            if (bytestream2_get_bytes_left(gbc) < packed_tiles_size) {
205
                ret = AVERROR_INVALIDDATA;
206
                goto end;
207
            }
208
209
24
            inflated_tiles = av_malloc(length);
210
24
            if (!inflated_tiles) {
211
                ret = AVERROR(ENOMEM);
212
                goto end;
213
            }
214
215
24
            ret = uncompress(inflated_tiles, &length,
216
24
                             gbc->buffer, packed_tiles_size);
217
24
            if (ret) {
218
                av_log(avctx, AV_LOG_ERROR, "Tile deflate error %d.\n", ret);
219
                ret = AVERROR_UNKNOWN;
220
                goto end;
221
            }
222
223
            /* Skip the compressed tile section in the main byte reader,
224
             * and point it to read the newly uncompressed data */
225
24
            bytestream2_skip(gbc, packed_tiles_size);
226
24
            bytestream2_init(&tiles_gbc, inflated_tiles, length);
227
24
            gbc = &tiles_gbc;
228
        }
229
    }
230
231
    /* Fill in array of tiles, keeping track of how many pixels are updated */
232
712
    for (i = 0; i < tiles_nb; i++) {
233
680
        ctx->tiles[i].x = bytestream2_get_le16(gbc);
234
680
        ctx->tiles[i].w = bytestream2_get_le16(gbc);
235
680
        ctx->tiles[i].y = bytestream2_get_le16(gbc);
236
680
        ctx->tiles[i].h = bytestream2_get_le16(gbc);
237
238
680
        if (pixel_size + ctx->tiles[i].w * (int64_t)ctx->tiles[i].h * ctx->component_size > INT_MAX) {
239
            av_log(avctx, AV_LOG_ERROR, "Invalid tile dimensions\n");
240
            ret = AVERROR_INVALIDDATA;
241
            goto end;
242
        }
243
244
680
        pixel_size += ctx->tiles[i].w * ctx->tiles[i].h * ctx->component_size;
245
246
        ff_dlog(avctx, "tile %d orig(%d,%d) %dx%d.\n", i,
247
                ctx->tiles[i].x, ctx->tiles[i].y,
248
                ctx->tiles[i].w, ctx->tiles[i].h);
249
250

680
        if (ctx->tiles[i].w == 0 || ctx->tiles[i].h == 0) {
251
            av_log(avctx, AV_LOG_ERROR,
252
                   "invalid tile %d at (%d.%d) with size %dx%d.\n", i,
253
                   ctx->tiles[i].x, ctx->tiles[i].y,
254
                   ctx->tiles[i].w, ctx->tiles[i].h);
255
            ret = AVERROR_INVALIDDATA;
256
            goto end;
257
680
        } else if (ctx->tiles[i].x + ctx->tiles[i].w > avctx->width ||
258
680
                   ctx->tiles[i].y + ctx->tiles[i].h > avctx->height) {
259
            av_log(avctx, AV_LOG_ERROR,
260
                   "out of bounds tile %d at (%d.%d) with size %dx%d.\n", i,
261
                   ctx->tiles[i].x, ctx->tiles[i].y,
262
                   ctx->tiles[i].w, ctx->tiles[i].h);
263
            ret = AVERROR_INVALIDDATA;
264
            goto end;
265
        }
266
    }
267
268
    /* Reset the reader in case it had been modified before */
269
32
    gbc = &ctx->gbc;
270
271
    /* Extract how much pixel data the tiles contain */
272
32
    if (pixel_size < 0x100)
273
        packed_size = bytestream2_get_byte(gbc);
274
32
    else if (pixel_size < 0x10000)
275
        packed_size = bytestream2_get_le16(gbc);
276
32
    else if (pixel_size < 0x1000000)
277
32
        packed_size = bytestream2_get_le24(gbc);
278
    else
279
        packed_size = bytestream2_get_le32(gbc);
280
281
    ff_dlog(avctx, "pixel_size %d packed_size %d.\n", pixel_size, packed_size);
282
283
32
    if (packed_size < 0) {
284
        av_log(avctx, AV_LOG_ERROR, "Invalid tile size %d\n", packed_size);
285
        ret = AVERROR_INVALIDDATA;
286
        goto end;
287
    }
288
289
    /* Get pixels buffer, it may be deflated or just raw */
290
32
    if (pixel_size == packed_size) {
291
        if (bytestream2_get_bytes_left(gbc) < pixel_size) {
292
            av_log(avctx, AV_LOG_ERROR, "Insufficient input for %d\n", pixel_size);
293
            ret = AVERROR_INVALIDDATA;
294
            goto end;
295
        }
296
        pixels = gbc->buffer;
297
    } else {
298
32
        uLongf len = ctx->inflated_size;
299
32
        if (bytestream2_get_bytes_left(gbc) < packed_size) {
300
2
            av_log(avctx, AV_LOG_ERROR, "Insufficient input for %d\n", packed_size);
301
2
            ret = AVERROR_INVALIDDATA;
302
2
            goto end;
303
        }
304
30
        if (ctx->inflated_size < pixel_size) {
305
            ret = AVERROR_INVALIDDATA;
306
            goto end;
307
        }
308
30
        ret = uncompress(ctx->inflated_buf, &len, gbc->buffer, packed_size);
309
30
        if (ret) {
310
            av_log(avctx, AV_LOG_ERROR, "Pixel deflate error %d.\n", ret);
311
            ret = AVERROR_UNKNOWN;
312
            goto end;
313
        }
314
30
        pixels = ctx->inflated_buf;
315
    }
316
317
    /* Allocate when needed */
318
30
    ret = ff_reget_buffer(avctx, ctx->reference, 0);
319
30
    if (ret < 0)
320
        goto end;
321
322
    /* Pointer to actual pixels, will be updated when data is consumed */
323
30
    raw = pixels;
324
694
    for (i = 0; i < tiles_nb; i++) {
325
664
        uint8_t *dst = ctx->reference->data[0] + ctx->reference->linesize[0] *
326
664
                       (avctx->height - ctx->tiles[i].y - 1) +
327
664
                       ctx->tiles[i].x * ctx->component_size;
328
664
        av_image_copy_plane(dst, -1 * ctx->reference->linesize[0],
329
664
                            raw, ctx->tiles[i].w * ctx->component_size,
330
664
                            ctx->tiles[i].w * ctx->component_size,
331
664
                            ctx->tiles[i].h);
332
664
        raw += ctx->tiles[i].w * ctx->component_size * ctx->tiles[i].h;
333
    }
334
335
    /* Frame is ready to be output */
336
30
    ret = av_frame_ref(frame, ctx->reference);
337
30
    if (ret < 0)
338
        goto end;
339
340
    /* Keyframe when the number of pixels updated matches the whole surface */
341
30
    if (pixel_size == ctx->inflated_size) {
342
5
        frame->pict_type = AV_PICTURE_TYPE_I;
343
5
        frame->key_frame = 1;
344
    } else {
345
25
        frame->pict_type = AV_PICTURE_TYPE_P;
346
    }
347
348
    /* Palette handling */
349
30
    if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
350
1
        frame->palette_has_changed = ff_copy_palette(ctx->palette, avpkt, avctx);
351
1
        memcpy(frame->data[1], ctx->palette, AVPALETTE_SIZE);
352
    }
353
    // We only return a picture when enough of it is undamaged, this avoids copying nearly broken frames around
354
30
    if (ctx->valid_pixels < ctx->inflated_size)
355
5
        ctx->valid_pixels += pixel_size;
356
30
    if (ctx->valid_pixels >= ctx->inflated_size * (100 - avctx->discard_damaged_percentage) / 100)
357
30
        *got_frame = 1;
358
359
30
    ret = avpkt->size;
360
32
end:
361
32
    av_free(inflated_tiles);
362
32
    return ret;
363
}
364
365
AVCodec ff_rscc_decoder = {
366
    .name           = "rscc",
367
    .long_name      = NULL_IF_CONFIG_SMALL("innoHeim/Rsupport Screen Capture Codec"),
368
    .type           = AVMEDIA_TYPE_VIDEO,
369
    .id             = AV_CODEC_ID_RSCC,
370
    .init           = rscc_init,
371
    .decode         = rscc_decode_frame,
372
    .close          = rscc_close,
373
    .priv_data_size = sizeof(RsccContext),
374
    .capabilities   = AV_CODEC_CAP_DR1,
375
    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE |
376
                      FF_CODEC_CAP_INIT_CLEANUP,
377
};