xref: /third_party/ffmpeg/libavcodec/rscc.c (revision cabdff1a)
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 "codec_internal.h"
47#include "decode.h"
48#include "internal.h"
49
50#define TILE_SIZE 8
51
52typedef struct Tile {
53    int x, y;
54    int w, h;
55} Tile;
56
57typedef struct RsccContext {
58    GetByteContext gbc;
59    AVFrame *reference;
60    Tile *tiles;
61    unsigned int tiles_size;
62    int component_size;
63
64    uint8_t palette[AVPALETTE_SIZE];
65
66    /* zlib interaction */
67    uint8_t *inflated_buf;
68    uLongf inflated_size;
69    int valid_pixels;
70} RsccContext;
71
72static av_cold int rscc_init(AVCodecContext *avctx)
73{
74    RsccContext *ctx = avctx->priv_data;
75
76    /* These needs to be set to estimate uncompressed buffer */
77    int ret = av_image_check_size(avctx->width, avctx->height, 0, avctx);
78    if (ret < 0) {
79        av_log(avctx, AV_LOG_ERROR, "Invalid image size %dx%d.\n",
80               avctx->width, avctx->height);
81        return ret;
82    }
83
84    /* Allocate reference frame */
85    ctx->reference = av_frame_alloc();
86    if (!ctx->reference)
87        return AVERROR(ENOMEM);
88
89    /* Get pixel format and the size of the pixel */
90    if (avctx->codec_tag == MKTAG('I', 'S', 'C', 'C')) {
91        if (avctx->extradata && avctx->extradata_size == 4) {
92            if ((avctx->extradata[0] >> 1) & 1) {
93                avctx->pix_fmt = AV_PIX_FMT_BGRA;
94                ctx->component_size = 4;
95            } else {
96                avctx->pix_fmt = AV_PIX_FMT_BGR24;
97                ctx->component_size = 3;
98            }
99        } else {
100            avctx->pix_fmt = AV_PIX_FMT_BGRA;
101            ctx->component_size = 4;
102        }
103    } else if (avctx->codec_tag == MKTAG('R', 'S', 'C', 'C')) {
104        ctx->component_size = avctx->bits_per_coded_sample / 8;
105        switch (avctx->bits_per_coded_sample) {
106        case 8:
107            avctx->pix_fmt = AV_PIX_FMT_PAL8;
108            break;
109        case 16:
110            avctx->pix_fmt = AV_PIX_FMT_RGB555LE;
111            break;
112        case 24:
113            avctx->pix_fmt = AV_PIX_FMT_BGR24;
114            break;
115        case 32:
116            avctx->pix_fmt = AV_PIX_FMT_BGR0;
117            break;
118        default:
119            av_log(avctx, AV_LOG_ERROR, "Invalid bits per pixel value (%d)\n",
120                   avctx->bits_per_coded_sample);
121            return AVERROR_INVALIDDATA;
122        }
123    } else {
124        avctx->pix_fmt = AV_PIX_FMT_BGR0;
125        ctx->component_size = 4;
126        av_log(avctx, AV_LOG_WARNING, "Invalid codec tag\n");
127    }
128
129    /* Store the value to check for keyframes */
130    ctx->inflated_size = avctx->width * avctx->height * ctx->component_size;
131
132    /* Allocate maximum size possible, a full frame */
133    ctx->inflated_buf = av_malloc(ctx->inflated_size);
134    if (!ctx->inflated_buf)
135        return AVERROR(ENOMEM);
136
137    return 0;
138}
139
140static av_cold int rscc_close(AVCodecContext *avctx)
141{
142    RsccContext *ctx = avctx->priv_data;
143
144    av_freep(&ctx->tiles);
145    av_freep(&ctx->inflated_buf);
146    av_frame_free(&ctx->reference);
147
148    return 0;
149}
150
151static int rscc_decode_frame(AVCodecContext *avctx, AVFrame *frame,
152                             int *got_frame, AVPacket *avpkt)
153{
154    RsccContext *ctx = avctx->priv_data;
155    GetByteContext *gbc = &ctx->gbc;
156    GetByteContext tiles_gbc;
157    const uint8_t *pixels, *raw;
158    uint8_t *inflated_tiles = NULL;
159    int tiles_nb, packed_size, pixel_size = 0;
160    int i, ret = 0;
161
162    bytestream2_init(gbc, avpkt->data, avpkt->size);
163
164    /* Size check */
165    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    tiles_nb = bytestream2_get_le16(gbc);
172
173    if (tiles_nb == 0) {
174        av_log(avctx, AV_LOG_DEBUG, "no tiles\n");
175        return avpkt->size;
176    }
177
178    av_fast_malloc(&ctx->tiles, &ctx->tiles_size,
179                   tiles_nb * sizeof(*ctx->tiles));
180    if (!ctx->tiles) {
181        ret = AVERROR(ENOMEM);
182        goto end;
183    }
184
185    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    if (tiles_nb > 5) {
191        uLongf packed_tiles_size;
192
193        if (tiles_nb < 32)
194            packed_tiles_size = bytestream2_get_byte(gbc);
195        else
196            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        if (packed_tiles_size != tiles_nb * TILE_SIZE) {
202            uLongf length = tiles_nb * TILE_SIZE;
203
204            if (bytestream2_get_bytes_left(gbc) < packed_tiles_size) {
205                ret = AVERROR_INVALIDDATA;
206                goto end;
207            }
208
209            inflated_tiles = av_malloc(length);
210            if (!inflated_tiles) {
211                ret = AVERROR(ENOMEM);
212                goto end;
213            }
214
215            ret = uncompress(inflated_tiles, &length,
216                             gbc->buffer, packed_tiles_size);
217            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            bytestream2_skip(gbc, packed_tiles_size);
226            bytestream2_init(&tiles_gbc, inflated_tiles, length);
227            gbc = &tiles_gbc;
228        }
229    }
230
231    /* Fill in array of tiles, keeping track of how many pixels are updated */
232    for (i = 0; i < tiles_nb; i++) {
233        ctx->tiles[i].x = bytestream2_get_le16(gbc);
234        ctx->tiles[i].w = bytestream2_get_le16(gbc);
235        ctx->tiles[i].y = bytestream2_get_le16(gbc);
236        ctx->tiles[i].h = bytestream2_get_le16(gbc);
237
238        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        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        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        } else if (ctx->tiles[i].x + ctx->tiles[i].w > avctx->width ||
258                   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    gbc = &ctx->gbc;
270
271    /* Extract how much pixel data the tiles contain */
272    if (pixel_size < 0x100)
273        packed_size = bytestream2_get_byte(gbc);
274    else if (pixel_size < 0x10000)
275        packed_size = bytestream2_get_le16(gbc);
276    else if (pixel_size < 0x1000000)
277        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    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    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        uLongf len = ctx->inflated_size;
299        if (bytestream2_get_bytes_left(gbc) < packed_size) {
300            av_log(avctx, AV_LOG_ERROR, "Insufficient input for %d\n", packed_size);
301            ret = AVERROR_INVALIDDATA;
302            goto end;
303        }
304        if (ctx->inflated_size < pixel_size) {
305            ret = AVERROR_INVALIDDATA;
306            goto end;
307        }
308        ret = uncompress(ctx->inflated_buf, &len, gbc->buffer, packed_size);
309        if (ret) {
310            av_log(avctx, AV_LOG_ERROR, "Pixel deflate error %d.\n", ret);
311            ret = AVERROR_UNKNOWN;
312            goto end;
313        }
314        pixels = ctx->inflated_buf;
315    }
316
317    /* Allocate when needed */
318    ret = ff_reget_buffer(avctx, ctx->reference, 0);
319    if (ret < 0)
320        goto end;
321
322    /* Pointer to actual pixels, will be updated when data is consumed */
323    raw = pixels;
324    for (i = 0; i < tiles_nb; i++) {
325        uint8_t *dst = ctx->reference->data[0] + ctx->reference->linesize[0] *
326                       (avctx->height - ctx->tiles[i].y - 1) +
327                       ctx->tiles[i].x * ctx->component_size;
328        av_image_copy_plane(dst, -1 * ctx->reference->linesize[0],
329                            raw, ctx->tiles[i].w * ctx->component_size,
330                            ctx->tiles[i].w * ctx->component_size,
331                            ctx->tiles[i].h);
332        raw += ctx->tiles[i].w * ctx->component_size * ctx->tiles[i].h;
333    }
334
335    /* Frame is ready to be output */
336    ret = av_frame_ref(frame, ctx->reference);
337    if (ret < 0)
338        goto end;
339
340    /* Keyframe when the number of pixels updated matches the whole surface */
341    if (pixel_size == ctx->inflated_size) {
342        frame->pict_type = AV_PICTURE_TYPE_I;
343        frame->key_frame = 1;
344    } else {
345        frame->pict_type = AV_PICTURE_TYPE_P;
346    }
347
348    /* Palette handling */
349    if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
350        frame->palette_has_changed = ff_copy_palette(ctx->palette, avpkt, avctx);
351        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    if (ctx->valid_pixels < ctx->inflated_size)
355        ctx->valid_pixels += pixel_size;
356    if (ctx->valid_pixels >= ctx->inflated_size * (100 - avctx->discard_damaged_percentage) / 100)
357        *got_frame = 1;
358
359    ret = avpkt->size;
360end:
361    av_free(inflated_tiles);
362    return ret;
363}
364
365const FFCodec ff_rscc_decoder = {
366    .p.name         = "rscc",
367    .p.long_name    = NULL_IF_CONFIG_SMALL("innoHeim/Rsupport Screen Capture Codec"),
368    .p.type         = AVMEDIA_TYPE_VIDEO,
369    .p.id           = AV_CODEC_ID_RSCC,
370    .init           = rscc_init,
371    FF_CODEC_DECODE_CB(rscc_decode_frame),
372    .close          = rscc_close,
373    .priv_data_size = sizeof(RsccContext),
374    .p.capabilities = AV_CODEC_CAP_DR1,
375    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE |
376                      FF_CODEC_CAP_INIT_CLEANUP,
377};
378