xref: /third_party/ffmpeg/libavcodec/fmvc.c (revision cabdff1a)
1/*
2 * FM Screen Capture Codec decoder
3 *
4 * Copyright (c) 2017 Paul B Mahol
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26
27#include "avcodec.h"
28#include "bytestream.h"
29#include "codec_internal.h"
30#include "internal.h"
31
32#define BLOCK_HEIGHT 112u
33#define BLOCK_WIDTH  84u
34
35typedef struct InterBlock {
36    int      w, h;
37    int      size;
38    int      xor;
39} InterBlock;
40
41typedef struct FMVCContext {
42    GetByteContext  gb;
43    PutByteContext  pb;
44    uint8_t        *buffer;
45    size_t          buffer_size;
46    uint8_t        *pbuffer;
47    size_t          pbuffer_size;
48    ptrdiff_t       stride;
49    int             bpp;
50    int             yb, xb;
51    InterBlock     *blocks;
52    unsigned        nb_blocks;
53} FMVCContext;
54
55static int decode_type2(GetByteContext *gb, PutByteContext *pb)
56{
57    unsigned repeat = 0, first = 1, opcode = 0;
58    int i, len, pos;
59
60    while (bytestream2_get_bytes_left(gb) > 0) {
61        GetByteContext gbc;
62
63        while (bytestream2_get_bytes_left(gb) > 0) {
64            if (first) {
65                first = 0;
66                if (bytestream2_peek_byte(gb) > 17) {
67                    len = bytestream2_get_byte(gb) - 17;
68                    if (len < 4) {
69                        do {
70                            bytestream2_put_byte(pb, bytestream2_get_byte(gb));
71                            --len;
72                        } while (len);
73                        opcode = bytestream2_peek_byte(gb);
74                        continue;
75                    } else {
76                        do {
77                            bytestream2_put_byte(pb, bytestream2_get_byte(gb));
78                            --len;
79                        } while (len);
80                        opcode = bytestream2_peek_byte(gb);
81                        if (opcode < 0x10) {
82                            bytestream2_skip(gb, 1);
83                            pos = - (opcode >> 2) - 4 * bytestream2_get_byte(gb) - 2049;
84
85                            bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
86                            bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
87
88                            bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
89                            bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
90                            bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
91                            len = opcode & 3;
92                            if (!len) {
93                                repeat = 1;
94                            } else {
95                                do {
96                                    bytestream2_put_byte(pb, bytestream2_get_byte(gb));
97                                    --len;
98                                } while (len);
99                                opcode = bytestream2_peek_byte(gb);
100                            }
101                            continue;
102                        }
103                    }
104                    repeat = 0;
105                }
106                repeat = 1;
107            }
108            if (repeat) {
109                repeat = 0;
110                opcode = bytestream2_peek_byte(gb);
111                if (opcode < 0x10) {
112                    bytestream2_skip(gb, 1);
113                    if (!opcode) {
114                        if (!bytestream2_peek_byte(gb)) {
115                            do {
116                                bytestream2_skip(gb, 1);
117                                opcode += 255;
118                            } while (!bytestream2_peek_byte(gb) && bytestream2_get_bytes_left(gb) > 0);
119                        }
120                        opcode += bytestream2_get_byte(gb) + 15;
121                    }
122                    bytestream2_put_le32(pb, bytestream2_get_le32(gb));
123                    for (i = opcode - 1; i > 0; --i)
124                        bytestream2_put_byte(pb, bytestream2_get_byte(gb));
125                    opcode = bytestream2_peek_byte(gb);
126                    if (opcode < 0x10) {
127                        bytestream2_skip(gb, 1);
128                        pos = - (opcode >> 2) - 4 * bytestream2_get_byte(gb) - 2049;
129
130                        bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
131                        bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
132
133                        bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
134                        bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
135                        bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
136                        len = opcode & 3;
137                        if (!len) {
138                            repeat = 1;
139                        } else {
140                            do {
141                                bytestream2_put_byte(pb, bytestream2_get_byte(gb));
142                                --len;
143                            } while (len);
144                            opcode = bytestream2_peek_byte(gb);
145                        }
146                        continue;
147                    }
148                }
149            }
150
151            if (opcode >= 0x40) {
152                bytestream2_skip(gb, 1);
153                pos = - ((opcode >> 2) & 7) - 1 - 8 * bytestream2_get_byte(gb);
154                len =    (opcode >> 5)      - 1;
155
156                bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
157                bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
158
159                bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
160                bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
161                do {
162                    bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
163                    --len;
164                } while (len);
165
166                len = opcode & 3;
167
168                if (!len) {
169                    repeat = 1;
170                } else {
171                    do {
172                        bytestream2_put_byte(pb, bytestream2_get_byte(gb));
173                        --len;
174                    } while (len);
175                    opcode = bytestream2_peek_byte(gb);
176                }
177                continue;
178            } else if (opcode < 0x20) {
179                break;
180            }
181            len = opcode & 0x1F;
182            bytestream2_skip(gb, 1);
183            if (!len) {
184                if (!bytestream2_peek_byte(gb)) {
185                    do {
186                        bytestream2_skip(gb, 1);
187                        len += 255;
188                    } while (!bytestream2_peek_byte(gb) && bytestream2_get_bytes_left(gb) > 0);
189                }
190                len += bytestream2_get_byte(gb) + 31;
191            }
192            i = bytestream2_get_le16(gb);
193            pos = - (i >> 2) - 1;
194
195            bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
196            bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
197
198            if (len < 6 || bytestream2_tell_p(pb) - bytestream2_tell(&gbc) < 4) {
199                bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
200                bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
201                do {
202                    bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
203                    --len;
204                } while (len);
205            } else {
206                bytestream2_put_le32(pb, bytestream2_get_le32(&gbc));
207                for (len = len - 2; len; --len)
208                    bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
209            }
210            len = i & 3;
211            if (!len) {
212                repeat = 1;
213            } else {
214                do {
215                    bytestream2_put_byte(pb, bytestream2_get_byte(gb));
216                    --len;
217                } while (len);
218                opcode = bytestream2_peek_byte(gb);
219            }
220        }
221        bytestream2_skip(gb, 1);
222        if (opcode < 0x10) {
223            pos = -(opcode >> 2) - 1 - 4 * bytestream2_get_byte(gb);
224
225            bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
226            bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
227
228            bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
229            bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
230            len = opcode & 3;
231            if (!len) {
232                repeat = 1;
233            } else {
234                do {
235                    bytestream2_put_byte(pb, bytestream2_get_byte(gb));
236                    --len;
237                } while (len);
238                opcode = bytestream2_peek_byte(gb);
239            }
240            continue;
241        }
242        len = opcode & 7;
243        if (!len) {
244            if (!bytestream2_peek_byte(gb)) {
245                do {
246                    bytestream2_skip(gb, 1);
247                    len += 255;
248                } while (!bytestream2_peek_byte(gb) && bytestream2_get_bytes_left(gb) > 0);
249            }
250            len += bytestream2_get_byte(gb) + 7;
251        }
252        i = bytestream2_get_le16(gb);
253        pos = bytestream2_tell_p(pb) - 2048 * (opcode & 8);
254        pos = pos - (i >> 2);
255        if (pos == bytestream2_tell_p(pb))
256            break;
257
258        pos = pos - 0x4000;
259        bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
260        bytestream2_seek(&gbc, pos, SEEK_SET);
261
262        if (len < 6 || bytestream2_tell_p(pb) - bytestream2_tell(&gbc) < 4) {
263            bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
264            bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
265            do {
266                bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
267                --len;
268            } while (len);
269        } else {
270            bytestream2_put_le32(pb, bytestream2_get_le32(&gbc));
271            for (len = len - 2; len; --len)
272                bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
273        }
274
275        len = i & 3;
276        if (!len) {
277            repeat = 1;
278        } else {
279            do {
280                bytestream2_put_byte(pb, bytestream2_get_byte(gb));
281                --len;
282            } while (len);
283            opcode = bytestream2_peek_byte(gb);
284        }
285    }
286
287    return 0;
288}
289
290static int decode_type1(GetByteContext *gb, PutByteContext *pb)
291{
292    unsigned opcode = 0, len;
293    int high = 0;
294    int i, pos;
295
296    while (bytestream2_get_bytes_left(gb) > 0) {
297        GetByteContext gbc;
298
299        while (bytestream2_get_bytes_left(gb) > 0) {
300            while (bytestream2_get_bytes_left(gb) > 0) {
301                opcode = bytestream2_get_byte(gb);
302                high = opcode >= 0x20;
303                if (high)
304                    break;
305                if (opcode)
306                    break;
307                opcode = bytestream2_get_byte(gb);
308                if (opcode < 0xF8) {
309                    opcode += 32;
310                    break;
311                }
312                i = opcode - 0xF8;
313                if (i) {
314                    len = 256;
315                    do {
316                        len *= 2;
317                        --i;
318                    } while (i);
319                } else {
320                    len = 280;
321                }
322                do {
323                    bytestream2_put_le32(pb, bytestream2_get_le32(gb));
324                    bytestream2_put_le32(pb, bytestream2_get_le32(gb));
325                    len -= 8;
326                } while (len && bytestream2_get_bytes_left(gb) > 0);
327            }
328
329            if (!high) {
330                do {
331                    bytestream2_put_byte(pb, bytestream2_get_byte(gb));
332                    --opcode;
333                } while (opcode && bytestream2_get_bytes_left(gb) > 0);
334
335                while (bytestream2_get_bytes_left(gb) > 0) {
336                    GetByteContext gbc;
337
338                    opcode = bytestream2_get_byte(gb);
339                    if (opcode >= 0x20)
340                        break;
341                    bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
342
343                    pos = -(opcode | 32 * bytestream2_get_byte(gb)) - 1;
344                    bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
345                    bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
346                    bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
347                    bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
348                    bytestream2_put_byte(pb, bytestream2_get_byte(gb));
349                }
350            }
351            high = 0;
352            if (opcode < 0x40)
353                break;
354            bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
355            pos = (-((opcode & 0x1F) | 32 * bytestream2_get_byte(gb)) - 1);
356            bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
357            bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
358            bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
359            len = (opcode >> 5) - 1;
360            do {
361                bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
362                --len;
363            } while (len && bytestream2_get_bytes_left(&gbc) > 0);
364        }
365        len = opcode & 0x1F;
366        if (!len) {
367            if (!bytestream2_peek_byte(gb)) {
368                do {
369                    bytestream2_skip(gb, 1);
370                    len += 255;
371                } while (!bytestream2_peek_byte(gb) && bytestream2_get_bytes_left(gb) > 0);
372            }
373            len += bytestream2_get_byte(gb) + 31;
374        }
375        pos = -bytestream2_get_byte(gb);
376        bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
377        bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos - (bytestream2_get_byte(gb) << 8), SEEK_SET);
378        if (bytestream2_tell_p(pb) == bytestream2_tell(&gbc))
379            break;
380        if (len < 5 || bytestream2_tell_p(pb) - bytestream2_tell(&gbc) < 4) {
381            bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
382            bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
383            bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
384        } else {
385            bytestream2_put_le32(pb, bytestream2_get_le32(&gbc));
386            len--;
387        }
388        do {
389            bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
390            len--;
391        } while (len && bytestream2_get_bytes_left(&gbc) > 0);
392    }
393
394    return 0;
395}
396
397static int decode_frame(AVCodecContext *avctx, AVFrame *frame,
398                        int *got_frame, AVPacket *avpkt)
399{
400    FMVCContext *s = avctx->priv_data;
401    GetByteContext *gb = &s->gb;
402    PutByteContext *pb = &s->pb;
403    int ret, y, x;
404    int key_frame;
405
406    if (avpkt->size < 8)
407        return AVERROR_INVALIDDATA;
408
409    bytestream2_init(gb, avpkt->data, avpkt->size);
410    bytestream2_skip(gb, 2);
411
412    key_frame = !!bytestream2_get_le16(gb);
413
414    if (key_frame) {
415        const uint8_t *src;
416        unsigned type, size;
417        uint8_t *dst;
418
419        type = bytestream2_get_le16(gb);
420        size = bytestream2_get_le16(gb);
421        if (size > bytestream2_get_bytes_left(gb))
422            return AVERROR_INVALIDDATA;
423
424        bytestream2_init_writer(pb, s->buffer, s->buffer_size);
425        if (type == 1) {
426            decode_type1(gb, pb);
427        } else if (type == 2){
428            decode_type2(gb, pb);
429        } else {
430            avpriv_report_missing_feature(avctx, "Compression type %d", type);
431            return AVERROR_PATCHWELCOME;
432        }
433
434        if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
435            return ret;
436
437        frame->key_frame = 1;
438        frame->pict_type = AV_PICTURE_TYPE_I;
439
440        src = s->buffer;
441        dst = frame->data[0] + (avctx->height - 1) * frame->linesize[0];
442        for (y = 0; y < avctx->height; y++) {
443            memcpy(dst, src, avctx->width * s->bpp);
444            dst -= frame->linesize[0];
445            src += s->stride * 4;
446            if (bytestream2_tell_p(pb) < y*s->stride * 4)
447                break;
448        }
449    } else {
450        unsigned block, nb_blocks;
451        int type, k, l;
452        uint8_t *ssrc, *ddst;
453        const uint32_t *src;
454        uint32_t *dst;
455
456        for (block = 0; block < s->nb_blocks; block++)
457            s->blocks[block].xor = 0;
458
459        nb_blocks = bytestream2_get_le16(gb);
460        if (nb_blocks > s->nb_blocks)
461            return AVERROR_INVALIDDATA;
462
463        bytestream2_init_writer(pb, s->pbuffer, s->pbuffer_size);
464
465        type = bytestream2_get_le16(gb);
466        for (block = 0; block < nb_blocks; block++) {
467            unsigned size, offset;
468            int start = 0;
469
470            offset = bytestream2_get_le16(gb);
471            if (offset >= s->nb_blocks)
472                return AVERROR_INVALIDDATA;
473
474            size = bytestream2_get_le16(gb);
475            if (size > bytestream2_get_bytes_left(gb))
476                return AVERROR_INVALIDDATA;
477
478            start = bytestream2_tell_p(pb);
479            if (type == 1) {
480                decode_type1(gb, pb);
481            } else if (type == 2){
482                decode_type2(gb, pb);
483            } else {
484                avpriv_report_missing_feature(avctx, "Compression type %d", type);
485                return AVERROR_PATCHWELCOME;
486            }
487
488            if (s->blocks[offset].size * 4 != bytestream2_tell_p(pb) - start)
489                return AVERROR_INVALIDDATA;
490
491            s->blocks[offset].xor = 1;
492        }
493
494        src = (const uint32_t *)s->pbuffer;
495        dst = (uint32_t *)s->buffer;
496
497        for (block = 0, y = 0; y < s->yb; y++) {
498            int block_h = s->blocks[block].h;
499            uint32_t *rect = dst;
500
501            for (x = 0; x < s->xb; x++) {
502                int block_w = s->blocks[block].w;
503                uint32_t *row = dst;
504
505                block_h = s->blocks[block].h;
506                if (s->blocks[block].xor) {
507                    for (k = 0; k < block_h; k++) {
508                        uint32_t *column = dst;
509                        for (l = 0; l < block_w; l++)
510                            *dst++ ^= *src++;
511                        dst = &column[s->stride];
512                    }
513                }
514                dst = &row[block_w];
515                ++block;
516            }
517            dst = &rect[block_h * s->stride];
518        }
519
520        if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
521            return ret;
522
523        frame->key_frame = 0;
524        frame->pict_type = AV_PICTURE_TYPE_P;
525
526        ssrc = s->buffer;
527        ddst = frame->data[0] + (avctx->height - 1) * frame->linesize[0];
528        for (y = 0; y < avctx->height; y++) {
529            memcpy(ddst, ssrc, avctx->width * s->bpp);
530            ddst -= frame->linesize[0];
531            ssrc += s->stride * 4;
532        }
533    }
534
535    *got_frame = 1;
536
537    return avpkt->size;
538}
539
540static av_cold int decode_init(AVCodecContext *avctx)
541{
542    FMVCContext *s = avctx->priv_data;
543    int i, j, m, block = 0, h = BLOCK_HEIGHT, w = BLOCK_WIDTH;
544
545    switch (avctx->bits_per_coded_sample) {
546    case 16:
547        avctx->pix_fmt = AV_PIX_FMT_RGB555LE;
548        break;
549    case 24:
550        avctx->pix_fmt = AV_PIX_FMT_BGR24;
551        break;
552    case 32:
553        avctx->pix_fmt = AV_PIX_FMT_BGRA;
554        break;
555    default:
556        av_log(avctx, AV_LOG_ERROR, "Unsupported bitdepth %i\n",
557               avctx->bits_per_coded_sample);
558        return AVERROR_INVALIDDATA;
559    }
560
561    s->stride = (avctx->width * avctx->bits_per_coded_sample + 31) / 32;
562    s->xb     = s->stride / BLOCK_WIDTH;
563    m         = s->stride % BLOCK_WIDTH;
564    if (m) {
565        if (m < 37) {
566            w = m + BLOCK_WIDTH;
567        } else {
568            w = m;
569            s->xb++;
570        }
571    }
572
573    s->yb = avctx->height / BLOCK_HEIGHT;
574    m     = avctx->height % BLOCK_HEIGHT;
575    if (m) {
576        if (m < 49) {
577            h = m + BLOCK_HEIGHT;
578        } else {
579            h = m;
580            s->yb++;
581        }
582    }
583
584    s->nb_blocks = s->xb * s->yb;
585    if (!s->nb_blocks)
586        return AVERROR_INVALIDDATA;
587    s->blocks    = av_calloc(s->nb_blocks, sizeof(*s->blocks));
588    if (!s->blocks)
589        return AVERROR(ENOMEM);
590
591    for (i = 0; i < s->yb; i++) {
592        for (j = 0; j < s->xb; j++) {
593            if (i != (s->yb - 1) || j != (s->xb - 1)) {
594                if (i == s->yb - 1) {
595                    s->blocks[block].w    = BLOCK_WIDTH;
596                    s->blocks[block].h    = h;
597                    s->blocks[block].size = BLOCK_WIDTH * h;
598                } else if (j == s->xb - 1) {
599                    s->blocks[block].w    = w;
600                    s->blocks[block].h    = BLOCK_HEIGHT;
601                    s->blocks[block].size = BLOCK_HEIGHT * w;
602                } else {
603                    s->blocks[block].w    = BLOCK_WIDTH;
604                    s->blocks[block].h    = BLOCK_HEIGHT;
605                    s->blocks[block].size = BLOCK_WIDTH * BLOCK_HEIGHT;
606                }
607            } else {
608                s->blocks[block].w    = w;
609                s->blocks[block].h    = h;
610                s->blocks[block].size = w * h;
611            }
612            block++;
613        }
614    }
615
616    s->bpp          = avctx->bits_per_coded_sample >> 3;
617    s->buffer_size  = avctx->width * avctx->height * 4;
618    s->pbuffer_size = avctx->width * avctx->height * 4;
619    s->buffer       = av_mallocz(s->buffer_size);
620    s->pbuffer      = av_mallocz(s->pbuffer_size);
621    if (!s->buffer || !s->pbuffer)
622        return AVERROR(ENOMEM);
623
624    return 0;
625}
626
627static av_cold int decode_close(AVCodecContext *avctx)
628{
629    FMVCContext *s = avctx->priv_data;
630
631    av_freep(&s->buffer);
632    av_freep(&s->pbuffer);
633    av_freep(&s->blocks);
634
635    return 0;
636}
637
638const FFCodec ff_fmvc_decoder = {
639    .p.name           = "fmvc",
640    .p.long_name      = NULL_IF_CONFIG_SMALL("FM Screen Capture Codec"),
641    .p.type           = AVMEDIA_TYPE_VIDEO,
642    .p.id             = AV_CODEC_ID_FMVC,
643    .priv_data_size   = sizeof(FMVCContext),
644    .init             = decode_init,
645    .close            = decode_close,
646    FF_CODEC_DECODE_CB(decode_frame),
647    .p.capabilities   = AV_CODEC_CAP_DR1,
648    .caps_internal    = FF_CODEC_CAP_INIT_THREADSAFE |
649                        FF_CODEC_CAP_INIT_CLEANUP,
650};
651