Browse code

avcodec: add FM Screen Capture Codec decoder

Signed-off-by: Paul B Mahol <onemda@gmail.com>

Paul B Mahol authored on 2017/02/06 17:17:29
Showing 9 changed files
... ...
@@ -22,6 +22,7 @@ version <next>:
22 22
 - threshold filter
23 23
 - midequalizer filter
24 24
 - Optimal Huffman tables for (M)JPEG encoding
25
+- FM Screen Capture Codec decoder
25 26
 
26 27
 version 3.2:
27 28
 - libopenmpt demuxer
... ...
@@ -716,6 +716,7 @@ following image formats are supported:
716 716
 @item Flash Screen Video v2  @tab  X  @tab  X
717 717
 @item Flash Video (FLV)      @tab  X  @tab  X
718 718
     @tab Sorenson H.263 used in Flash
719
+@item FM Screen Capture Codec  @tab     @tab  X
719 720
 @item Forward Uncompressed   @tab     @tab  X
720 721
 @item Fraps                  @tab     @tab  X
721 722
 @item Go2Meeting             @tab     @tab  X
... ...
@@ -293,6 +293,7 @@ OBJS-$(CONFIG_FLASHSV_ENCODER)         += flashsvenc.o
293 293
 OBJS-$(CONFIG_FLASHSV2_ENCODER)        += flashsv2enc.o
294 294
 OBJS-$(CONFIG_FLASHSV2_DECODER)        += flashsv.o
295 295
 OBJS-$(CONFIG_FLIC_DECODER)            += flicvideo.o
296
+OBJS-$(CONFIG_FMVC_DECODER)            += fmvc.o
296 297
 OBJS-$(CONFIG_FOURXM_DECODER)          += 4xm.o
297 298
 OBJS-$(CONFIG_FRAPS_DECODER)           += fraps.o
298 299
 OBJS-$(CONFIG_FRWU_DECODER)            += frwu.o
... ...
@@ -192,6 +192,7 @@ void avcodec_register_all(void)
192 192
     REGISTER_ENCDEC (FLASHSV2,          flashsv2);
193 193
     REGISTER_DECODER(FLIC,              flic);
194 194
     REGISTER_ENCDEC (FLV,               flv);
195
+    REGISTER_DECODER(FMVC,              fmvc);
195 196
     REGISTER_DECODER(FOURXM,            fourxm);
196 197
     REGISTER_DECODER(FRAPS,             fraps);
197 198
     REGISTER_DECODER(FRWU,              frwu);
... ...
@@ -414,6 +414,7 @@ enum AVCodecID {
414 414
     AV_CODEC_ID_PSD,
415 415
     AV_CODEC_ID_PIXLET,
416 416
     AV_CODEC_ID_SPEEDHQ,
417
+    AV_CODEC_ID_FMVC,
417 418
 
418 419
     /* various PCM "codecs" */
419 420
     AV_CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at the start of audio codecs
... ...
@@ -1353,6 +1353,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
1353 1353
         .long_name = NULL_IF_CONFIG_SMALL("Apple Pixlet"),
1354 1354
         .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
1355 1355
     },
1356
+    {
1357
+        .id        = AV_CODEC_ID_FMVC,
1358
+        .type      = AVMEDIA_TYPE_VIDEO,
1359
+        .name      = "fmvc",
1360
+        .long_name = NULL_IF_CONFIG_SMALL("FM Screen Capture Codec"),
1361
+        .props     = AV_CODEC_PROP_LOSSLESS,
1362
+    },
1356 1363
 
1357 1364
     /* image codecs */
1358 1365
     {
1359 1366
new file mode 100644
... ...
@@ -0,0 +1,631 @@
0
+/*
1
+ * FM Screen Capture Codec decoder
2
+ *
3
+ * Copyright (c) 2017 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
+#include <stdio.h>
23
+#include <stdlib.h>
24
+#include <string.h>
25
+
26
+#include "avcodec.h"
27
+#include "bytestream.h"
28
+#include "internal.h"
29
+
30
+#define BLOCK_HEIGHT 112u
31
+#define BLOCK_WIDTH  84u
32
+
33
+typedef struct InterBlock {
34
+    int      w, h;
35
+    int      size;
36
+    int      xor;
37
+} InterBlock;
38
+
39
+typedef struct FMVCContext {
40
+    GetByteContext  gb;
41
+    PutByteContext  pb;
42
+    uint8_t        *buffer;
43
+    size_t          buffer_size;
44
+    uint8_t        *pbuffer;
45
+    size_t          pbuffer_size;
46
+    int             stride;
47
+    int             bpp;
48
+    int             yb, xb;
49
+    InterBlock     *blocks;
50
+    int             nb_blocks;
51
+} FMVCContext;
52
+
53
+static int decode_type2(GetByteContext *gb, PutByteContext *pb)
54
+{
55
+    unsigned repeat = 0, first = 1, opcode;
56
+    int i, len, pos;
57
+
58
+    while (bytestream2_get_bytes_left(gb) > 0) {
59
+        GetByteContext gbc;
60
+
61
+        while (bytestream2_get_bytes_left(gb) > 0) {
62
+            if (first) {
63
+                first = 0;
64
+                if (bytestream2_peek_byte(gb) > 17) {
65
+                    len = bytestream2_get_byte(gb) - 17;
66
+                    if (len < 4) {
67
+                        do {
68
+                            bytestream2_put_byte(pb, bytestream2_get_byte(gb));
69
+                            --len;
70
+                        } while (len);
71
+                        opcode = bytestream2_peek_byte(gb);
72
+                        continue;
73
+                    } else {
74
+                        do {
75
+                            bytestream2_put_byte(pb, bytestream2_get_byte(gb));
76
+                            --len;
77
+                        } while (len);
78
+                        opcode = bytestream2_peek_byte(gb);
79
+                        if (opcode < 0x10) {
80
+                            bytestream2_skip(gb, 1);
81
+                            pos = - (opcode >> 2) - 4 * bytestream2_get_byte(gb) - 2049;
82
+
83
+                            bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
84
+                            bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
85
+
86
+                            bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
87
+                            bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
88
+                            bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
89
+                            len = opcode & 3;
90
+                            if (!len) {
91
+                                repeat = 1;
92
+                            } else {
93
+                                do {
94
+                                    bytestream2_put_byte(pb, bytestream2_get_byte(gb));
95
+                                    --len;
96
+                                } while (len);
97
+                                opcode = bytestream2_peek_byte(gb);
98
+                            }
99
+                            continue;
100
+                        }
101
+                    }
102
+                    repeat = 0;
103
+                }
104
+                repeat = 1;
105
+            }
106
+            if (repeat) {
107
+                repeat = 0;
108
+                opcode = bytestream2_peek_byte(gb);
109
+                if (opcode < 0x10) {
110
+                    bytestream2_skip(gb, 1);
111
+                    if (!opcode) {
112
+                        if (!bytestream2_peek_byte(gb)) {
113
+                            do {
114
+                                bytestream2_skip(gb, 1);
115
+                                opcode += 255;
116
+                            } while (!bytestream2_peek_byte(gb) && bytestream2_get_bytes_left(gb) > 0);
117
+                        }
118
+                        opcode += bytestream2_get_byte(gb) + 15;
119
+                    }
120
+                    bytestream2_put_le32(pb, bytestream2_get_le32(gb));
121
+                    for (i = opcode - 1; i > 0; --i)
122
+                        bytestream2_put_byte(pb, bytestream2_get_byte(gb));
123
+                    opcode = bytestream2_peek_byte(gb);
124
+                    if (opcode < 0x10) {
125
+                        bytestream2_skip(gb, 1);
126
+                        pos = - (opcode >> 2) - 4 * bytestream2_get_byte(gb) - 2049;
127
+
128
+                        bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
129
+                        bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
130
+
131
+                        bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
132
+                        bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
133
+                        bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
134
+                        len = opcode & 3;
135
+                        if (!len) {
136
+                            repeat = 1;
137
+                        } else {
138
+                            do {
139
+                                bytestream2_put_byte(pb, bytestream2_get_byte(gb));
140
+                                --len;
141
+                            } while (len);
142
+                            opcode = bytestream2_peek_byte(gb);
143
+                        }
144
+                        continue;
145
+                    }
146
+                }
147
+            }
148
+
149
+            if (opcode >= 0x40) {
150
+                bytestream2_skip(gb, 1);
151
+                pos = - ((opcode >> 2) & 7) - 1 - 8 * bytestream2_get_byte(gb);
152
+                len = (opcode >> 5) - 1;
153
+
154
+                bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
155
+                bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
156
+
157
+                bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
158
+                bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
159
+                do {
160
+                    bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
161
+                    --len;
162
+                } while (len);
163
+
164
+                len = opcode & 3;
165
+
166
+                if (!len) {
167
+                    repeat = 1;
168
+                } else {
169
+                    do {
170
+                        bytestream2_put_byte(pb, bytestream2_get_byte(gb));
171
+                        --len;
172
+                    } while (len);
173
+                    opcode = bytestream2_peek_byte(gb);
174
+                }
175
+                continue;
176
+            } else if (opcode < 0x20) {
177
+                break;
178
+            }
179
+            len = opcode & 0x1F;
180
+            bytestream2_skip(gb, 1);
181
+            if (!len) {
182
+                if (!bytestream2_peek_byte(gb)) {
183
+                    do {
184
+                        bytestream2_skip(gb, 1);
185
+                        len += 255;
186
+                    } while (!bytestream2_peek_byte(gb) && bytestream2_get_bytes_left(gb) > 0);
187
+                }
188
+                len += bytestream2_get_byte(gb) + 31;
189
+            }
190
+            i = bytestream2_get_le16(gb);
191
+            pos = - (i >> 2) - 1;
192
+
193
+            bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
194
+            bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
195
+
196
+            if (len < 6 || bytestream2_tell_p(pb) - bytestream2_tell(&gbc) < 4) {
197
+                bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
198
+                bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
199
+                do {
200
+                    bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
201
+                    --len;
202
+                } while (len);
203
+            } else {
204
+                bytestream2_put_le32(pb, bytestream2_get_le32(&gbc));
205
+                for (len = len - 2; len; --len)
206
+                    bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
207
+            }
208
+            len = i & 3;
209
+            if (!len) {
210
+                repeat = 1;
211
+            } else {
212
+                do {
213
+                    bytestream2_put_byte(pb, bytestream2_get_byte(gb));
214
+                    --len;
215
+                } while (len);
216
+                opcode = bytestream2_peek_byte(gb);
217
+            }
218
+        }
219
+        bytestream2_skip(gb, 1);
220
+        if (opcode < 0x10) {
221
+            pos = -(opcode >> 2) - 1 - 4 * bytestream2_get_byte(gb);
222
+
223
+            bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
224
+            bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
225
+
226
+            bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
227
+            bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
228
+            len = opcode & 3;
229
+            if (!len) {
230
+                repeat = 1;
231
+            } else {
232
+                do {
233
+                    bytestream2_put_byte(pb, bytestream2_get_byte(gb));
234
+                    --len;
235
+                } while (len);
236
+                opcode = bytestream2_peek_byte(gb);
237
+            }
238
+            continue;
239
+        }
240
+        len = opcode & 7;
241
+        if (!len) {
242
+            if (!bytestream2_peek_byte(gb)) {
243
+                do {
244
+                    bytestream2_skip(gb, 1);
245
+                    len += 255;
246
+                } while (!bytestream2_peek_byte(gb) && bytestream2_get_bytes_left(gb) > 0);
247
+            }
248
+            len += bytestream2_get_byte(gb) + 7;
249
+        }
250
+        i = bytestream2_get_le16(gb);
251
+        pos = bytestream2_tell_p(pb) - 2048 * (opcode & 8);
252
+        pos = pos - (i >> 2);
253
+        if (pos == bytestream2_tell_p(pb))
254
+            break;
255
+
256
+        pos = pos - 0x4000;
257
+        bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
258
+        bytestream2_seek(&gbc, pos, SEEK_SET);
259
+
260
+        if (len < 6 || bytestream2_tell_p(pb) - bytestream2_tell(&gbc) < 4) {
261
+            bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
262
+            bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
263
+            do {
264
+                bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
265
+                --len;
266
+            } while (len);
267
+        } else {
268
+            bytestream2_put_le32(pb, bytestream2_get_le32(&gbc));
269
+            for (len = len - 2; len; --len)
270
+                bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
271
+        }
272
+
273
+        len = i & 3;
274
+        if (!len) {
275
+            repeat = 1;
276
+        } else {
277
+            do {
278
+                bytestream2_put_byte(pb, bytestream2_get_byte(gb));
279
+                --len;
280
+            } while (len);
281
+            opcode = bytestream2_peek_byte(gb);
282
+        }
283
+    }
284
+
285
+    return 0;
286
+}
287
+
288
+static int decode_type1(GetByteContext *gb, PutByteContext *pb)
289
+{
290
+    unsigned opcode, len;
291
+    int high = 0;
292
+    int i, pos;
293
+
294
+    while (bytestream2_get_bytes_left(gb) > 0) {
295
+        GetByteContext gbc;
296
+
297
+        while (bytestream2_get_bytes_left(gb) > 0) {
298
+            while (bytestream2_get_bytes_left(gb) > 0) {
299
+                opcode = bytestream2_get_byte(gb);
300
+                high = opcode >= 0x20;
301
+                if (high)
302
+                    break;
303
+                if (opcode)
304
+                    break;
305
+                opcode = bytestream2_get_byte(gb);
306
+                if (opcode < 0xF8) {
307
+                    opcode = opcode + 32;
308
+                    break;
309
+                }
310
+                i = opcode - 0xF8;
311
+                if (i) {
312
+                    len = 256;
313
+                    do {
314
+                        len *= 2;
315
+                        --i;
316
+                    } while (i);
317
+                } else {
318
+                    len = 280;
319
+                }
320
+                do {
321
+                    bytestream2_put_le32(pb, bytestream2_get_le32(gb));
322
+                    bytestream2_put_le32(pb, bytestream2_get_le32(gb));
323
+                    len -= 8;
324
+                } while (len && bytestream2_get_bytes_left(gb) > 0);
325
+            }
326
+
327
+            if (!high) {
328
+                do {
329
+                    bytestream2_put_byte(pb, bytestream2_get_byte(gb));
330
+                    --opcode;
331
+                } while (opcode && bytestream2_get_bytes_left(gb) > 0);
332
+
333
+                while (bytestream2_get_bytes_left(gb) > 0) {
334
+                    GetByteContext gbc;
335
+
336
+                    opcode = bytestream2_get_byte(gb);
337
+                    if (opcode >= 0x20)
338
+                        break;
339
+                    bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
340
+
341
+                    pos = -(opcode | 32 * bytestream2_get_byte(gb)) - 1;
342
+                    bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
343
+                    bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
344
+                    bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
345
+                    bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
346
+                    bytestream2_put_byte(pb, bytestream2_get_byte(gb));
347
+                }
348
+            }
349
+            high = 0;
350
+            if (opcode < 0x40)
351
+                break;
352
+            bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
353
+            pos = (-((opcode & 0x1F) | 32 * bytestream2_get_byte(gb)) - 1);
354
+            bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
355
+            bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
356
+            bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
357
+            len = (opcode >> 5) - 1;
358
+            do {
359
+                bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
360
+                --len;
361
+            } while (len && bytestream2_get_bytes_left(&gbc) > 0);
362
+        }
363
+        len = opcode & 0x1F;
364
+        if (!len) {
365
+            if (!bytestream2_peek_byte(gb)) {
366
+                do {
367
+                    bytestream2_skip(gb, 1);
368
+                    len += 255;
369
+                } while (!bytestream2_peek_byte(gb) && bytestream2_get_bytes_left(gb) > 0);
370
+            }
371
+            len += bytestream2_get_byte(gb) + 31;
372
+        }
373
+        pos = -bytestream2_get_byte(gb);
374
+        bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
375
+        bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos - (bytestream2_get_byte(gb) << 8), SEEK_SET);
376
+        if (bytestream2_tell_p(pb) == bytestream2_tell(&gbc))
377
+            break;
378
+        if (len < 5 || bytestream2_tell_p(pb) - bytestream2_tell(&gbc) < 4) {
379
+            bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
380
+            bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
381
+            bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
382
+            do {
383
+                bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
384
+                --len;
385
+            } while (len && bytestream2_get_bytes_left(&gbc) > 0);
386
+        } else {
387
+            bytestream2_put_le32(pb, bytestream2_get_le32(&gbc));
388
+            len--;
389
+            do {
390
+                bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
391
+                len--;
392
+            } while (len && bytestream2_get_bytes_left(&gbc) > 0);
393
+        }
394
+    }
395
+
396
+    return 0;
397
+}
398
+
399
+static int decode_frame(AVCodecContext *avctx,
400
+                        void *data, int *got_frame,
401
+                        AVPacket *avpkt)
402
+{
403
+    FMVCContext *s = avctx->priv_data;
404
+    GetByteContext *gb = &s->gb;
405
+    PutByteContext *pb = &s->pb;
406
+    AVFrame *frame = data;
407
+    int ret, y, x;
408
+
409
+    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
410
+        return ret;
411
+
412
+    bytestream2_init(gb, avpkt->data, avpkt->size);
413
+    bytestream2_skip(gb, 2);
414
+
415
+    frame->key_frame = !!bytestream2_get_le16(gb);
416
+    frame->pict_type = frame->key_frame ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
417
+
418
+    if (frame->key_frame) {
419
+        const uint8_t *src;
420
+        int type, size;
421
+        uint8_t *dst;
422
+
423
+        type = bytestream2_get_le16(gb);
424
+        size = bytestream2_get_le16(gb);
425
+        if (size > bytestream2_get_bytes_left(gb))
426
+            return AVERROR_INVALIDDATA;
427
+
428
+        bytestream2_init_writer(pb, s->buffer, s->buffer_size);
429
+        if (type == 1) {
430
+            decode_type1(gb, pb);
431
+        } else if (type == 2){
432
+            decode_type2(gb, pb);
433
+        } else {
434
+            avpriv_report_missing_feature(avctx, "compression %d", type);
435
+            return AVERROR_PATCHWELCOME;
436
+        }
437
+
438
+        src = s->buffer;
439
+        dst = frame->data[0] + (avctx->height - 1) * frame->linesize[0];
440
+        for (y = 0; y < avctx->height; y++) {
441
+            memcpy(dst, src, avctx->width * s->bpp);
442
+            dst -= frame->linesize[0];
443
+            src += avctx->width * s->bpp;
444
+        }
445
+    } else {
446
+        int block, nb_blocks, type, k, l;
447
+        uint8_t *ssrc, *ddst;
448
+        const uint32_t *src;
449
+        uint32_t *dst;
450
+
451
+        for (block = 0; block < s->nb_blocks; block++)
452
+            s->blocks[block].xor = 0;
453
+
454
+        nb_blocks = bytestream2_get_le16(gb);
455
+        if (nb_blocks > s->nb_blocks)
456
+            return AVERROR_INVALIDDATA;
457
+
458
+        bytestream2_init_writer(pb, s->pbuffer, s->pbuffer_size);
459
+
460
+        type = bytestream2_get_le16(gb);
461
+        for (block = 0; block < nb_blocks; block++) {
462
+            int size, offset, start = 0;
463
+
464
+            offset = bytestream2_get_le16(gb);
465
+            if (offset > s->nb_blocks)
466
+                return AVERROR_INVALIDDATA;
467
+
468
+            size = bytestream2_get_le16(gb);
469
+            if (size > bytestream2_get_bytes_left(gb))
470
+                return AVERROR_INVALIDDATA;
471
+
472
+            start = bytestream2_tell_p(pb);
473
+            if (type == 1) {
474
+                decode_type1(gb, pb);
475
+            } else if (type == 2){
476
+                decode_type2(gb, pb);
477
+            } else {
478
+                avpriv_report_missing_feature(avctx, "compression %d", type);
479
+                return AVERROR_PATCHWELCOME;
480
+            }
481
+
482
+            if (s->blocks[offset].size * 4 != bytestream2_tell_p(pb) - start)
483
+                return AVERROR_INVALIDDATA;
484
+
485
+            s->blocks[offset].xor = 1;
486
+        }
487
+
488
+        src = (const uint32_t *)s->pbuffer;
489
+        dst = (uint32_t *)s->buffer;
490
+
491
+        for (block = 0, y = 0; y < s->yb; y++) {
492
+            int block_h = s->blocks[block].h;
493
+            uint32_t *rect = dst;
494
+
495
+            for (x = 0; x < s->xb; x++) {
496
+                int block_w = s->blocks[block].w;
497
+                uint32_t *row = dst;
498
+
499
+                block_h = s->blocks[block].h;
500
+                if (s->blocks[block].xor) {
501
+                    for (k = 0; k < block_h; k++) {
502
+                        uint32_t *column = dst;
503
+                        for (l = 0; l < block_w; l++) {
504
+                            *dst++ ^= *src++;
505
+                        }
506
+                        dst = &column[s->stride];
507
+                    }
508
+                }
509
+                dst = &row[block_w];
510
+                ++block;
511
+            }
512
+            dst = &rect[block_h * s->stride];
513
+        }
514
+
515
+        ssrc = s->buffer;
516
+        ddst = frame->data[0] + (avctx->height - 1) * frame->linesize[0];
517
+        for (y = 0; y < avctx->height; y++) {
518
+            memcpy(ddst, ssrc, avctx->width * s->bpp);
519
+            ddst -= frame->linesize[0];
520
+            ssrc += avctx->width * s->bpp;
521
+        }
522
+    }
523
+
524
+    *got_frame = 1;
525
+
526
+    return avpkt->size;
527
+}
528
+
529
+static av_cold int decode_init(AVCodecContext *avctx)
530
+{
531
+    FMVCContext *s = avctx->priv_data;
532
+    int i, j, m, block = 0, h = BLOCK_HEIGHT, w = BLOCK_WIDTH;
533
+
534
+    switch (avctx->bits_per_coded_sample) {
535
+    case 16: avctx->pix_fmt = AV_PIX_FMT_RGB555; break;
536
+    case 24: avctx->pix_fmt = AV_PIX_FMT_BGR24;  break;
537
+    case 32: avctx->pix_fmt = AV_PIX_FMT_BGRA;   break;
538
+    default:
539
+        av_log(avctx, AV_LOG_ERROR, "Unsupported bitdepth %i\n", avctx->bits_per_coded_sample);
540
+        return AVERROR_INVALIDDATA;
541
+    }
542
+
543
+    s->stride = (avctx->width * avctx->bits_per_coded_sample + 31) / 32;
544
+    s->xb = s->stride / BLOCK_WIDTH;
545
+    m = s->stride % BLOCK_WIDTH;
546
+    if (m) {
547
+        if (m < 37) {
548
+            w = m + BLOCK_WIDTH;
549
+        } else {
550
+            w = m;
551
+            s->xb++;
552
+        }
553
+    }
554
+
555
+    s->yb = avctx->height / BLOCK_HEIGHT;
556
+    m = avctx->height % BLOCK_HEIGHT;
557
+    if (m) {
558
+        if (m < 49) {
559
+            h = m + BLOCK_HEIGHT;
560
+        } else {
561
+            h = m;
562
+            s->yb++;
563
+        }
564
+    }
565
+
566
+    s->nb_blocks = s->xb * s->yb;
567
+    s->blocks = av_calloc(s->nb_blocks, sizeof(*s->blocks));
568
+    if (!s->blocks)
569
+        return AVERROR(ENOMEM);
570
+
571
+    for (i = 0; i < s->yb; i++) {
572
+        for (j = 0; j < s->xb; j++) {
573
+            if (i != (s->yb - 1) || j != (s->xb - 1)) {
574
+                if (i == s->yb - 1) {
575
+                    s->blocks[block].w = BLOCK_WIDTH;
576
+                    s->blocks[block].h = h;
577
+                    s->blocks[block].size = BLOCK_WIDTH * h;
578
+                } else if (j == s->xb - 1) {
579
+                    s->blocks[block].w = w;
580
+                    s->blocks[block].h = BLOCK_HEIGHT;
581
+                    s->blocks[block].size = BLOCK_HEIGHT * w;
582
+                } else {
583
+                    s->blocks[block].w = BLOCK_WIDTH;
584
+                    s->blocks[block].h = BLOCK_HEIGHT;
585
+                    s->blocks[block].size = BLOCK_WIDTH * BLOCK_HEIGHT;
586
+                }
587
+            } else {
588
+                s->blocks[block].w = w;
589
+                s->blocks[block].h = h;
590
+                s->blocks[block].size = w * h;
591
+            }
592
+            block++;
593
+        }
594
+    }
595
+
596
+    s->bpp = avctx->bits_per_coded_sample >> 3;
597
+    s->buffer_size = avctx->width * avctx->height * 4;
598
+    s->pbuffer_size = avctx->width * avctx->height * 4;
599
+    s->buffer = av_malloc(s->buffer_size);
600
+    s->pbuffer = av_malloc(s->pbuffer_size);
601
+    if (!s->buffer || !s->pbuffer)
602
+        return AVERROR(ENOMEM);
603
+
604
+    return 0;
605
+}
606
+
607
+static av_cold int decode_close(AVCodecContext *avctx)
608
+{
609
+    FMVCContext *s = avctx->priv_data;
610
+
611
+    av_freep(&s->buffer);
612
+    av_freep(&s->pbuffer);
613
+    av_freep(&s->blocks);
614
+
615
+    return 0;
616
+}
617
+
618
+AVCodec ff_fmvc_decoder = {
619
+    .name             = "fmvc",
620
+    .long_name        = NULL_IF_CONFIG_SMALL("FM Screen Capture Codec"),
621
+    .type             = AVMEDIA_TYPE_VIDEO,
622
+    .id               = AV_CODEC_ID_FMVC,
623
+    .priv_data_size   = sizeof(FMVCContext),
624
+    .init             = decode_init,
625
+    .close            = decode_close,
626
+    .decode           = decode_frame,
627
+    .capabilities     = AV_CODEC_CAP_DR1,
628
+    .caps_internal    = FF_CODEC_CAP_INIT_THREADSAFE |
629
+                        FF_CODEC_CAP_INIT_CLEANUP,
630
+};
... ...
@@ -28,7 +28,7 @@
28 28
 #include "libavutil/version.h"
29 29
 
30 30
 #define LIBAVCODEC_VERSION_MAJOR  57
31
-#define LIBAVCODEC_VERSION_MINOR  78
31
+#define LIBAVCODEC_VERSION_MINOR  79
32 32
 #define LIBAVCODEC_VERSION_MICRO 100
33 33
 
34 34
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
... ...
@@ -448,6 +448,7 @@ const AVCodecTag ff_codec_bmp_tags[] = {
448 448
     { AV_CODEC_ID_SPEEDHQ,      MKTAG('S', 'H', 'Q', '5') },
449 449
     { AV_CODEC_ID_SPEEDHQ,      MKTAG('S', 'H', 'Q', '7') },
450 450
     { AV_CODEC_ID_SPEEDHQ,      MKTAG('S', 'H', 'Q', '9') },
451
+    { AV_CODEC_ID_FMVC,         MKTAG('F', 'M', 'V', 'C') },
451 452
 
452 453
     { AV_CODEC_ID_NONE,         0 }
453 454
 };