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 
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 
decode_type2(GetByteContext *gb, PutByteContext *pb)55 static 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 
decode_type1(GetByteContext *gb, PutByteContext *pb)290 static 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 
decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame, AVPacket *avpkt)397 static 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 
decode_init(AVCodecContext *avctx)540 static 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 
decode_close(AVCodecContext *avctx)627 static 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 
638 const 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