LCOV - code coverage report
Current view: top level - libavcodec - fmvc.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 334 388 86.1 %
Date: 2017-12-17 16:07:53 Functions: 5 5 100.0 %

          Line data    Source code
       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 "internal.h"
      30             : 
      31             : #define BLOCK_HEIGHT 112u
      32             : #define BLOCK_WIDTH  84u
      33             : 
      34             : typedef struct InterBlock {
      35             :     int      w, h;
      36             :     int      size;
      37             :     int      xor;
      38             : } InterBlock;
      39             : 
      40             : typedef struct FMVCContext {
      41             :     GetByteContext  gb;
      42             :     PutByteContext  pb;
      43             :     uint8_t        *buffer;
      44             :     size_t          buffer_size;
      45             :     uint8_t        *pbuffer;
      46             :     size_t          pbuffer_size;
      47             :     ptrdiff_t       stride;
      48             :     int             bpp;
      49             :     int             yb, xb;
      50             :     InterBlock     *blocks;
      51             :     unsigned        nb_blocks;
      52             : } FMVCContext;
      53             : 
      54          72 : static int decode_type2(GetByteContext *gb, PutByteContext *pb)
      55             : {
      56          72 :     unsigned repeat = 0, first = 1, opcode = 0;
      57             :     int i, len, pos;
      58             : 
      59        4665 :     while (bytestream2_get_bytes_left(gb) > 0) {
      60             :         GetByteContext gbc;
      61             : 
      62       37694 :         while (bytestream2_get_bytes_left(gb) > 0) {
      63       33101 :             if (first) {
      64          72 :                 first = 0;
      65          72 :                 if (bytestream2_peek_byte(gb) > 17) {
      66          72 :                     len = bytestream2_get_byte(gb) - 17;
      67          72 :                     if (len < 4) {
      68             :                         do {
      69          65 :                             bytestream2_put_byte(pb, bytestream2_get_byte(gb));
      70          65 :                             --len;
      71          65 :                         } while (len);
      72          65 :                         opcode = bytestream2_peek_byte(gb);
      73          65 :                         continue;
      74             :                     } else {
      75             :                         do {
      76         103 :                             bytestream2_put_byte(pb, bytestream2_get_byte(gb));
      77         103 :                             --len;
      78         103 :                         } while (len);
      79           7 :                         opcode = bytestream2_peek_byte(gb);
      80           7 :                         if (opcode < 0x10) {
      81           0 :                             bytestream2_skip(gb, 1);
      82           0 :                             pos = - (opcode >> 2) - 4 * bytestream2_get_byte(gb) - 2049;
      83             : 
      84           0 :                             bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
      85           0 :                             bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
      86             : 
      87           0 :                             bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
      88           0 :                             bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
      89           0 :                             bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
      90           0 :                             len = opcode & 3;
      91           0 :                             if (!len) {
      92           0 :                                 repeat = 1;
      93             :                             } else {
      94             :                                 do {
      95           0 :                                     bytestream2_put_byte(pb, bytestream2_get_byte(gb));
      96           0 :                                     --len;
      97           0 :                                 } while (len);
      98           0 :                                 opcode = bytestream2_peek_byte(gb);
      99             :                             }
     100           0 :                             continue;
     101             :                         }
     102             :                     }
     103           7 :                     repeat = 0;
     104             :                 }
     105           7 :                 repeat = 1;
     106             :             }
     107       33036 :             if (repeat) {
     108       26608 :                 repeat = 0;
     109       26608 :                 opcode = bytestream2_peek_byte(gb);
     110       26608 :                 if (opcode < 0x10) {
     111         586 :                     bytestream2_skip(gb, 1);
     112         586 :                     if (!opcode) {
     113          82 :                         if (!bytestream2_peek_byte(gb)) {
     114             :                             do {
     115           0 :                                 bytestream2_skip(gb, 1);
     116           0 :                                 opcode += 255;
     117           0 :                             } while (!bytestream2_peek_byte(gb) && bytestream2_get_bytes_left(gb) > 0);
     118             :                         }
     119          82 :                         opcode += bytestream2_get_byte(gb) + 15;
     120             :                     }
     121         586 :                     bytestream2_put_le32(pb, bytestream2_get_le32(gb));
     122        4212 :                     for (i = opcode - 1; i > 0; --i)
     123        3626 :                         bytestream2_put_byte(pb, bytestream2_get_byte(gb));
     124         586 :                     opcode = bytestream2_peek_byte(gb);
     125         586 :                     if (opcode < 0x10) {
     126          28 :                         bytestream2_skip(gb, 1);
     127          28 :                         pos = - (opcode >> 2) - 4 * bytestream2_get_byte(gb) - 2049;
     128             : 
     129          28 :                         bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
     130          28 :                         bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
     131             : 
     132          28 :                         bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
     133          28 :                         bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
     134          28 :                         bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
     135          28 :                         len = opcode & 3;
     136          28 :                         if (!len) {
     137          22 :                             repeat = 1;
     138             :                         } else {
     139             :                             do {
     140          17 :                                 bytestream2_put_byte(pb, bytestream2_get_byte(gb));
     141          17 :                                 --len;
     142          17 :                             } while (len);
     143           6 :                             opcode = bytestream2_peek_byte(gb);
     144             :                         }
     145          28 :                         continue;
     146             :                     }
     147             :                 }
     148             :             }
     149             : 
     150       33008 :             if (opcode >= 0x40) {
     151        6293 :                 bytestream2_skip(gb, 1);
     152        6293 :                 pos = - ((opcode >> 2) & 7) - 1 - 8 * bytestream2_get_byte(gb);
     153        6293 :                 len =    (opcode >> 5)      - 1;
     154             : 
     155        6293 :                 bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
     156        6293 :                 bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
     157             : 
     158        6293 :                 bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
     159        6293 :                 bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
     160             :                 do {
     161       15169 :                     bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
     162       15169 :                     --len;
     163       15169 :                 } while (len);
     164             : 
     165        6293 :                 len = opcode & 3;
     166             : 
     167        6293 :                 if (!len) {
     168        3620 :                     repeat = 1;
     169             :                 } else {
     170             :                     do {
     171        4856 :                         bytestream2_put_byte(pb, bytestream2_get_byte(gb));
     172        4856 :                         --len;
     173        4856 :                     } while (len);
     174        2673 :                     opcode = bytestream2_peek_byte(gb);
     175             :                 }
     176        6293 :                 continue;
     177       26715 :             } else if (opcode < 0x20) {
     178        4593 :                 break;
     179             :             }
     180       22122 :             len = opcode & 0x1F;
     181       22122 :             bytestream2_skip(gb, 1);
     182       22122 :             if (!len) {
     183        7443 :                 if (!bytestream2_peek_byte(gb)) {
     184             :                     do {
     185        9973 :                         bytestream2_skip(gb, 1);
     186        9973 :                         len += 255;
     187        9973 :                     } while (!bytestream2_peek_byte(gb) && bytestream2_get_bytes_left(gb) > 0);
     188             :                 }
     189        7443 :                 len += bytestream2_get_byte(gb) + 31;
     190             :             }
     191       22122 :             i = bytestream2_get_le16(gb);
     192       22122 :             pos = - (i >> 2) - 1;
     193             : 
     194       22122 :             bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
     195       22122 :             bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
     196             : 
     197       25172 :             if (len < 6 || bytestream2_tell_p(pb) - bytestream2_tell(&gbc) < 4) {
     198        3050 :                 bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
     199        3050 :                 bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
     200             :                 do {
     201     1990991 :                     bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
     202     1990991 :                     --len;
     203     1990991 :                 } while (len);
     204             :             } else {
     205       19072 :                 bytestream2_put_le32(pb, bytestream2_get_le32(&gbc));
     206     1700600 :                 for (len = len - 2; len; --len)
     207     1681528 :                     bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
     208             :             }
     209       22122 :             len = i & 3;
     210       22122 :             if (!len) {
     211       19401 :                 repeat = 1;
     212             :             } else {
     213             :                 do {
     214        5082 :                     bytestream2_put_byte(pb, bytestream2_get_byte(gb));
     215        5082 :                     --len;
     216        5082 :                 } while (len);
     217        2721 :                 opcode = bytestream2_peek_byte(gb);
     218             :             }
     219             :         }
     220        4593 :         bytestream2_skip(gb, 1);
     221        4593 :         if (opcode < 0x10) {
     222         998 :             pos = -(opcode >> 2) - 1 - 4 * bytestream2_get_byte(gb);
     223             : 
     224         998 :             bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
     225         998 :             bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
     226             : 
     227         998 :             bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
     228         998 :             bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
     229         998 :             len = opcode & 3;
     230         998 :             if (!len) {
     231         371 :                 repeat = 1;
     232             :             } else {
     233             :                 do {
     234        1101 :                     bytestream2_put_byte(pb, bytestream2_get_byte(gb));
     235        1101 :                     --len;
     236        1101 :                 } while (len);
     237         627 :                 opcode = bytestream2_peek_byte(gb);
     238             :             }
     239         998 :             continue;
     240             :         }
     241        3595 :         len = opcode & 7;
     242        3595 :         if (!len) {
     243        3085 :             if (!bytestream2_peek_byte(gb)) {
     244             :                 do {
     245         411 :                     bytestream2_skip(gb, 1);
     246         411 :                     len += 255;
     247         411 :                 } while (!bytestream2_peek_byte(gb) && bytestream2_get_bytes_left(gb) > 0);
     248             :             }
     249        3085 :             len += bytestream2_get_byte(gb) + 7;
     250             :         }
     251        3595 :         i = bytestream2_get_le16(gb);
     252        3595 :         pos = bytestream2_tell_p(pb) - 2048 * (opcode & 8);
     253        3595 :         pos = pos - (i >> 2);
     254        3595 :         if (pos == bytestream2_tell_p(pb))
     255          72 :             break;
     256             : 
     257        3523 :         pos = pos - 0x4000;
     258        3523 :         bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
     259        3523 :         bytestream2_seek(&gbc, pos, SEEK_SET);
     260             : 
     261        3739 :         if (len < 6 || bytestream2_tell_p(pb) - bytestream2_tell(&gbc) < 4) {
     262         216 :             bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
     263         216 :             bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
     264             :             do {
     265         667 :                 bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
     266         667 :                 --len;
     267         667 :             } while (len);
     268             :         } else {
     269        3307 :             bytestream2_put_le32(pb, bytestream2_get_le32(&gbc));
     270      219261 :             for (len = len - 2; len; --len)
     271      215954 :                 bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
     272             :         }
     273             : 
     274        3523 :         len = i & 3;
     275        3523 :         if (!len) {
     276        3187 :             repeat = 1;
     277             :         } else {
     278             :             do {
     279         551 :                 bytestream2_put_byte(pb, bytestream2_get_byte(gb));
     280         551 :                 --len;
     281         551 :             } while (len);
     282         336 :             opcode = bytestream2_peek_byte(gb);
     283             :         }
     284             :     }
     285             : 
     286          72 :     return 0;
     287             : }
     288             : 
     289          42 : static int decode_type1(GetByteContext *gb, PutByteContext *pb)
     290             : {
     291          42 :     unsigned opcode = 0, len;
     292          42 :     int high = 0;
     293             :     int i, pos;
     294             : 
     295       10471 :     while (bytestream2_get_bytes_left(gb) > 0) {
     296             :         GetByteContext gbc;
     297             : 
     298       31871 :         while (bytestream2_get_bytes_left(gb) > 0) {
     299       42884 :             while (bytestream2_get_bytes_left(gb) > 0) {
     300       21442 :                 opcode = bytestream2_get_byte(gb);
     301       21442 :                 high = opcode >= 0x20;
     302       21442 :                 if (high)
     303       18221 :                     break;
     304        3221 :                 if (opcode)
     305        3220 :                     break;
     306           1 :                 opcode = bytestream2_get_byte(gb);
     307           1 :                 if (opcode < 0xF8) {
     308           1 :                     opcode += 32;
     309           1 :                     break;
     310             :                 }
     311           0 :                 i = opcode - 0xF8;
     312           0 :                 if (i) {
     313           0 :                     len = 256;
     314             :                     do {
     315           0 :                         len *= 2;
     316           0 :                         --i;
     317           0 :                     } while (i);
     318             :                 } else {
     319           0 :                     len = 280;
     320             :                 }
     321             :                 do {
     322           0 :                     bytestream2_put_le32(pb, bytestream2_get_le32(gb));
     323           0 :                     bytestream2_put_le32(pb, bytestream2_get_le32(gb));
     324           0 :                     len -= 8;
     325           0 :                 } while (len && bytestream2_get_bytes_left(gb) > 0);
     326             :             }
     327             : 
     328       21442 :             if (!high) {
     329             :                 do {
     330       11005 :                     bytestream2_put_byte(pb, bytestream2_get_byte(gb));
     331       11005 :                     --opcode;
     332       11005 :                 } while (opcode && bytestream2_get_bytes_left(gb) > 0);
     333             : 
     334        6444 :                 while (bytestream2_get_bytes_left(gb) > 0) {
     335             :                     GetByteContext gbc;
     336             : 
     337        3223 :                     opcode = bytestream2_get_byte(gb);
     338        3223 :                     if (opcode >= 0x20)
     339        3221 :                         break;
     340           2 :                     bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
     341             : 
     342           2 :                     pos = -(opcode | 32 * bytestream2_get_byte(gb)) - 1;
     343           2 :                     bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
     344           2 :                     bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
     345           2 :                     bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
     346           2 :                     bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
     347           2 :                     bytestream2_put_byte(pb, bytestream2_get_byte(gb));
     348             :                 }
     349             :             }
     350       21442 :             high = 0;
     351       21442 :             if (opcode < 0x40)
     352       10429 :                 break;
     353       11013 :             bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
     354       11013 :             pos = (-((opcode & 0x1F) | 32 * bytestream2_get_byte(gb)) - 1);
     355       11013 :             bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET);
     356       11013 :             bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
     357       11013 :             bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
     358       11013 :             len = (opcode >> 5) - 1;
     359             :             do {
     360       35434 :                 bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
     361       35434 :                 --len;
     362       35434 :             } while (len && bytestream2_get_bytes_left(&gbc) > 0);
     363             :         }
     364       10429 :         len = opcode & 0x1F;
     365       10429 :         if (!len) {
     366        3296 :             if (!bytestream2_peek_byte(gb)) {
     367             :                 do {
     368        7405 :                     bytestream2_skip(gb, 1);
     369        7405 :                     len += 255;
     370        7405 :                 } while (!bytestream2_peek_byte(gb) && bytestream2_get_bytes_left(gb) > 0);
     371             :             }
     372        3296 :             len += bytestream2_get_byte(gb) + 31;
     373             :         }
     374       10429 :         pos = -bytestream2_get_byte(gb);
     375       10429 :         bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start);
     376       10429 :         bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos - (bytestream2_get_byte(gb) << 8), SEEK_SET);
     377       10429 :         if (bytestream2_tell_p(pb) == bytestream2_tell(&gbc))
     378          42 :             break;
     379       10387 :         if (len < 5 || bytestream2_tell_p(pb) - bytestream2_tell(&gbc) < 4) {
     380        1068 :             bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
     381        1068 :             bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
     382        1068 :             bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
     383             :         } else {
     384        9319 :             bytestream2_put_le32(pb, bytestream2_get_le32(&gbc));
     385        9319 :             len--;
     386             :         }
     387             :         do {
     388     2411287 :             bytestream2_put_byte(pb, bytestream2_get_byte(&gbc));
     389     2411287 :             len--;
     390     2411287 :         } while (len && bytestream2_get_bytes_left(&gbc) > 0);
     391             :     }
     392             : 
     393          42 :     return 0;
     394             : }
     395             : 
     396          34 : static int decode_frame(AVCodecContext *avctx, void *data,
     397             :                         int *got_frame, AVPacket *avpkt)
     398             : {
     399          34 :     FMVCContext *s = avctx->priv_data;
     400          34 :     GetByteContext *gb = &s->gb;
     401          34 :     PutByteContext *pb = &s->pb;
     402          34 :     AVFrame *frame = data;
     403             :     int ret, y, x;
     404             : 
     405          34 :     if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
     406           0 :         return ret;
     407             : 
     408          34 :     bytestream2_init(gb, avpkt->data, avpkt->size);
     409          34 :     bytestream2_skip(gb, 2);
     410             : 
     411          34 :     frame->key_frame = !!bytestream2_get_le16(gb);
     412          34 :     frame->pict_type = frame->key_frame ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
     413             : 
     414          34 :     if (frame->key_frame) {
     415             :         const uint8_t *src;
     416             :         unsigned type, size;
     417             :         uint8_t *dst;
     418             : 
     419           2 :         type = bytestream2_get_le16(gb);
     420           2 :         size = bytestream2_get_le16(gb);
     421           2 :         if (size > bytestream2_get_bytes_left(gb))
     422           0 :             return AVERROR_INVALIDDATA;
     423             : 
     424           2 :         bytestream2_init_writer(pb, s->buffer, s->buffer_size);
     425           2 :         if (type == 1) {
     426           1 :             decode_type1(gb, pb);
     427           1 :         } else if (type == 2){
     428           1 :             decode_type2(gb, pb);
     429             :         } else {
     430           0 :             avpriv_report_missing_feature(avctx, "Compression type %d", type);
     431           0 :             return AVERROR_PATCHWELCOME;
     432             :         }
     433             : 
     434           2 :         src = s->buffer;
     435           2 :         dst = frame->data[0] + (avctx->height - 1) * frame->linesize[0];
     436         960 :         for (y = 0; y < avctx->height; y++) {
     437         958 :             memcpy(dst, src, avctx->width * s->bpp);
     438         958 :             dst -= frame->linesize[0];
     439         958 :             src += s->stride * 4;
     440             :         }
     441             :     } else {
     442             :         unsigned block, nb_blocks;
     443             :         int type, k, l;
     444             :         uint8_t *ssrc, *ddst;
     445             :         const uint32_t *src;
     446             :         uint32_t *dst;
     447             : 
     448        1067 :         for (block = 0; block < s->nb_blocks; block++)
     449        1035 :             s->blocks[block].xor = 0;
     450             : 
     451          32 :         nb_blocks = bytestream2_get_le16(gb);
     452          32 :         if (nb_blocks > s->nb_blocks)
     453           0 :             return AVERROR_INVALIDDATA;
     454             : 
     455          32 :         bytestream2_init_writer(pb, s->pbuffer, s->pbuffer_size);
     456             : 
     457          32 :         type = bytestream2_get_le16(gb);
     458         144 :         for (block = 0; block < nb_blocks; block++) {
     459             :             unsigned size, offset;
     460         112 :             int start = 0;
     461             : 
     462         112 :             offset = bytestream2_get_le16(gb);
     463         112 :             if (offset >= s->nb_blocks)
     464           0 :                 return AVERROR_INVALIDDATA;
     465             : 
     466         112 :             size = bytestream2_get_le16(gb);
     467         112 :             if (size > bytestream2_get_bytes_left(gb))
     468           0 :                 return AVERROR_INVALIDDATA;
     469             : 
     470         112 :             start = bytestream2_tell_p(pb);
     471         112 :             if (type == 1) {
     472          41 :                 decode_type1(gb, pb);
     473          71 :             } else if (type == 2){
     474          71 :                 decode_type2(gb, pb);
     475             :             } else {
     476           0 :                 avpriv_report_missing_feature(avctx, "Compression type %d", type);
     477           0 :                 return AVERROR_PATCHWELCOME;
     478             :             }
     479             : 
     480         112 :             if (s->blocks[offset].size * 4 != bytestream2_tell_p(pb) - start)
     481           0 :                 return AVERROR_INVALIDDATA;
     482             : 
     483         112 :             s->blocks[offset].xor = 1;
     484             :         }
     485             : 
     486          32 :         src = (const uint32_t *)s->pbuffer;
     487          32 :         dst = (uint32_t *)s->buffer;
     488             : 
     489         182 :         for (block = 0, y = 0; y < s->yb; y++) {
     490         150 :             int block_h = s->blocks[block].h;
     491         150 :             uint32_t *rect = dst;
     492             : 
     493        1185 :             for (x = 0; x < s->xb; x++) {
     494        1035 :                 int block_w = s->blocks[block].w;
     495        1035 :                 uint32_t *row = dst;
     496             : 
     497        1035 :                 block_h = s->blocks[block].h;
     498        1035 :                 if (s->blocks[block].xor) {
     499       13668 :                     for (k = 0; k < block_h; k++) {
     500       13556 :                         uint32_t *column = dst;
     501     1129796 :                         for (l = 0; l < block_w; l++)
     502     1116240 :                             *dst++ ^= *src++;
     503       13556 :                         dst = &column[s->stride];
     504             :                     }
     505             :                 }
     506        1035 :                 dst = &row[block_w];
     507        1035 :                 ++block;
     508             :             }
     509         150 :             dst = &rect[block_h * s->stride];
     510             :         }
     511             : 
     512          32 :         ssrc = s->buffer;
     513          32 :         ddst = frame->data[0] + (avctx->height - 1) * frame->linesize[0];
     514       17494 :         for (y = 0; y < avctx->height; y++) {
     515       17462 :             memcpy(ddst, ssrc, avctx->width * s->bpp);
     516       17462 :             ddst -= frame->linesize[0];
     517       17462 :             ssrc += s->stride * 4;
     518             :         }
     519             :     }
     520             : 
     521          34 :     *got_frame = 1;
     522             : 
     523          34 :     return avpkt->size;
     524             : }
     525             : 
     526           4 : static av_cold int decode_init(AVCodecContext *avctx)
     527             : {
     528           4 :     FMVCContext *s = avctx->priv_data;
     529           4 :     int i, j, m, block = 0, h = BLOCK_HEIGHT, w = BLOCK_WIDTH;
     530             : 
     531           4 :     switch (avctx->bits_per_coded_sample) {
     532           0 :     case 16:
     533           0 :         avctx->pix_fmt = AV_PIX_FMT_RGB555;
     534           0 :         break;
     535           4 :     case 24:
     536           4 :         avctx->pix_fmt = AV_PIX_FMT_BGR24;
     537           4 :         break;
     538           0 :     case 32:
     539           0 :         avctx->pix_fmt = AV_PIX_FMT_BGRA;
     540           0 :         break;
     541           0 :     default:
     542           0 :         av_log(avctx, AV_LOG_ERROR, "Unsupported bitdepth %i\n",
     543             :                avctx->bits_per_coded_sample);
     544           0 :         return AVERROR_INVALIDDATA;
     545             :     }
     546             : 
     547           4 :     s->stride = (avctx->width * avctx->bits_per_coded_sample + 31) / 32;
     548           4 :     s->xb     = s->stride / BLOCK_WIDTH;
     549           4 :     m         = s->stride % BLOCK_WIDTH;
     550           4 :     if (m) {
     551           4 :         if (m < 37) {
     552           0 :             w = m + BLOCK_WIDTH;
     553             :         } else {
     554           4 :             w = m;
     555           4 :             s->xb++;
     556             :         }
     557             :     }
     558             : 
     559           4 :     s->yb = avctx->height / BLOCK_HEIGHT;
     560           4 :     m     = avctx->height % BLOCK_HEIGHT;
     561           4 :     if (m) {
     562           4 :         if (m < 49) {
     563           4 :             h = m + BLOCK_HEIGHT;
     564             :         } else {
     565           0 :             h = m;
     566           0 :             s->yb++;
     567             :         }
     568             :     }
     569             : 
     570           4 :     s->nb_blocks = s->xb * s->yb;
     571           4 :     if (!s->nb_blocks)
     572           0 :         return AVERROR_INVALIDDATA;
     573           4 :     s->blocks    = av_calloc(s->nb_blocks, sizeof(*s->blocks));
     574           4 :     if (!s->blocks)
     575           0 :         return AVERROR(ENOMEM);
     576             : 
     577          20 :     for (i = 0; i < s->yb; i++) {
     578         122 :         for (j = 0; j < s->xb; j++) {
     579         106 :             if (i != (s->yb - 1) || j != (s->xb - 1)) {
     580         204 :                 if (i == s->yb - 1) {
     581          22 :                     s->blocks[block].w    = BLOCK_WIDTH;
     582          22 :                     s->blocks[block].h    = h;
     583          22 :                     s->blocks[block].size = BLOCK_WIDTH * h;
     584          80 :                 } else if (j == s->xb - 1) {
     585          12 :                     s->blocks[block].w    = w;
     586          12 :                     s->blocks[block].h    = BLOCK_HEIGHT;
     587          12 :                     s->blocks[block].size = BLOCK_HEIGHT * w;
     588             :                 } else {
     589          68 :                     s->blocks[block].w    = BLOCK_WIDTH;
     590          68 :                     s->blocks[block].h    = BLOCK_HEIGHT;
     591          68 :                     s->blocks[block].size = BLOCK_WIDTH * BLOCK_HEIGHT;
     592             :                 }
     593             :             } else {
     594           4 :                 s->blocks[block].w    = w;
     595           4 :                 s->blocks[block].h    = h;
     596           4 :                 s->blocks[block].size = w * h;
     597             :             }
     598         106 :             block++;
     599             :         }
     600             :     }
     601             : 
     602           4 :     s->bpp          = avctx->bits_per_coded_sample >> 3;
     603           4 :     s->buffer_size  = avctx->width * avctx->height * 4;
     604           4 :     s->pbuffer_size = avctx->width * avctx->height * 4;
     605           4 :     s->buffer       = av_mallocz(s->buffer_size);
     606           4 :     s->pbuffer      = av_mallocz(s->pbuffer_size);
     607           4 :     if (!s->buffer || !s->pbuffer)
     608           0 :         return AVERROR(ENOMEM);
     609             : 
     610           4 :     return 0;
     611             : }
     612             : 
     613           4 : static av_cold int decode_close(AVCodecContext *avctx)
     614             : {
     615           4 :     FMVCContext *s = avctx->priv_data;
     616             : 
     617           4 :     av_freep(&s->buffer);
     618           4 :     av_freep(&s->pbuffer);
     619           4 :     av_freep(&s->blocks);
     620             : 
     621           4 :     return 0;
     622             : }
     623             : 
     624             : AVCodec ff_fmvc_decoder = {
     625             :     .name             = "fmvc",
     626             :     .long_name        = NULL_IF_CONFIG_SMALL("FM Screen Capture Codec"),
     627             :     .type             = AVMEDIA_TYPE_VIDEO,
     628             :     .id               = AV_CODEC_ID_FMVC,
     629             :     .priv_data_size   = sizeof(FMVCContext),
     630             :     .init             = decode_init,
     631             :     .close            = decode_close,
     632             :     .decode           = decode_frame,
     633             :     .capabilities     = AV_CODEC_CAP_DR1,
     634             :     .caps_internal    = FF_CODEC_CAP_INIT_THREADSAFE |
     635             :                         FF_CODEC_CAP_INIT_CLEANUP,
     636             : };

Generated by: LCOV version 1.13