| 
							- /*
 -  * FM Screen Capture Codec decoder
 -  *
 -  * Copyright (c) 2017 Paul B Mahol
 -  *
 -  * This file is part of FFmpeg.
 -  *
 -  * FFmpeg is free software; you can redistribute it and/or
 -  * modify it under the terms of the GNU Lesser General Public
 -  * License as published by the Free Software Foundation; either
 -  * version 2.1 of the License, or (at your option) any later version.
 -  *
 -  * FFmpeg is distributed in the hope that it will be useful,
 -  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 -  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 -  * Lesser General Public License for more details.
 -  *
 -  * You should have received a copy of the GNU Lesser General Public
 -  * License along with FFmpeg; if not, write to the Free Software
 -  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 -  */
 - 
 - #include <stdio.h>
 - #include <stdlib.h>
 - #include <string.h>
 - 
 - #include "avcodec.h"
 - #include "bytestream.h"
 - #include "internal.h"
 - 
 - #define BLOCK_HEIGHT 112u
 - #define BLOCK_WIDTH  84u
 - 
 - typedef struct InterBlock {
 -     int      w, h;
 -     int      size;
 -     int      xor;
 - } InterBlock;
 - 
 - typedef struct FMVCContext {
 -     GetByteContext  gb;
 -     PutByteContext  pb;
 -     uint8_t        *buffer;
 -     size_t          buffer_size;
 -     uint8_t        *pbuffer;
 -     size_t          pbuffer_size;
 -     ptrdiff_t       stride;
 -     int             bpp;
 -     int             yb, xb;
 -     InterBlock     *blocks;
 -     unsigned        nb_blocks;
 - } FMVCContext;
 - 
 - static int decode_type2(GetByteContext *gb, PutByteContext *pb)
 - {
 -     unsigned repeat = 0, first = 1, opcode = 0;
 -     int i, len, pos;
 - 
 -     while (bytestream2_get_bytes_left(gb) > 0) {
 -         GetByteContext gbc;
 - 
 -         while (bytestream2_get_bytes_left(gb) > 0) {
 -             if (first) {
 -                 first = 0;
 -                 if (bytestream2_peek_byte(gb) > 17) {
 -                     len = bytestream2_get_byte(gb) - 17;
 -                     if (len < 4) {
 -                         do {
 -                             bytestream2_put_byte(pb, bytestream2_get_byte(gb));
 -                             --len;
 -                         } while (len);
 -                         opcode = bytestream2_peek_byte(gb);
 -                         continue;
 -                     } else {
 -                         do {
 -                             bytestream2_put_byte(pb, bytestream2_get_byte(gb));
 -                             --len;
 -                         } while (len);
 -                         opcode = bytestream2_peek_byte(gb);
 -                         if (opcode < 0x10) {
 -                             bytestream2_skip(gb, 1);
 -                             pos = - (opcode >> 2) - 4 * bytestream2_get_byte(gb) - 2049;
 - 
 -                             bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
 -                             bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
 - 
 -                             bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -                             bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -                             bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -                             len = opcode & 3;
 -                             if (!len) {
 -                                 repeat = 1;
 -                             } else {
 -                                 do {
 -                                     bytestream2_put_byte(pb, bytestream2_get_byte(gb));
 -                                     --len;
 -                                 } while (len);
 -                                 opcode = bytestream2_peek_byte(gb);
 -                             }
 -                             continue;
 -                         }
 -                     }
 -                     repeat = 0;
 -                 }
 -                 repeat = 1;
 -             }
 -             if (repeat) {
 -                 repeat = 0;
 -                 opcode = bytestream2_peek_byte(gb);
 -                 if (opcode < 0x10) {
 -                     bytestream2_skip(gb, 1);
 -                     if (!opcode) {
 -                         if (!bytestream2_peek_byte(gb)) {
 -                             do {
 -                                 bytestream2_skip(gb, 1);
 -                                 opcode += 255;
 -                             } while (!bytestream2_peek_byte(gb) && bytestream2_get_bytes_left(gb) > 0);
 -                         }
 -                         opcode += bytestream2_get_byte(gb) + 15;
 -                     }
 -                     bytestream2_put_le32(pb, bytestream2_get_le32(gb));
 -                     for (i = opcode - 1; i > 0; --i)
 -                         bytestream2_put_byte(pb, bytestream2_get_byte(gb));
 -                     opcode = bytestream2_peek_byte(gb);
 -                     if (opcode < 0x10) {
 -                         bytestream2_skip(gb, 1);
 -                         pos = - (opcode >> 2) - 4 * bytestream2_get_byte(gb) - 2049;
 - 
 -                         bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
 -                         bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
 - 
 -                         bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -                         bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -                         bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -                         len = opcode & 3;
 -                         if (!len) {
 -                             repeat = 1;
 -                         } else {
 -                             do {
 -                                 bytestream2_put_byte(pb, bytestream2_get_byte(gb));
 -                                 --len;
 -                             } while (len);
 -                             opcode = bytestream2_peek_byte(gb);
 -                         }
 -                         continue;
 -                     }
 -                 }
 -             }
 - 
 -             if (opcode >= 0x40) {
 -                 bytestream2_skip(gb, 1);
 -                 pos = - ((opcode >> 2) & 7) - 1 - 8 * bytestream2_get_byte(gb);
 -                 len =    (opcode >> 5)      - 1;
 - 
 -                 bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
 -                 bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
 - 
 -                 bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -                 bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -                 do {
 -                     bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -                     --len;
 -                 } while (len);
 - 
 -                 len = opcode & 3;
 - 
 -                 if (!len) {
 -                     repeat = 1;
 -                 } else {
 -                     do {
 -                         bytestream2_put_byte(pb, bytestream2_get_byte(gb));
 -                         --len;
 -                     } while (len);
 -                     opcode = bytestream2_peek_byte(gb);
 -                 }
 -                 continue;
 -             } else if (opcode < 0x20) {
 -                 break;
 -             }
 -             len = opcode & 0x1F;
 -             bytestream2_skip(gb, 1);
 -             if (!len) {
 -                 if (!bytestream2_peek_byte(gb)) {
 -                     do {
 -                         bytestream2_skip(gb, 1);
 -                         len += 255;
 -                     } while (!bytestream2_peek_byte(gb) && bytestream2_get_bytes_left(gb) > 0);
 -                 }
 -                 len += bytestream2_get_byte(gb) + 31;
 -             }
 -             i = bytestream2_get_le16(gb);
 -             pos = - (i >> 2) - 1;
 - 
 -             bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
 -             bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
 - 
 -             if (len < 6 || bytestream2_tell_p(pb) - bytestream2_tell(&gbc) < 4) {
 -                 bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -                 bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -                 do {
 -                     bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -                     --len;
 -                 } while (len);
 -             } else {
 -                 bytestream2_put_le32(pb, bytestream2_get_le32(&gbc));
 -                 for (len = len - 2; len; --len)
 -                     bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -             }
 -             len = i & 3;
 -             if (!len) {
 -                 repeat = 1;
 -             } else {
 -                 do {
 -                     bytestream2_put_byte(pb, bytestream2_get_byte(gb));
 -                     --len;
 -                 } while (len);
 -                 opcode = bytestream2_peek_byte(gb);
 -             }
 -         }
 -         bytestream2_skip(gb, 1);
 -         if (opcode < 0x10) {
 -             pos = -(opcode >> 2) - 1 - 4 * bytestream2_get_byte(gb);
 - 
 -             bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
 -             bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
 - 
 -             bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -             bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -             len = opcode & 3;
 -             if (!len) {
 -                 repeat = 1;
 -             } else {
 -                 do {
 -                     bytestream2_put_byte(pb, bytestream2_get_byte(gb));
 -                     --len;
 -                 } while (len);
 -                 opcode = bytestream2_peek_byte(gb);
 -             }
 -             continue;
 -         }
 -         len = opcode & 7;
 -         if (!len) {
 -             if (!bytestream2_peek_byte(gb)) {
 -                 do {
 -                     bytestream2_skip(gb, 1);
 -                     len += 255;
 -                 } while (!bytestream2_peek_byte(gb) && bytestream2_get_bytes_left(gb) > 0);
 -             }
 -             len += bytestream2_get_byte(gb) + 7;
 -         }
 -         i = bytestream2_get_le16(gb);
 -         pos = bytestream2_tell_p(pb) - 2048 * (opcode & 8);
 -         pos = pos - (i >> 2);
 -         if (pos == bytestream2_tell_p(pb))
 -             break;
 - 
 -         pos = pos - 0x4000;
 -         bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
 -         bytestream2_seek(&gbc, pos, SEEK_SET);
 - 
 -         if (len < 6 || bytestream2_tell_p(pb) - bytestream2_tell(&gbc) < 4) {
 -             bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -             bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -             do {
 -                 bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -                 --len;
 -             } while (len);
 -         } else {
 -             bytestream2_put_le32(pb, bytestream2_get_le32(&gbc));
 -             for (len = len - 2; len; --len)
 -                 bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -         }
 - 
 -         len = i & 3;
 -         if (!len) {
 -             repeat = 1;
 -         } else {
 -             do {
 -                 bytestream2_put_byte(pb, bytestream2_get_byte(gb));
 -                 --len;
 -             } while (len);
 -             opcode = bytestream2_peek_byte(gb);
 -         }
 -     }
 - 
 -     return 0;
 - }
 - 
 - static int decode_type1(GetByteContext *gb, PutByteContext *pb)
 - {
 -     unsigned opcode = 0, len;
 -     int high = 0;
 -     int i, pos;
 - 
 -     while (bytestream2_get_bytes_left(gb) > 0) {
 -         GetByteContext gbc;
 - 
 -         while (bytestream2_get_bytes_left(gb) > 0) {
 -             while (bytestream2_get_bytes_left(gb) > 0) {
 -                 opcode = bytestream2_get_byte(gb);
 -                 high = opcode >= 0x20;
 -                 if (high)
 -                     break;
 -                 if (opcode)
 -                     break;
 -                 opcode = bytestream2_get_byte(gb);
 -                 if (opcode < 0xF8) {
 -                     opcode += 32;
 -                     break;
 -                 }
 -                 i = opcode - 0xF8;
 -                 if (i) {
 -                     len = 256;
 -                     do {
 -                         len *= 2;
 -                         --i;
 -                     } while (i);
 -                 } else {
 -                     len = 280;
 -                 }
 -                 do {
 -                     bytestream2_put_le32(pb, bytestream2_get_le32(gb));
 -                     bytestream2_put_le32(pb, bytestream2_get_le32(gb));
 -                     len -= 8;
 -                 } while (len && bytestream2_get_bytes_left(gb) > 0);
 -             }
 - 
 -             if (!high) {
 -                 do {
 -                     bytestream2_put_byte(pb, bytestream2_get_byte(gb));
 -                     --opcode;
 -                 } while (opcode && bytestream2_get_bytes_left(gb) > 0);
 - 
 -                 while (bytestream2_get_bytes_left(gb) > 0) {
 -                     GetByteContext gbc;
 - 
 -                     opcode = bytestream2_get_byte(gb);
 -                     if (opcode >= 0x20)
 -                         break;
 -                     bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
 - 
 -                     pos = -(opcode | 32 * bytestream2_get_byte(gb)) - 1;
 -                     bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
 -                     bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -                     bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -                     bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -                     bytestream2_put_byte(pb, bytestream2_get_byte(gb));
 -                 }
 -             }
 -             high = 0;
 -             if (opcode < 0x40)
 -                 break;
 -             bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
 -             pos = (-((opcode & 0x1F) | 32 * bytestream2_get_byte(gb)) - 1);
 -             bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
 -             bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -             bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -             len = (opcode >> 5) - 1;
 -             do {
 -                 bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -                 --len;
 -             } while (len && bytestream2_get_bytes_left(&gbc) > 0);
 -         }
 -         len = opcode & 0x1F;
 -         if (!len) {
 -             if (!bytestream2_peek_byte(gb)) {
 -                 do {
 -                     bytestream2_skip(gb, 1);
 -                     len += 255;
 -                 } while (!bytestream2_peek_byte(gb) && bytestream2_get_bytes_left(gb) > 0);
 -             }
 -             len += bytestream2_get_byte(gb) + 31;
 -         }
 -         pos = -bytestream2_get_byte(gb);
 -         bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
 -         bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos - (bytestream2_get_byte(gb) << 8), SEEK_SET);
 -         if (bytestream2_tell_p(pb) == bytestream2_tell(&gbc))
 -             break;
 -         if (len < 5 || bytestream2_tell_p(pb) - bytestream2_tell(&gbc) < 4) {
 -             bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -             bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -             bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -         } else {
 -             bytestream2_put_le32(pb, bytestream2_get_le32(&gbc));
 -             len--;
 -         }
 -         do {
 -             bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
 -             len--;
 -         } while (len && bytestream2_get_bytes_left(&gbc) > 0);
 -     }
 - 
 -     return 0;
 - }
 - 
 - static int decode_frame(AVCodecContext *avctx, void *data,
 -                         int *got_frame, AVPacket *avpkt)
 - {
 -     FMVCContext *s = avctx->priv_data;
 -     GetByteContext *gb = &s->gb;
 -     PutByteContext *pb = &s->pb;
 -     AVFrame *frame = data;
 -     int ret, y, x;
 - 
 -     if (avpkt->size < 8)
 -         return AVERROR_INVALIDDATA;
 - 
 -     if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
 -         return ret;
 - 
 -     bytestream2_init(gb, avpkt->data, avpkt->size);
 -     bytestream2_skip(gb, 2);
 - 
 -     frame->key_frame = !!bytestream2_get_le16(gb);
 -     frame->pict_type = frame->key_frame ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
 - 
 -     if (frame->key_frame) {
 -         const uint8_t *src;
 -         unsigned type, size;
 -         uint8_t *dst;
 - 
 -         type = bytestream2_get_le16(gb);
 -         size = bytestream2_get_le16(gb);
 -         if (size > bytestream2_get_bytes_left(gb))
 -             return AVERROR_INVALIDDATA;
 - 
 -         bytestream2_init_writer(pb, s->buffer, s->buffer_size);
 -         if (type == 1) {
 -             decode_type1(gb, pb);
 -         } else if (type == 2){
 -             decode_type2(gb, pb);
 -         } else {
 -             avpriv_report_missing_feature(avctx, "Compression type %d", type);
 -             return AVERROR_PATCHWELCOME;
 -         }
 - 
 -         src = s->buffer;
 -         dst = frame->data[0] + (avctx->height - 1) * frame->linesize[0];
 -         for (y = 0; y < avctx->height; y++) {
 -             memcpy(dst, src, avctx->width * s->bpp);
 -             dst -= frame->linesize[0];
 -             src += s->stride * 4;
 -         }
 -     } else {
 -         unsigned block, nb_blocks;
 -         int type, k, l;
 -         uint8_t *ssrc, *ddst;
 -         const uint32_t *src;
 -         uint32_t *dst;
 - 
 -         for (block = 0; block < s->nb_blocks; block++)
 -             s->blocks[block].xor = 0;
 - 
 -         nb_blocks = bytestream2_get_le16(gb);
 -         if (nb_blocks > s->nb_blocks)
 -             return AVERROR_INVALIDDATA;
 - 
 -         bytestream2_init_writer(pb, s->pbuffer, s->pbuffer_size);
 - 
 -         type = bytestream2_get_le16(gb);
 -         for (block = 0; block < nb_blocks; block++) {
 -             unsigned size, offset;
 -             int start = 0;
 - 
 -             offset = bytestream2_get_le16(gb);
 -             if (offset >= s->nb_blocks)
 -                 return AVERROR_INVALIDDATA;
 - 
 -             size = bytestream2_get_le16(gb);
 -             if (size > bytestream2_get_bytes_left(gb))
 -                 return AVERROR_INVALIDDATA;
 - 
 -             start = bytestream2_tell_p(pb);
 -             if (type == 1) {
 -                 decode_type1(gb, pb);
 -             } else if (type == 2){
 -                 decode_type2(gb, pb);
 -             } else {
 -                 avpriv_report_missing_feature(avctx, "Compression type %d", type);
 -                 return AVERROR_PATCHWELCOME;
 -             }
 - 
 -             if (s->blocks[offset].size * 4 != bytestream2_tell_p(pb) - start)
 -                 return AVERROR_INVALIDDATA;
 - 
 -             s->blocks[offset].xor = 1;
 -         }
 - 
 -         src = (const uint32_t *)s->pbuffer;
 -         dst = (uint32_t *)s->buffer;
 - 
 -         for (block = 0, y = 0; y < s->yb; y++) {
 -             int block_h = s->blocks[block].h;
 -             uint32_t *rect = dst;
 - 
 -             for (x = 0; x < s->xb; x++) {
 -                 int block_w = s->blocks[block].w;
 -                 uint32_t *row = dst;
 - 
 -                 block_h = s->blocks[block].h;
 -                 if (s->blocks[block].xor) {
 -                     for (k = 0; k < block_h; k++) {
 -                         uint32_t *column = dst;
 -                         for (l = 0; l < block_w; l++)
 -                             *dst++ ^= *src++;
 -                         dst = &column[s->stride];
 -                     }
 -                 }
 -                 dst = &row[block_w];
 -                 ++block;
 -             }
 -             dst = &rect[block_h * s->stride];
 -         }
 - 
 -         ssrc = s->buffer;
 -         ddst = frame->data[0] + (avctx->height - 1) * frame->linesize[0];
 -         for (y = 0; y < avctx->height; y++) {
 -             memcpy(ddst, ssrc, avctx->width * s->bpp);
 -             ddst -= frame->linesize[0];
 -             ssrc += s->stride * 4;
 -         }
 -     }
 - 
 -     *got_frame = 1;
 - 
 -     return avpkt->size;
 - }
 - 
 - static av_cold int decode_init(AVCodecContext *avctx)
 - {
 -     FMVCContext *s = avctx->priv_data;
 -     int i, j, m, block = 0, h = BLOCK_HEIGHT, w = BLOCK_WIDTH;
 - 
 -     switch (avctx->bits_per_coded_sample) {
 -     case 16:
 -         avctx->pix_fmt = AV_PIX_FMT_RGB555LE;
 -         break;
 -     case 24:
 -         avctx->pix_fmt = AV_PIX_FMT_BGR24;
 -         break;
 -     case 32:
 -         avctx->pix_fmt = AV_PIX_FMT_BGRA;
 -         break;
 -     default:
 -         av_log(avctx, AV_LOG_ERROR, "Unsupported bitdepth %i\n",
 -                avctx->bits_per_coded_sample);
 -         return AVERROR_INVALIDDATA;
 -     }
 - 
 -     s->stride = (avctx->width * avctx->bits_per_coded_sample + 31) / 32;
 -     s->xb     = s->stride / BLOCK_WIDTH;
 -     m         = s->stride % BLOCK_WIDTH;
 -     if (m) {
 -         if (m < 37) {
 -             w = m + BLOCK_WIDTH;
 -         } else {
 -             w = m;
 -             s->xb++;
 -         }
 -     }
 - 
 -     s->yb = avctx->height / BLOCK_HEIGHT;
 -     m     = avctx->height % BLOCK_HEIGHT;
 -     if (m) {
 -         if (m < 49) {
 -             h = m + BLOCK_HEIGHT;
 -         } else {
 -             h = m;
 -             s->yb++;
 -         }
 -     }
 - 
 -     s->nb_blocks = s->xb * s->yb;
 -     if (!s->nb_blocks)
 -         return AVERROR_INVALIDDATA;
 -     s->blocks    = av_calloc(s->nb_blocks, sizeof(*s->blocks));
 -     if (!s->blocks)
 -         return AVERROR(ENOMEM);
 - 
 -     for (i = 0; i < s->yb; i++) {
 -         for (j = 0; j < s->xb; j++) {
 -             if (i != (s->yb - 1) || j != (s->xb - 1)) {
 -                 if (i == s->yb - 1) {
 -                     s->blocks[block].w    = BLOCK_WIDTH;
 -                     s->blocks[block].h    = h;
 -                     s->blocks[block].size = BLOCK_WIDTH * h;
 -                 } else if (j == s->xb - 1) {
 -                     s->blocks[block].w    = w;
 -                     s->blocks[block].h    = BLOCK_HEIGHT;
 -                     s->blocks[block].size = BLOCK_HEIGHT * w;
 -                 } else {
 -                     s->blocks[block].w    = BLOCK_WIDTH;
 -                     s->blocks[block].h    = BLOCK_HEIGHT;
 -                     s->blocks[block].size = BLOCK_WIDTH * BLOCK_HEIGHT;
 -                 }
 -             } else {
 -                 s->blocks[block].w    = w;
 -                 s->blocks[block].h    = h;
 -                 s->blocks[block].size = w * h;
 -             }
 -             block++;
 -         }
 -     }
 - 
 -     s->bpp          = avctx->bits_per_coded_sample >> 3;
 -     s->buffer_size  = avctx->width * avctx->height * 4;
 -     s->pbuffer_size = avctx->width * avctx->height * 4;
 -     s->buffer       = av_mallocz(s->buffer_size);
 -     s->pbuffer      = av_mallocz(s->pbuffer_size);
 -     if (!s->buffer || !s->pbuffer)
 -         return AVERROR(ENOMEM);
 - 
 -     return 0;
 - }
 - 
 - static av_cold int decode_close(AVCodecContext *avctx)
 - {
 -     FMVCContext *s = avctx->priv_data;
 - 
 -     av_freep(&s->buffer);
 -     av_freep(&s->pbuffer);
 -     av_freep(&s->blocks);
 - 
 -     return 0;
 - }
 - 
 - AVCodec ff_fmvc_decoder = {
 -     .name             = "fmvc",
 -     .long_name        = NULL_IF_CONFIG_SMALL("FM Screen Capture Codec"),
 -     .type             = AVMEDIA_TYPE_VIDEO,
 -     .id               = AV_CODEC_ID_FMVC,
 -     .priv_data_size   = sizeof(FMVCContext),
 -     .init             = decode_init,
 -     .close            = decode_close,
 -     .decode           = decode_frame,
 -     .capabilities     = AV_CODEC_CAP_DR1,
 -     .caps_internal    = FF_CODEC_CAP_INIT_THREADSAFE |
 -                         FF_CODEC_CAP_INIT_CLEANUP,
 - };
 
 
  |