/src/ffmpeg/libavcodec/fmvc.c
Line | Count | Source |
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 <string.h> |
25 | | |
26 | | #include "libavutil/mem.h" |
27 | | #include "avcodec.h" |
28 | | #include "bytestream.h" |
29 | | #include "codec_internal.h" |
30 | | #include "decode.h" |
31 | | |
32 | 389k | #define BLOCK_HEIGHT 112u |
33 | 477k | #define BLOCK_WIDTH 84u |
34 | | |
35 | | typedef struct InterBlock { |
36 | | int w, h; |
37 | | int size; |
38 | | int xor; |
39 | | } InterBlock; |
40 | | |
41 | | typedef 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 | | |
55 | | static int decode_type2(GetByteContext *gb, PutByteContext *pb) |
56 | 13.8k | { |
57 | 13.8k | unsigned repeat = 0, first = 1, opcode = 0; |
58 | 13.8k | int i, len, pos; |
59 | | |
60 | 548k | while (bytestream2_get_bytes_left(gb) > 0) { |
61 | 535k | GetByteContext gbc; |
62 | | |
63 | 1.97M | while (bytestream2_get_bytes_left(gb) > 0) { |
64 | 1.96M | if (first) { |
65 | 13.3k | first = 0; |
66 | 13.3k | if (bytestream2_peek_byte(gb) > 17) { |
67 | 3.13k | len = bytestream2_get_byte(gb) - 17; |
68 | 3.13k | if (len < 4) { |
69 | 2.78k | do { |
70 | 2.78k | bytestream2_put_byte(pb, bytestream2_get_byte(gb)); |
71 | 2.78k | --len; |
72 | 2.78k | } while (len); |
73 | 1.01k | opcode = bytestream2_peek_byte(gb); |
74 | 1.01k | continue; |
75 | 2.12k | } else { |
76 | 109k | do { |
77 | 109k | bytestream2_put_byte(pb, bytestream2_get_byte(gb)); |
78 | 109k | --len; |
79 | 109k | } while (len); |
80 | 2.12k | opcode = bytestream2_peek_byte(gb); |
81 | 2.12k | if (opcode < 0x10) { |
82 | 1.61k | bytestream2_skip(gb, 1); |
83 | 1.61k | pos = - (opcode >> 2) - 4 * bytestream2_get_byte(gb) - 2049; |
84 | | |
85 | 1.61k | bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start); |
86 | 1.61k | bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET); |
87 | | |
88 | 1.61k | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
89 | 1.61k | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
90 | 1.61k | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
91 | 1.61k | len = opcode & 3; |
92 | 1.61k | if (!len) { |
93 | 602 | repeat = 1; |
94 | 1.00k | } else { |
95 | 2.77k | do { |
96 | 2.77k | bytestream2_put_byte(pb, bytestream2_get_byte(gb)); |
97 | 2.77k | --len; |
98 | 2.77k | } while (len); |
99 | 1.00k | opcode = bytestream2_peek_byte(gb); |
100 | 1.00k | } |
101 | 1.61k | continue; |
102 | 1.61k | } |
103 | 2.12k | } |
104 | 3.13k | } |
105 | 10.7k | repeat = 1; |
106 | 10.7k | } |
107 | 1.96M | if (repeat) { |
108 | 577k | repeat = 0; |
109 | 577k | opcode = bytestream2_peek_byte(gb); |
110 | 577k | if (opcode < 0x10) { |
111 | 328k | bytestream2_skip(gb, 1); |
112 | 328k | if (!opcode) { |
113 | 46.1k | if (!bytestream2_peek_byte(gb)) { |
114 | 1.44M | do { |
115 | 1.44M | bytestream2_skip(gb, 1); |
116 | 1.44M | opcode += 255; |
117 | 1.44M | } while (!bytestream2_peek_byte(gb) && bytestream2_get_bytes_left(gb) > 0); |
118 | 14.7k | } |
119 | 46.1k | opcode += bytestream2_get_byte(gb) + 15; |
120 | 46.1k | } |
121 | 328k | bytestream2_put_le32(pb, bytestream2_get_le32(gb)); |
122 | 373M | for (i = opcode - 1; i > 0; --i) |
123 | 372M | bytestream2_put_byte(pb, bytestream2_get_byte(gb)); |
124 | 328k | opcode = bytestream2_peek_byte(gb); |
125 | 328k | if (opcode < 0x10) { |
126 | 294k | bytestream2_skip(gb, 1); |
127 | 294k | pos = - (opcode >> 2) - 4 * bytestream2_get_byte(gb) - 2049; |
128 | | |
129 | 294k | bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start); |
130 | 294k | bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET); |
131 | | |
132 | 294k | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
133 | 294k | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
134 | 294k | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
135 | 294k | len = opcode & 3; |
136 | 294k | if (!len) { |
137 | 231k | repeat = 1; |
138 | 231k | } else { |
139 | 126k | do { |
140 | 126k | bytestream2_put_byte(pb, bytestream2_get_byte(gb)); |
141 | 126k | --len; |
142 | 126k | } while (len); |
143 | 62.4k | opcode = bytestream2_peek_byte(gb); |
144 | 62.4k | } |
145 | 294k | continue; |
146 | 294k | } |
147 | 328k | } |
148 | 577k | } |
149 | | |
150 | 1.67M | if (opcode >= 0x40) { |
151 | 962k | bytestream2_skip(gb, 1); |
152 | 962k | pos = - ((opcode >> 2) & 7) - 1 - 8 * bytestream2_get_byte(gb); |
153 | 962k | len = (opcode >> 5) - 1; |
154 | | |
155 | 962k | bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start); |
156 | 962k | bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET); |
157 | | |
158 | 962k | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
159 | 962k | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
160 | 4.55M | do { |
161 | 4.55M | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
162 | 4.55M | --len; |
163 | 4.55M | } while (len); |
164 | | |
165 | 962k | len = opcode & 3; |
166 | | |
167 | 962k | if (!len) { |
168 | 159k | repeat = 1; |
169 | 802k | } else { |
170 | 1.73M | do { |
171 | 1.73M | bytestream2_put_byte(pb, bytestream2_get_byte(gb)); |
172 | 1.73M | --len; |
173 | 1.73M | } while (len); |
174 | 802k | opcode = bytestream2_peek_byte(gb); |
175 | 802k | } |
176 | 962k | continue; |
177 | 962k | } else if (opcode < 0x20) { |
178 | 524k | break; |
179 | 524k | } |
180 | 184k | len = opcode & 0x1F; |
181 | 184k | bytestream2_skip(gb, 1); |
182 | 184k | if (!len) { |
183 | 50.3k | if (!bytestream2_peek_byte(gb)) { |
184 | 227k | do { |
185 | 227k | bytestream2_skip(gb, 1); |
186 | 227k | len += 255; |
187 | 227k | } while (!bytestream2_peek_byte(gb) && bytestream2_get_bytes_left(gb) > 0); |
188 | 40.7k | } |
189 | 50.3k | len += bytestream2_get_byte(gb) + 31; |
190 | 50.3k | } |
191 | 184k | i = bytestream2_get_le16(gb); |
192 | 184k | pos = - (i >> 2) - 1; |
193 | | |
194 | 184k | bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start); |
195 | 184k | bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET); |
196 | | |
197 | 184k | if (len < 6 || bytestream2_tell_p(pb) - bytestream2_tell(&gbc) < 4) { |
198 | 18.4k | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
199 | 18.4k | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
200 | 6.80M | do { |
201 | 6.80M | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
202 | 6.80M | --len; |
203 | 6.80M | } while (len); |
204 | 165k | } else { |
205 | 165k | bytestream2_put_le32(pb, bytestream2_get_le32(&gbc)); |
206 | 55.5M | for (len = len - 2; len; --len) |
207 | 55.4M | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
208 | 165k | } |
209 | 184k | len = i & 3; |
210 | 184k | if (!len) { |
211 | 37.1k | repeat = 1; |
212 | 147k | } else { |
213 | 347k | do { |
214 | 347k | bytestream2_put_byte(pb, bytestream2_get_byte(gb)); |
215 | 347k | --len; |
216 | 347k | } while (len); |
217 | 147k | opcode = bytestream2_peek_byte(gb); |
218 | 147k | } |
219 | 184k | } |
220 | 535k | bytestream2_skip(gb, 1); |
221 | 535k | if (opcode < 0x10) { |
222 | 396k | pos = -(opcode >> 2) - 1 - 4 * bytestream2_get_byte(gb); |
223 | | |
224 | 396k | bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start); |
225 | 396k | bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET); |
226 | | |
227 | 396k | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
228 | 396k | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
229 | 396k | len = opcode & 3; |
230 | 396k | if (!len) { |
231 | 142k | repeat = 1; |
232 | 253k | } else { |
233 | 473k | do { |
234 | 473k | bytestream2_put_byte(pb, bytestream2_get_byte(gb)); |
235 | 473k | --len; |
236 | 473k | } while (len); |
237 | 253k | opcode = bytestream2_peek_byte(gb); |
238 | 253k | } |
239 | 396k | continue; |
240 | 396k | } |
241 | 139k | len = opcode & 7; |
242 | 139k | if (!len) { |
243 | 13.6k | if (!bytestream2_peek_byte(gb)) { |
244 | 196k | do { |
245 | 196k | bytestream2_skip(gb, 1); |
246 | 196k | len += 255; |
247 | 196k | } while (!bytestream2_peek_byte(gb) && bytestream2_get_bytes_left(gb) > 0); |
248 | 9.67k | } |
249 | 13.6k | len += bytestream2_get_byte(gb) + 7; |
250 | 13.6k | } |
251 | 139k | i = bytestream2_get_le16(gb); |
252 | 139k | pos = bytestream2_tell_p(pb) - 2048 * (opcode & 8); |
253 | 139k | pos = pos - (i >> 2); |
254 | 139k | if (pos == bytestream2_tell_p(pb)) |
255 | 1.40k | break; |
256 | | |
257 | 138k | pos = pos - 0x4000; |
258 | 138k | bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start); |
259 | 138k | bytestream2_seek(&gbc, pos, SEEK_SET); |
260 | | |
261 | 138k | if (len < 6 || bytestream2_tell_p(pb) - bytestream2_tell(&gbc) < 4) { |
262 | 107k | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
263 | 107k | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
264 | 48.0M | do { |
265 | 48.0M | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
266 | 48.0M | --len; |
267 | 48.0M | } while (len); |
268 | 107k | } else { |
269 | 30.4k | bytestream2_put_le32(pb, bytestream2_get_le32(&gbc)); |
270 | 3.73M | for (len = len - 2; len; --len) |
271 | 3.70M | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
272 | 30.4k | } |
273 | | |
274 | 138k | len = i & 3; |
275 | 138k | if (!len) { |
276 | 13.4k | repeat = 1; |
277 | 124k | } else { |
278 | 171k | do { |
279 | 171k | bytestream2_put_byte(pb, bytestream2_get_byte(gb)); |
280 | 171k | --len; |
281 | 171k | } while (len); |
282 | 124k | opcode = bytestream2_peek_byte(gb); |
283 | 124k | } |
284 | 138k | } |
285 | | |
286 | 13.8k | return 0; |
287 | 13.8k | } |
288 | | |
289 | | static int decode_type1(GetByteContext *gb, PutByteContext *pb) |
290 | 139k | { |
291 | 139k | unsigned opcode = 0, len; |
292 | 139k | int high = 0; |
293 | 139k | int i, pos; |
294 | | |
295 | 180k | while (bytestream2_get_bytes_left(gb) > 0) { |
296 | 179k | GetByteContext gbc; |
297 | | |
298 | 675k | while (bytestream2_get_bytes_left(gb) > 0) { |
299 | 545k | while (bytestream2_get_bytes_left(gb) > 0) { |
300 | 543k | opcode = bytestream2_get_byte(gb); |
301 | 543k | high = opcode >= 0x20; |
302 | 543k | if (high) |
303 | 512k | break; |
304 | 30.4k | if (opcode) |
305 | 14.5k | break; |
306 | 15.8k | opcode = bytestream2_get_byte(gb); |
307 | 15.8k | if (opcode < 0xF8) { |
308 | 13.2k | opcode += 32; |
309 | 13.2k | break; |
310 | 13.2k | } |
311 | 2.63k | i = opcode - 0xF8; |
312 | 2.63k | if (i) { |
313 | 2.19k | len = 256; |
314 | 13.6k | do { |
315 | 13.6k | len *= 2; |
316 | 13.6k | --i; |
317 | 13.6k | } while (i); |
318 | 2.19k | } else { |
319 | 443 | len = 280; |
320 | 443 | } |
321 | 962k | do { |
322 | 962k | bytestream2_put_le32(pb, bytestream2_get_le32(gb)); |
323 | 962k | bytestream2_put_le32(pb, bytestream2_get_le32(gb)); |
324 | 962k | len -= 8; |
325 | 962k | } while (len && bytestream2_get_bytes_left(gb) > 0); |
326 | 2.63k | } |
327 | | |
328 | 542k | if (!high) { |
329 | 452k | do { |
330 | 452k | bytestream2_put_byte(pb, bytestream2_get_byte(gb)); |
331 | 452k | --opcode; |
332 | 452k | } while (opcode && bytestream2_get_bytes_left(gb) > 0); |
333 | | |
334 | 384k | while (bytestream2_get_bytes_left(gb) > 0) { |
335 | 376k | GetByteContext gbc; |
336 | | |
337 | 376k | opcode = bytestream2_get_byte(gb); |
338 | 376k | if (opcode >= 0x20) |
339 | 22.5k | break; |
340 | 354k | bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start); |
341 | | |
342 | 354k | pos = -(opcode | 32 * bytestream2_get_byte(gb)) - 1; |
343 | 354k | bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET); |
344 | 354k | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
345 | 354k | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
346 | 354k | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
347 | 354k | bytestream2_put_byte(pb, bytestream2_get_byte(gb)); |
348 | 354k | } |
349 | 29.9k | } |
350 | 542k | high = 0; |
351 | 542k | if (opcode < 0x40) |
352 | 46.5k | break; |
353 | 496k | bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start); |
354 | 496k | pos = (-((opcode & 0x1F) | 32 * bytestream2_get_byte(gb)) - 1); |
355 | 496k | bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET); |
356 | 496k | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
357 | 496k | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
358 | 496k | len = (opcode >> 5) - 1; |
359 | 2.64M | do { |
360 | 2.64M | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
361 | 2.64M | --len; |
362 | 2.64M | } while (len && bytestream2_get_bytes_left(&gbc) > 0); |
363 | 496k | } |
364 | 179k | len = opcode & 0x1F; |
365 | 179k | if (!len) { |
366 | 9.12k | if (!bytestream2_peek_byte(gb)) { |
367 | 1.58M | do { |
368 | 1.58M | bytestream2_skip(gb, 1); |
369 | 1.58M | len += 255; |
370 | 1.58M | } while (!bytestream2_peek_byte(gb) && bytestream2_get_bytes_left(gb) > 0); |
371 | 6.48k | } |
372 | 9.12k | len += bytestream2_get_byte(gb) + 31; |
373 | 9.12k | } |
374 | 179k | pos = -bytestream2_get_byte(gb); |
375 | 179k | bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start); |
376 | 179k | bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos - (bytestream2_get_byte(gb) << 8), SEEK_SET); |
377 | 179k | if (bytestream2_tell_p(pb) == bytestream2_tell(&gbc)) |
378 | 138k | break; |
379 | 41.0k | if (len < 5 || bytestream2_tell_p(pb) - bytestream2_tell(&gbc) < 4) { |
380 | 3.68k | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
381 | 3.68k | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
382 | 3.68k | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
383 | 37.4k | } else { |
384 | 37.4k | bytestream2_put_le32(pb, bytestream2_get_le32(&gbc)); |
385 | 37.4k | len--; |
386 | 37.4k | } |
387 | 389M | do { |
388 | 389M | bytestream2_put_byte(pb, bytestream2_get_byte(&gbc)); |
389 | 389M | len--; |
390 | 389M | } while (len && bytestream2_get_bytes_left(&gbc) > 0); |
391 | 41.0k | } |
392 | | |
393 | 139k | return 0; |
394 | 139k | } |
395 | | |
396 | | static int decode_frame(AVCodecContext *avctx, AVFrame *frame, |
397 | | int *got_frame, AVPacket *avpkt) |
398 | 265k | { |
399 | 265k | FMVCContext *s = avctx->priv_data; |
400 | 265k | GetByteContext *gb = &s->gb; |
401 | 265k | PutByteContext *pb = &s->pb; |
402 | 265k | int ret, y, x; |
403 | 265k | int key_frame; |
404 | | |
405 | 265k | if (avpkt->size < 8) |
406 | 100k | return AVERROR_INVALIDDATA; |
407 | | |
408 | 164k | bytestream2_init(gb, avpkt->data, avpkt->size); |
409 | 164k | bytestream2_skip(gb, 2); |
410 | | |
411 | 164k | key_frame = !!bytestream2_get_le16(gb); |
412 | | |
413 | 164k | if (key_frame) { |
414 | 148k | const uint8_t *src; |
415 | 148k | unsigned type, size; |
416 | 148k | uint8_t *dst; |
417 | | |
418 | 148k | type = bytestream2_get_le16(gb); |
419 | 148k | size = bytestream2_get_le16(gb); |
420 | 148k | if (size > bytestream2_get_bytes_left(gb)) |
421 | 6.28k | return AVERROR_INVALIDDATA; |
422 | | |
423 | 142k | bytestream2_init_writer(pb, s->buffer, s->buffer_size); |
424 | 142k | if (type == 1) { |
425 | 138k | decode_type1(gb, pb); |
426 | 138k | } else if (type == 2){ |
427 | 2.21k | decode_type2(gb, pb); |
428 | 2.21k | } else { |
429 | 1.14k | avpriv_report_missing_feature(avctx, "Compression type %d", type); |
430 | 1.14k | return AVERROR_PATCHWELCOME; |
431 | 1.14k | } |
432 | | |
433 | 141k | if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) |
434 | 64 | return ret; |
435 | | |
436 | 141k | frame->flags |= AV_FRAME_FLAG_KEY; |
437 | 141k | frame->pict_type = AV_PICTURE_TYPE_I; |
438 | | |
439 | 141k | src = s->buffer; |
440 | 141k | dst = frame->data[0] + (avctx->height - 1) * frame->linesize[0]; |
441 | 1.00M | for (y = 0; y < avctx->height; y++) { |
442 | 998k | memcpy(dst, src, avctx->width * s->bpp); |
443 | 998k | dst -= frame->linesize[0]; |
444 | 998k | src += s->stride * 4; |
445 | 998k | if (bytestream2_tell_p(pb) < y*s->stride * 4) |
446 | 136k | break; |
447 | 998k | } |
448 | 141k | } else { |
449 | 15.6k | unsigned block, nb_blocks; |
450 | 15.6k | int type, k, l; |
451 | 15.6k | uint8_t *ssrc, *ddst; |
452 | 15.6k | const uint32_t *src; |
453 | 15.6k | uint32_t *dst; |
454 | | |
455 | 1.15M | for (block = 0; block < s->nb_blocks; block++) |
456 | 1.14M | s->blocks[block].xor = 0; |
457 | | |
458 | 15.6k | nb_blocks = bytestream2_get_le16(gb); |
459 | 15.6k | if (nb_blocks > s->nb_blocks) |
460 | 1.17k | return AVERROR_INVALIDDATA; |
461 | | |
462 | 14.4k | bytestream2_init_writer(pb, s->pbuffer, s->pbuffer_size); |
463 | | |
464 | 14.4k | type = bytestream2_get_le16(gb); |
465 | 18.9k | for (block = 0; block < nb_blocks; block++) { |
466 | 13.9k | unsigned size, offset; |
467 | 13.9k | int start = 0; |
468 | | |
469 | 13.9k | offset = bytestream2_get_le16(gb); |
470 | 13.9k | if (offset >= s->nb_blocks) |
471 | 770 | return AVERROR_INVALIDDATA; |
472 | | |
473 | 13.1k | size = bytestream2_get_le16(gb); |
474 | 13.1k | if (size > bytestream2_get_bytes_left(gb)) |
475 | 691 | return AVERROR_INVALIDDATA; |
476 | | |
477 | 12.4k | start = bytestream2_tell_p(pb); |
478 | 12.4k | if (type == 1) { |
479 | 221 | decode_type1(gb, pb); |
480 | 12.2k | } else if (type == 2){ |
481 | 11.6k | decode_type2(gb, pb); |
482 | 11.6k | } else { |
483 | 605 | avpriv_report_missing_feature(avctx, "Compression type %d", type); |
484 | 605 | return AVERROR_PATCHWELCOME; |
485 | 605 | } |
486 | | |
487 | 11.8k | if (s->blocks[offset].size * 4 != bytestream2_tell_p(pb) - start) |
488 | 7.37k | return AVERROR_INVALIDDATA; |
489 | | |
490 | 4.46k | s->blocks[offset].xor = 1; |
491 | 4.46k | } |
492 | | |
493 | 5.02k | src = (const uint32_t *)s->pbuffer; |
494 | 5.02k | dst = (uint32_t *)s->buffer; |
495 | | |
496 | 46.0k | for (block = 0, y = 0; y < s->yb; y++) { |
497 | 41.0k | int block_h = s->blocks[block].h; |
498 | 41.0k | uint32_t *rect = dst; |
499 | | |
500 | 185k | for (x = 0; x < s->xb; x++) { |
501 | 144k | int block_w = s->blocks[block].w; |
502 | 144k | uint32_t *row = dst; |
503 | | |
504 | 144k | block_h = s->blocks[block].h; |
505 | 144k | if (s->blocks[block].xor) { |
506 | 243k | for (k = 0; k < block_h; k++) { |
507 | 239k | uint32_t *column = dst; |
508 | 10.2M | for (l = 0; l < block_w; l++) |
509 | 9.97M | *dst++ ^= *src++; |
510 | 239k | dst = &column[s->stride]; |
511 | 239k | } |
512 | 4.39k | } |
513 | 144k | dst = &row[block_w]; |
514 | 144k | ++block; |
515 | 144k | } |
516 | 41.0k | dst = &rect[block_h * s->stride]; |
517 | 41.0k | } |
518 | | |
519 | 5.02k | if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) |
520 | 27 | return ret; |
521 | | |
522 | 4.99k | frame->flags &= ~AV_FRAME_FLAG_KEY; |
523 | 4.99k | frame->pict_type = AV_PICTURE_TYPE_P; |
524 | | |
525 | 4.99k | ssrc = s->buffer; |
526 | 4.99k | ddst = frame->data[0] + (avctx->height - 1) * frame->linesize[0]; |
527 | 3.79M | for (y = 0; y < avctx->height; y++) { |
528 | 3.79M | memcpy(ddst, ssrc, avctx->width * s->bpp); |
529 | 3.79M | ddst -= frame->linesize[0]; |
530 | 3.79M | ssrc += s->stride * 4; |
531 | 3.79M | } |
532 | 4.99k | } |
533 | | |
534 | 146k | *got_frame = 1; |
535 | | |
536 | 146k | return avpkt->size; |
537 | 164k | } |
538 | | |
539 | | static av_cold int decode_init(AVCodecContext *avctx) |
540 | 1.51k | { |
541 | 1.51k | FMVCContext *s = avctx->priv_data; |
542 | 1.51k | int i, j, m, block = 0, h = BLOCK_HEIGHT, w = BLOCK_WIDTH; |
543 | | |
544 | 1.51k | switch (avctx->bits_per_coded_sample) { |
545 | 500 | case 16: |
546 | 500 | avctx->pix_fmt = AV_PIX_FMT_RGB555LE; |
547 | 500 | break; |
548 | 122 | case 24: |
549 | 122 | avctx->pix_fmt = AV_PIX_FMT_BGR24; |
550 | 122 | break; |
551 | 758 | case 32: |
552 | 758 | avctx->pix_fmt = AV_PIX_FMT_BGRA; |
553 | 758 | break; |
554 | 134 | default: |
555 | 134 | av_log(avctx, AV_LOG_ERROR, "Unsupported bitdepth %i\n", |
556 | 134 | avctx->bits_per_coded_sample); |
557 | 134 | return AVERROR_INVALIDDATA; |
558 | 1.51k | } |
559 | | |
560 | 1.38k | s->stride = (avctx->width * avctx->bits_per_coded_sample + 31) / 32; |
561 | 1.38k | s->xb = s->stride / BLOCK_WIDTH; |
562 | 1.38k | m = s->stride % BLOCK_WIDTH; |
563 | 1.38k | if (m) { |
564 | 1.36k | if (m < 37) { |
565 | 300 | w = m + BLOCK_WIDTH; |
566 | 1.06k | } else { |
567 | 1.06k | w = m; |
568 | 1.06k | s->xb++; |
569 | 1.06k | } |
570 | 1.36k | } |
571 | | |
572 | 1.38k | s->yb = avctx->height / BLOCK_HEIGHT; |
573 | 1.38k | m = avctx->height % BLOCK_HEIGHT; |
574 | 1.38k | if (m) { |
575 | 1.36k | if (m < 49) { |
576 | 330 | h = m + BLOCK_HEIGHT; |
577 | 1.03k | } else { |
578 | 1.03k | h = m; |
579 | 1.03k | s->yb++; |
580 | 1.03k | } |
581 | 1.36k | } |
582 | | |
583 | 1.38k | s->nb_blocks = s->xb * s->yb; |
584 | 1.38k | if (!s->nb_blocks) |
585 | 8 | return AVERROR_INVALIDDATA; |
586 | 1.37k | s->blocks = av_calloc(s->nb_blocks, sizeof(*s->blocks)); |
587 | 1.37k | if (!s->blocks) |
588 | 0 | return AVERROR(ENOMEM); |
589 | | |
590 | 91.3k | for (i = 0; i < s->yb; i++) { |
591 | 416k | for (j = 0; j < s->xb; j++) { |
592 | 326k | if (i != (s->yb - 1) || j != (s->xb - 1)) { |
593 | 325k | if (i == s->yb - 1) { |
594 | 132k | s->blocks[block].w = BLOCK_WIDTH; |
595 | 132k | s->blocks[block].h = h; |
596 | 132k | s->blocks[block].size = BLOCK_WIDTH * h; |
597 | 192k | } else if (j == s->xb - 1) { |
598 | 88.5k | s->blocks[block].w = w; |
599 | 88.5k | s->blocks[block].h = BLOCK_HEIGHT; |
600 | 88.5k | s->blocks[block].size = BLOCK_HEIGHT * w; |
601 | 103k | } else { |
602 | 103k | s->blocks[block].w = BLOCK_WIDTH; |
603 | 103k | s->blocks[block].h = BLOCK_HEIGHT; |
604 | 103k | s->blocks[block].size = BLOCK_WIDTH * BLOCK_HEIGHT; |
605 | 103k | } |
606 | 325k | } else { |
607 | 1.37k | s->blocks[block].w = w; |
608 | 1.37k | s->blocks[block].h = h; |
609 | 1.37k | s->blocks[block].size = w * h; |
610 | 1.37k | } |
611 | 326k | block++; |
612 | 326k | } |
613 | 89.9k | } |
614 | | |
615 | 1.37k | s->bpp = avctx->bits_per_coded_sample >> 3; |
616 | 1.37k | s->buffer_size = avctx->width * avctx->height * 4; |
617 | 1.37k | s->pbuffer_size = avctx->width * avctx->height * 4; |
618 | 1.37k | s->buffer = av_mallocz(s->buffer_size); |
619 | 1.37k | s->pbuffer = av_mallocz(s->pbuffer_size); |
620 | 1.37k | if (!s->buffer || !s->pbuffer) |
621 | 0 | return AVERROR(ENOMEM); |
622 | | |
623 | 1.37k | return 0; |
624 | 1.37k | } |
625 | | |
626 | | static av_cold int decode_close(AVCodecContext *avctx) |
627 | 1.51k | { |
628 | 1.51k | FMVCContext *s = avctx->priv_data; |
629 | | |
630 | 1.51k | av_freep(&s->buffer); |
631 | 1.51k | av_freep(&s->pbuffer); |
632 | 1.51k | av_freep(&s->blocks); |
633 | | |
634 | 1.51k | return 0; |
635 | 1.51k | } |
636 | | |
637 | | const FFCodec ff_fmvc_decoder = { |
638 | | .p.name = "fmvc", |
639 | | CODEC_LONG_NAME("FM Screen Capture Codec"), |
640 | | .p.type = AVMEDIA_TYPE_VIDEO, |
641 | | .p.id = AV_CODEC_ID_FMVC, |
642 | | .priv_data_size = sizeof(FMVCContext), |
643 | | .init = decode_init, |
644 | | .close = decode_close, |
645 | | FF_CODEC_DECODE_CB(decode_frame), |
646 | | .p.capabilities = AV_CODEC_CAP_DR1, |
647 | | .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, |
648 | | }; |