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