Browse code

Merge commit '533a6198505edd1379e1cd722852350ae4a85acc'

* commit '533a6198505edd1379e1cd722852350ae4a85acc':
innoHeim/Rsupport Screen Capture Codec decoder

Merged-by: Hendrik Leppkes <h.leppkes@gmail.com>

Hendrik Leppkes authored on 2015/10/27 21:58:44
Showing 11 changed files
... ...
@@ -27,6 +27,7 @@ version <next>:
27 27
 - shuffleframes filter
28 28
 - SDX2 DPCM decoder
29 29
 - vibrato filter
30
+- innoHeim/Rsupport Screen Capture Codec decoder
30 31
 
31 32
 
32 33
 version 2.8:
... ...
@@ -2344,6 +2344,7 @@ ra_144_encoder_select="audio_frame_queue lpc audiodsp"
2344 2344
 ra_144_decoder_select="audiodsp"
2345 2345
 ralf_decoder_select="golomb"
2346 2346
 rawvideo_decoder_select="bswapdsp"
2347
+rscc_decoder_select="zlib"
2347 2348
 rtjpeg_decoder_select="me_cmp"
2348 2349
 rv10_decoder_select="h263_decoder"
2349 2350
 rv10_encoder_select="h263_encoder"
... ...
@@ -447,6 +447,7 @@ OBJS-$(CONFIG_ROQ_ENCODER)             += roqvideoenc.o roqvideo.o elbg.o
447 447
 OBJS-$(CONFIG_ROQ_DPCM_DECODER)        += dpcm.o
448 448
 OBJS-$(CONFIG_ROQ_DPCM_ENCODER)        += roqaudioenc.o
449 449
 OBJS-$(CONFIG_RPZA_DECODER)            += rpza.o
450
+OBJS-$(CONFIG_RSCC_DECODER)            += rscc.o
450 451
 OBJS-$(CONFIG_RV10_DECODER)            += rv10.o
451 452
 OBJS-$(CONFIG_RV10_ENCODER)            += rv10enc.o
452 453
 OBJS-$(CONFIG_RV20_DECODER)            += rv10.o
... ...
@@ -280,6 +280,7 @@ void avcodec_register_all(void)
280 280
     REGISTER_DECODER(RL2,               rl2);
281 281
     REGISTER_ENCDEC (ROQ,               roq);
282 282
     REGISTER_DECODER(RPZA,              rpza);
283
+    REGISTER_DECODER(RSCC,              rscc);
283 284
     REGISTER_ENCDEC (RV10,              rv10);
284 285
     REGISTER_ENCDEC (RV20,              rv20);
285 286
     REGISTER_DECODER(RV30,              rv30);
... ...
@@ -297,6 +297,7 @@ enum AVCodecID {
297 297
     AV_CODEC_ID_DDS,
298 298
     AV_CODEC_ID_DXV,
299 299
     AV_CODEC_ID_SCREENPRESSO,
300
+    AV_CODEC_ID_RSCC,
300 301
 
301 302
     AV_CODEC_ID_Y41P = 0x8000,
302 303
     AV_CODEC_ID_AVRP,
... ...
@@ -1280,6 +1280,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
1280 1280
         .long_name = NULL_IF_CONFIG_SMALL("AVFrame to AVPacket passthrough"),
1281 1281
         .props     = AV_CODEC_PROP_LOSSLESS,
1282 1282
     },
1283
+    {
1284
+        .id        = AV_CODEC_ID_RSCC,
1285
+        .type      = AVMEDIA_TYPE_VIDEO,
1286
+        .name      = "rscc",
1287
+        .long_name = NULL_IF_CONFIG_SMALL("innoHeim/Rsupport Screen Capture Codec"),
1288
+        .props     = AV_CODEC_PROP_LOSSLESS,
1289
+    },
1283 1290
 
1284 1291
     /* image codecs */
1285 1292
     {
1286 1293
new file mode 100644
... ...
@@ -0,0 +1,284 @@
0
+/*
1
+ * innoHeim/Rsupport Screen Capture Codec
2
+ * Copyright (C) 2015 Vittorio Giovara <vittorio.giovara@gmail.com>
3
+ *
4
+ * This file is part of FFmpeg.
5
+ *
6
+ * FFmpeg is free software; you can redistribute it and/or
7
+ * modify it under the terms of the GNU Lesser General Public
8
+ * License as published by the Free Software Foundation; either
9
+ * version 2.1 of the License, or (at your option) any later version.
10
+ *
11
+ * FFmpeg is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
+ * Lesser General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Lesser General Public
17
+ * License along with FFmpeg; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ */
20
+
21
+/**
22
+ * @file
23
+ * innoHeim/Rsupport Screen Capture Codec decoder
24
+ *
25
+ * Fourcc: ISCC, RSCC
26
+ *
27
+ * Lossless codec, data stored in tiles, with optional deflate compression.
28
+ *
29
+ * Header contains the number of tiles in a frame with the tile coordinates,
30
+ * and it can be deflated or not. Similarly, pixel data comes after the header
31
+ * and a variable size value, and it can be deflated or just raw.
32
+ *
33
+ * Supports: BGRA
34
+ */
35
+
36
+#include <stdint.h>
37
+#include <string.h>
38
+#include <zlib.h>
39
+
40
+#include "libavutil/imgutils.h"
41
+#include "libavutil/internal.h"
42
+
43
+#include "avcodec.h"
44
+#include "bytestream.h"
45
+#include "internal.h"
46
+
47
+#define TILE_SIZE 8
48
+
49
+typedef struct Tile {
50
+    int x, y;
51
+    int w, h;
52
+} Tile;
53
+
54
+typedef struct RsccContext {
55
+    GetByteContext gbc;
56
+    AVFrame *reference;
57
+    Tile *tiles;
58
+    unsigned int tiles_size;
59
+
60
+    /* zlib interaction */
61
+    uint8_t *inflated_buf;
62
+    uLongf inflated_size;
63
+} RsccContext;
64
+
65
+static av_cold int rscc_init(AVCodecContext *avctx)
66
+{
67
+    RsccContext *ctx = avctx->priv_data;
68
+
69
+    /* These needs to be set to estimate uncompressed buffer */
70
+    int ret = av_image_check_size(avctx->width, avctx->height, 0, avctx);
71
+    if (ret < 0) {
72
+        av_log(avctx, AV_LOG_ERROR, "Invalid image size %dx%d.\n",
73
+               avctx->width, avctx->height);
74
+        return ret;
75
+    }
76
+
77
+    /* Allocate reference frame */
78
+    ctx->reference = av_frame_alloc();
79
+    if (!ctx->reference)
80
+        return AVERROR(ENOMEM);
81
+
82
+    avctx->pix_fmt = AV_PIX_FMT_BGRA;
83
+
84
+    /* Store the value to check for keyframes */
85
+    ctx->inflated_size = avctx->width * avctx->height * 4;
86
+
87
+    /* Allocate maximum size possible, a full frame */
88
+    ctx->inflated_buf = av_malloc(ctx->inflated_size);
89
+    if (!ctx->inflated_buf)
90
+        return AVERROR(ENOMEM);
91
+
92
+    return 0;
93
+}
94
+
95
+static av_cold int rscc_close(AVCodecContext *avctx)
96
+{
97
+    RsccContext *ctx = avctx->priv_data;
98
+
99
+    av_freep(&ctx->tiles);
100
+    av_freep(&ctx->inflated_buf);
101
+    av_frame_free(&ctx->reference);
102
+
103
+    return 0;
104
+}
105
+
106
+static int rscc_decode_frame(AVCodecContext *avctx, void *data,
107
+                                     int *got_frame, AVPacket *avpkt)
108
+{
109
+    RsccContext *ctx = avctx->priv_data;
110
+    GetByteContext *gbc = &ctx->gbc;
111
+    GetByteContext tiles_gbc;
112
+    AVFrame *frame = data;
113
+    const uint8_t *pixels, *raw;
114
+    uint8_t *inflated_tiles = NULL;
115
+    int tiles_nb, packed_size, pixel_size = 0;
116
+    int i, ret = 0;
117
+
118
+    bytestream2_init(gbc, avpkt->data, avpkt->size);
119
+
120
+    /* Size check */
121
+    if (bytestream2_get_bytes_left(gbc) < 12) {
122
+        av_log(avctx, AV_LOG_ERROR, "Packet too small (%d)\n", avpkt->size);
123
+        return AVERROR_INVALIDDATA;
124
+    }
125
+
126
+    /* Read number of tiles, and allocate the array */
127
+    tiles_nb = bytestream2_get_le16(gbc);
128
+    av_fast_malloc(&ctx->tiles, &ctx->tiles_size,
129
+                   tiles_nb * sizeof(*ctx->tiles));
130
+    if (!ctx->tiles) {
131
+        ret = AVERROR(ENOMEM);
132
+        goto end;
133
+    }
134
+
135
+    av_log(avctx, AV_LOG_DEBUG, "Frame with %d tiles.\n", tiles_nb);
136
+
137
+    /* When there are more than 5 tiles, they are packed together with
138
+     * a size header. When that size does not match the number of tiles
139
+     * times the tile size, it means it needs to be inflated as well */
140
+    if (tiles_nb > 5) {
141
+        uLongf packed_tiles_size;
142
+
143
+        if (tiles_nb < 32)
144
+            packed_tiles_size = bytestream2_get_byte(gbc);
145
+        else
146
+            packed_tiles_size = bytestream2_get_le16(gbc);
147
+
148
+        ff_dlog(avctx, "packed tiles of size %lu.\n", packed_tiles_size);
149
+
150
+        /* If necessary, uncompress tiles, and hijack the bytestream reader */
151
+        if (packed_tiles_size != tiles_nb * TILE_SIZE) {
152
+            uLongf length = tiles_nb * TILE_SIZE;
153
+            inflated_tiles = av_malloc(length);
154
+            if (!inflated_tiles) {
155
+                ret = AVERROR(ENOMEM);
156
+                goto end;
157
+            }
158
+
159
+            ret = uncompress(inflated_tiles, &length,
160
+                             gbc->buffer, packed_tiles_size);
161
+            if (ret) {
162
+                av_log(avctx, AV_LOG_ERROR, "Tile deflate error %d.\n", ret);
163
+                ret = AVERROR_UNKNOWN;
164
+                goto end;
165
+            }
166
+
167
+            /* Skip the compressed tile section in the main byte reader,
168
+             * and point it to read the newly uncompressed data */
169
+            bytestream2_skip(gbc, packed_tiles_size);
170
+            bytestream2_init(&tiles_gbc, inflated_tiles, length);
171
+            gbc = &tiles_gbc;
172
+        }
173
+    }
174
+
175
+    /* Fill in array of tiles, keeping track of how many pixels are updated */
176
+    for (i = 0; i < tiles_nb; i++) {
177
+        ctx->tiles[i].x = bytestream2_get_le16(gbc);
178
+        ctx->tiles[i].w = bytestream2_get_le16(gbc);
179
+        ctx->tiles[i].y = bytestream2_get_le16(gbc);
180
+        ctx->tiles[i].h = bytestream2_get_le16(gbc);
181
+
182
+        pixel_size += ctx->tiles[i].w * ctx->tiles[i].h * 4;
183
+
184
+        ff_dlog(avctx, "tile %d orig(%d,%d) %dx%d.\n", i,
185
+                ctx->tiles[i].x, ctx->tiles[i].y,
186
+                ctx->tiles[i].w, ctx->tiles[i].h);
187
+
188
+        if (ctx->tiles[i].w == 0 || ctx->tiles[i].h == 0) {
189
+            av_log(avctx, AV_LOG_ERROR,
190
+                   "invalid tile %d at (%d.%d) with size %dx%d.\n", i,
191
+                   ctx->tiles[i].x, ctx->tiles[i].y,
192
+                   ctx->tiles[i].w, ctx->tiles[i].h);
193
+            ret = AVERROR_INVALIDDATA;
194
+            goto end;
195
+        } else if (ctx->tiles[i].x + ctx->tiles[i].w > avctx->width ||
196
+                   ctx->tiles[i].y + ctx->tiles[i].h > avctx->height) {
197
+            av_log(avctx, AV_LOG_ERROR,
198
+                   "out of bounds tile %d at (%d.%d) with size %dx%d.\n", i,
199
+                   ctx->tiles[i].x, ctx->tiles[i].y,
200
+                   ctx->tiles[i].w, ctx->tiles[i].h);
201
+            ret = AVERROR_INVALIDDATA;
202
+            goto end;
203
+        }
204
+    }
205
+
206
+    /* Reset the reader in case it had been modified before */
207
+    gbc = &ctx->gbc;
208
+
209
+    /* Extract how much pixel data the tiles contain */
210
+    if (pixel_size < 0x100)
211
+        packed_size = bytestream2_get_byte(gbc);
212
+    else if (pixel_size < 0x10000)
213
+        packed_size = bytestream2_get_le16(gbc);
214
+    else if (pixel_size < 0x1000000)
215
+        packed_size = bytestream2_get_le24(gbc);
216
+    else
217
+        packed_size = bytestream2_get_le32(gbc);
218
+
219
+    ff_dlog(avctx, "pixel_size %d packed_size %d.\n", pixel_size, packed_size);
220
+
221
+    /* Get pixels buffer, it may be deflated or just raw */
222
+    if (pixel_size == packed_size) {
223
+        pixels = gbc->buffer;
224
+    } else {
225
+        uLongf len = ctx->inflated_size;
226
+        ret = uncompress(ctx->inflated_buf, &len, gbc->buffer, packed_size);
227
+        if (ret) {
228
+            av_log(avctx, AV_LOG_ERROR, "Pixel deflate error %d.\n", ret);
229
+            ret = AVERROR_UNKNOWN;
230
+            goto end;
231
+        }
232
+        pixels = ctx->inflated_buf;
233
+    }
234
+
235
+    /* Allocate when needed */
236
+    ret = ff_reget_buffer(avctx, ctx->reference);
237
+    if (ret < 0)
238
+        goto end;
239
+
240
+    /* Pointer to actual pixels, will be updated when data is consumed */
241
+    raw = pixels;
242
+    for (i = 0; i < tiles_nb; i++) {
243
+        uint8_t *dst = ctx->reference->data[0] + ctx->reference->linesize[0] *
244
+                       (avctx->height - ctx->tiles[i].y - 1) +
245
+                       ctx->tiles[i].x * 4;
246
+        av_image_copy_plane(dst, -1 * ctx->reference->linesize[0],
247
+                            raw, ctx->tiles[i].w * 4,
248
+                            ctx->tiles[i].w * 4, ctx->tiles[i].h);
249
+        raw += ctx->tiles[i].w * 4 * ctx->tiles[i].h;
250
+    }
251
+
252
+    /* Frame is ready to be output */
253
+    ret = av_frame_ref(frame, ctx->reference);
254
+    if (ret < 0)
255
+        goto end;
256
+
257
+    /* Keyframe when the number of pixels updated matches the whole surface */
258
+    if (pixel_size == ctx->inflated_size) {
259
+        frame->pict_type = AV_PICTURE_TYPE_I;
260
+        frame->key_frame = 1;
261
+    } else {
262
+        frame->pict_type = AV_PICTURE_TYPE_P;
263
+    }
264
+    *got_frame = 1;
265
+
266
+end:
267
+    av_free(inflated_tiles);
268
+    return ret;
269
+}
270
+
271
+AVCodec ff_rscc_decoder = {
272
+    .name           = "rscc",
273
+    .long_name      = NULL_IF_CONFIG_SMALL("innoHeim/Rsupport Screen Capture Codec"),
274
+    .type           = AVMEDIA_TYPE_VIDEO,
275
+    .id             = AV_CODEC_ID_RSCC,
276
+    .init           = rscc_init,
277
+    .decode         = rscc_decode_frame,
278
+    .close          = rscc_close,
279
+    .priv_data_size = sizeof(RsccContext),
280
+    .capabilities   = AV_CODEC_CAP_DR1,
281
+    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE |
282
+                      FF_CODEC_CAP_INIT_CLEANUP,
283
+};
... ...
@@ -29,7 +29,7 @@
29 29
 #include "libavutil/version.h"
30 30
 
31 31
 #define LIBAVCODEC_VERSION_MAJOR  57
32
-#define LIBAVCODEC_VERSION_MINOR  10
32
+#define LIBAVCODEC_VERSION_MINOR  11
33 33
 #define LIBAVCODEC_VERSION_MICRO 100
34 34
 
35 35
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
... ...
@@ -375,6 +375,8 @@ const AVCodecTag ff_codec_bmp_tags[] = {
375 375
     { AV_CODEC_ID_HQ_HQA,       MKTAG('C', 'U', 'V', 'C') },
376 376
     { AV_CODEC_ID_RV40,         MKTAG('R', 'V', '4', '0') },
377 377
     { AV_CODEC_ID_SCREENPRESSO, MKTAG('S', 'P', 'V', '1') },
378
+    { AV_CODEC_ID_RSCC,         MKTAG('R', 'S', 'C', 'C') },
379
+    { AV_CODEC_ID_RSCC,         MKTAG('I', 'S', 'C', 'C') },
378 380
     { AV_CODEC_ID_NONE,         0 }
379 381
 };
380 382
 
... ...
@@ -41,6 +41,9 @@ fate-g2m4: CMD = framecrc -idct simple -i $(TARGET_SAMPLES)/g2m/g2m4.asf
41 41
 FATE_SAMPLES_AVCONV-$(call DEMDEC, ASF, G2M) += $(FATE_G2M)
42 42
 fate-g2m: $(FATE_G2M)
43 43
 
44
+FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, RSCC) += fate-rscc
45
+fate-rscc: CMD = framecrc -i $(TARGET_SAMPLES)/rscc/pip.avi -an
46
+
44 47
 FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, SCREENPRESSO) += fate-screenpresso
45 48
 fate-screenpresso: CMD = framecrc -i $(TARGET_SAMPLES)/spv1/bunny.avi
46 49
 
47 50
new file mode 100644
... ...
@@ -0,0 +1,6 @@
0
+#tb 0: 1/10
1
+0,          0,          0,        1,  6814720, 0x1365f8ef
2
+0,          1,          1,        1,  6814720, 0x90838983
3
+0,          2,          2,        1,  6814720, 0xf0cc3131
4
+0,          3,          3,        1,  6814720, 0xc07e404d
5
+0,          4,          4,        1,  6814720, 0x945962dd