LCOV - code coverage report
Current view: top level - libavcodec - sanm.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 322 767 42.0 %
Date: 2017-12-14 01:15:32 Functions: 25 36 69.4 %

          Line data    Source code
       1             : /*
       2             :  * LucasArts Smush video decoder
       3             :  * Copyright (c) 2006 Cyril Zorin
       4             :  * Copyright (c) 2011 Konstantin Shishkov
       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 "libavutil/avassert.h"
      24             : #include "libavutil/bswap.h"
      25             : #include "libavutil/imgutils.h"
      26             : 
      27             : #include "avcodec.h"
      28             : #include "bytestream.h"
      29             : #include "copy_block.h"
      30             : #include "internal.h"
      31             : 
      32             : #define NGLYPHS 256
      33             : #define GLYPH_COORD_VECT_SIZE 16
      34             : #define PALETTE_SIZE 256
      35             : #define PALETTE_DELTA 768
      36             : 
      37             : static const int8_t glyph4_x[GLYPH_COORD_VECT_SIZE] = {
      38             :     0, 1, 2, 3, 3, 3, 3, 2, 1, 0, 0, 0, 1, 2, 2, 1
      39             : };
      40             : 
      41             : static const int8_t glyph4_y[GLYPH_COORD_VECT_SIZE] = {
      42             :     0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 2, 1, 1, 1, 2, 2
      43             : };
      44             : 
      45             : static const int8_t glyph8_x[GLYPH_COORD_VECT_SIZE] = {
      46             :     0, 2, 5, 7, 7, 7, 7, 7, 7, 5, 2, 0, 0, 0, 0, 0
      47             : };
      48             : 
      49             : static const int8_t glyph8_y[GLYPH_COORD_VECT_SIZE] = {
      50             :     0, 0, 0, 0, 1, 3, 4, 6, 7, 7, 7, 7, 6, 4, 3, 1
      51             : };
      52             : 
      53             : static const int8_t motion_vectors[256][2] = {
      54             :     {   0,   0 }, {  -1, -43 }, {   6, -43 }, {  -9, -42 }, {  13, -41 },
      55             :     { -16, -40 }, {  19, -39 }, { -23, -36 }, {  26, -34 }, {  -2, -33 },
      56             :     {   4, -33 }, { -29, -32 }, {  -9, -32 }, {  11, -31 }, { -16, -29 },
      57             :     {  32, -29 }, {  18, -28 }, { -34, -26 }, { -22, -25 }, {  -1, -25 },
      58             :     {   3, -25 }, {  -7, -24 }, {   8, -24 }, {  24, -23 }, {  36, -23 },
      59             :     { -12, -22 }, {  13, -21 }, { -38, -20 }, {   0, -20 }, { -27, -19 },
      60             :     {  -4, -19 }, {   4, -19 }, { -17, -18 }, {  -8, -17 }, {   8, -17 },
      61             :     {  18, -17 }, {  28, -17 }, {  39, -17 }, { -12, -15 }, {  12, -15 },
      62             :     { -21, -14 }, {  -1, -14 }, {   1, -14 }, { -41, -13 }, {  -5, -13 },
      63             :     {   5, -13 }, {  21, -13 }, { -31, -12 }, { -15, -11 }, {  -8, -11 },
      64             :     {   8, -11 }, {  15, -11 }, {  -2, -10 }, {   1, -10 }, {  31, -10 },
      65             :     { -23,  -9 }, { -11,  -9 }, {  -5,  -9 }, {   4,  -9 }, {  11,  -9 },
      66             :     {  42,  -9 }, {   6,  -8 }, {  24,  -8 }, { -18,  -7 }, {  -7,  -7 },
      67             :     {  -3,  -7 }, {  -1,  -7 }, {   2,  -7 }, {  18,  -7 }, { -43,  -6 },
      68             :     { -13,  -6 }, {  -4,  -6 }, {   4,  -6 }, {   8,  -6 }, { -33,  -5 },
      69             :     {  -9,  -5 }, {  -2,  -5 }, {   0,  -5 }, {   2,  -5 }, {   5,  -5 },
      70             :     {  13,  -5 }, { -25,  -4 }, {  -6,  -4 }, {  -3,  -4 }, {   3,  -4 },
      71             :     {   9,  -4 }, { -19,  -3 }, {  -7,  -3 }, {  -4,  -3 }, {  -2,  -3 },
      72             :     {  -1,  -3 }, {   0,  -3 }, {   1,  -3 }, {   2,  -3 }, {   4,  -3 },
      73             :     {   6,  -3 }, {  33,  -3 }, { -14,  -2 }, { -10,  -2 }, {  -5,  -2 },
      74             :     {  -3,  -2 }, {  -2,  -2 }, {  -1,  -2 }, {   0,  -2 }, {   1,  -2 },
      75             :     {   2,  -2 }, {   3,  -2 }, {   5,  -2 }, {   7,  -2 }, {  14,  -2 },
      76             :     {  19,  -2 }, {  25,  -2 }, {  43,  -2 }, {  -7,  -1 }, {  -3,  -1 },
      77             :     {  -2,  -1 }, {  -1,  -1 }, {   0,  -1 }, {   1,  -1 }, {   2,  -1 },
      78             :     {   3,  -1 }, {  10,  -1 }, {  -5,   0 }, {  -3,   0 }, {  -2,   0 },
      79             :     {  -1,   0 }, {   1,   0 }, {   2,   0 }, {   3,   0 }, {   5,   0 },
      80             :     {   7,   0 }, { -10,   1 }, {  -7,   1 }, {  -3,   1 }, {  -2,   1 },
      81             :     {  -1,   1 }, {   0,   1 }, {   1,   1 }, {   2,   1 }, {   3,   1 },
      82             :     { -43,   2 }, { -25,   2 }, { -19,   2 }, { -14,   2 }, {  -5,   2 },
      83             :     {  -3,   2 }, {  -2,   2 }, {  -1,   2 }, {   0,   2 }, {   1,   2 },
      84             :     {   2,   2 }, {   3,   2 }, {   5,   2 }, {   7,   2 }, {  10,   2 },
      85             :     {  14,   2 }, { -33,   3 }, {  -6,   3 }, {  -4,   3 }, {  -2,   3 },
      86             :     {  -1,   3 }, {   0,   3 }, {   1,   3 }, {   2,   3 }, {   4,   3 },
      87             :     {  19,   3 }, {  -9,   4 }, {  -3,   4 }, {   3,   4 }, {   7,   4 },
      88             :     {  25,   4 }, { -13,   5 }, {  -5,   5 }, {  -2,   5 }, {   0,   5 },
      89             :     {   2,   5 }, {   5,   5 }, {   9,   5 }, {  33,   5 }, {  -8,   6 },
      90             :     {  -4,   6 }, {   4,   6 }, {  13,   6 }, {  43,   6 }, { -18,   7 },
      91             :     {  -2,   7 }, {   0,   7 }, {   2,   7 }, {   7,   7 }, {  18,   7 },
      92             :     { -24,   8 }, {  -6,   8 }, { -42,   9 }, { -11,   9 }, {  -4,   9 },
      93             :     {   5,   9 }, {  11,   9 }, {  23,   9 }, { -31,  10 }, {  -1,  10 },
      94             :     {   2,  10 }, { -15,  11 }, {  -8,  11 }, {   8,  11 }, {  15,  11 },
      95             :     {  31,  12 }, { -21,  13 }, {  -5,  13 }, {   5,  13 }, {  41,  13 },
      96             :     {  -1,  14 }, {   1,  14 }, {  21,  14 }, { -12,  15 }, {  12,  15 },
      97             :     { -39,  17 }, { -28,  17 }, { -18,  17 }, {  -8,  17 }, {   8,  17 },
      98             :     {  17,  18 }, {  -4,  19 }, {   0,  19 }, {   4,  19 }, {  27,  19 },
      99             :     {  38,  20 }, { -13,  21 }, {  12,  22 }, { -36,  23 }, { -24,  23 },
     100             :     {  -8,  24 }, {   7,  24 }, {  -3,  25 }, {   1,  25 }, {  22,  25 },
     101             :     {  34,  26 }, { -18,  28 }, { -32,  29 }, {  16,  29 }, { -11,  31 },
     102             :     {   9,  32 }, {  29,  32 }, {  -4,  33 }, {   2,  33 }, { -26,  34 },
     103             :     {  23,  36 }, { -19,  39 }, {  16,  40 }, { -13,  41 }, {   9,  42 },
     104             :     {  -6,  43 }, {   1,  43 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
     105             : };
     106             : 
     107             : static const int8_t c37_mv[] = {
     108             :     0,   0,   1,   0,   2,   0,   3,   0,   5,   0,
     109             :     8,   0,  13,   0,  21,   0,  -1,   0,  -2,   0,
     110             :    -3,   0,  -5,   0,  -8,   0, -13,   0, -17,   0,
     111             :   -21,   0,   0,   1,   1,   1,   2,   1,   3,   1,
     112             :     5,   1,   8,   1,  13,   1,  21,   1,  -1,   1,
     113             :    -2,   1,  -3,   1,  -5,   1,  -8,   1, -13,   1,
     114             :   -17,   1, -21,   1,   0,   2,   1,   2,   2,   2,
     115             :     3,   2,   5,   2,   8,   2,  13,   2,  21,   2,
     116             :    -1,   2,  -2,   2,  -3,   2,  -5,   2,  -8,   2,
     117             :   -13,   2, -17,   2, -21,   2,   0,   3,   1,   3,
     118             :     2,   3,   3,   3,   5,   3,   8,   3,  13,   3,
     119             :    21,   3,  -1,   3,  -2,   3,  -3,   3,  -5,   3,
     120             :    -8,   3, -13,   3, -17,   3, -21,   3,   0,   5,
     121             :     1,   5,   2,   5,   3,   5,   5,   5,   8,   5,
     122             :    13,   5,  21,   5,  -1,   5,  -2,   5,  -3,   5,
     123             :    -5,   5,  -8,   5, -13,   5, -17,   5, -21,   5,
     124             :     0,   8,   1,   8,   2,   8,   3,   8,   5,   8,
     125             :     8,   8,  13,   8,  21,   8,  -1,   8,  -2,   8,
     126             :    -3,   8,  -5,   8,  -8,   8, -13,   8, -17,   8,
     127             :   -21,   8,   0,  13,   1,  13,   2,  13,   3,  13,
     128             :     5,  13,   8,  13,  13,  13,  21,  13,  -1,  13,
     129             :    -2,  13,  -3,  13,  -5,  13,  -8,  13, -13,  13,
     130             :   -17,  13, -21,  13,   0,  21,   1,  21,   2,  21,
     131             :     3,  21,   5,  21,   8,  21,  13,  21,  21,  21,
     132             :    -1,  21,  -2,  21,  -3,  21,  -5,  21,  -8,  21,
     133             :   -13,  21, -17,  21, -21,  21,   0,  -1,   1,  -1,
     134             :     2,  -1,   3,  -1,   5,  -1,   8,  -1,  13,  -1,
     135             :    21,  -1,  -1,  -1,  -2,  -1,  -3,  -1,  -5,  -1,
     136             :    -8,  -1, -13,  -1, -17,  -1, -21,  -1,   0,  -2,
     137             :     1,  -2,   2,  -2,   3,  -2,   5,  -2,   8,  -2,
     138             :    13,  -2,  21,  -2,  -1,  -2,  -2,  -2,  -3,  -2,
     139             :    -5,  -2,  -8,  -2, -13,  -2, -17,  -2, -21,  -2,
     140             :     0,  -3,   1,  -3,   2,  -3,   3,  -3,   5,  -3,
     141             :     8,  -3,  13,  -3,  21,  -3,  -1,  -3,  -2,  -3,
     142             :    -3,  -3,  -5,  -3,  -8,  -3, -13,  -3, -17,  -3,
     143             :   -21,  -3,   0,  -5,   1,  -5,   2,  -5,   3,  -5,
     144             :     5,  -5,   8,  -5,  13,  -5,  21,  -5,  -1,  -5,
     145             :    -2,  -5,  -3,  -5,  -5,  -5,  -8,  -5, -13,  -5,
     146             :   -17,  -5, -21,  -5,   0,  -8,   1,  -8,   2,  -8,
     147             :     3,  -8,   5,  -8,   8,  -8,  13,  -8,  21,  -8,
     148             :    -1,  -8,  -2,  -8,  -3,  -8,  -5,  -8,  -8,  -8,
     149             :   -13,  -8, -17,  -8, -21,  -8,   0, -13,   1, -13,
     150             :     2, -13,   3, -13,   5, -13,   8, -13,  13, -13,
     151             :    21, -13,  -1, -13,  -2, -13,  -3, -13,  -5, -13,
     152             :    -8, -13, -13, -13, -17, -13, -21, -13,   0, -17,
     153             :     1, -17,   2, -17,   3, -17,   5, -17,   8, -17,
     154             :    13, -17,  21, -17,  -1, -17,  -2, -17,  -3, -17,
     155             :    -5, -17,  -8, -17, -13, -17, -17, -17, -21, -17,
     156             :     0, -21,   1, -21,   2, -21,   3, -21,   5, -21,
     157             :     8, -21,  13, -21,  21, -21,  -1, -21,  -2, -21,
     158             :    -3, -21,  -5, -21,  -8, -21, -13, -21, -17, -21,
     159             :     0,   0,  -8, -29,   8, -29, -18, -25,  17, -25,
     160             :     0, -23,  -6, -22,   6, -22, -13, -19,  12, -19,
     161             :     0, -18,  25, -18, -25, -17,  -5, -17,   5, -17,
     162             :   -10, -15,  10, -15,   0, -14,  -4, -13,   4, -13,
     163             :    19, -13, -19, -12,  -8, -11,  -2, -11,   0, -11,
     164             :     2, -11,   8, -11, -15, -10,  -4, -10,   4, -10,
     165             :    15, -10,  -6,  -9,  -1,  -9,   1,  -9,   6,  -9,
     166             :   -29,  -8, -11,  -8,  -8,  -8,  -3,  -8,   3,  -8,
     167             :     8,  -8,  11,  -8,  29,  -8,  -5,  -7,  -2,  -7,
     168             :     0,  -7,   2,  -7,   5,  -7, -22,  -6,  -9,  -6,
     169             :    -6,  -6,  -3,  -6,  -1,  -6,   1,  -6,   3,  -6,
     170             :     6,  -6,   9,  -6,  22,  -6, -17,  -5,  -7,  -5,
     171             :    -4,  -5,  -2,  -5,   0,  -5,   2,  -5,   4,  -5,
     172             :     7,  -5,  17,  -5, -13,  -4, -10,  -4,  -5,  -4,
     173             :    -3,  -4,  -1,  -4,   0,  -4,   1,  -4,   3,  -4,
     174             :     5,  -4,  10,  -4,  13,  -4,  -8,  -3,  -6,  -3,
     175             :    -4,  -3,  -3,  -3,  -2,  -3,  -1,  -3,   0,  -3,
     176             :     1,  -3,   2,  -3,   4,  -3,   6,  -3,   8,  -3,
     177             :   -11,  -2,  -7,  -2,  -5,  -2,  -3,  -2,  -2,  -2,
     178             :    -1,  -2,   0,  -2,   1,  -2,   2,  -2,   3,  -2,
     179             :     5,  -2,   7,  -2,  11,  -2,  -9,  -1,  -6,  -1,
     180             :    -4,  -1,  -3,  -1,  -2,  -1,  -1,  -1,   0,  -1,
     181             :     1,  -1,   2,  -1,   3,  -1,   4,  -1,   6,  -1,
     182             :     9,  -1, -31,   0, -23,   0, -18,   0, -14,   0,
     183             :   -11,   0,  -7,   0,  -5,   0,  -4,   0,  -3,   0,
     184             :    -2,   0,  -1,   0,   0, -31,   1,   0,   2,   0,
     185             :     3,   0,   4,   0,   5,   0,   7,   0,  11,   0,
     186             :    14,   0,  18,   0,  23,   0,  31,   0,  -9,   1,
     187             :    -6,   1,  -4,   1,  -3,   1,  -2,   1,  -1,   1,
     188             :     0,   1,   1,   1,   2,   1,   3,   1,   4,   1,
     189             :     6,   1,   9,   1, -11,   2,  -7,   2,  -5,   2,
     190             :    -3,   2,  -2,   2,  -1,   2,   0,   2,   1,   2,
     191             :     2,   2,   3,   2,   5,   2,   7,   2,  11,   2,
     192             :    -8,   3,  -6,   3,  -4,   3,  -2,   3,  -1,   3,
     193             :     0,   3,   1,   3,   2,   3,   3,   3,   4,   3,
     194             :     6,   3,   8,   3, -13,   4, -10,   4,  -5,   4,
     195             :    -3,   4,  -1,   4,   0,   4,   1,   4,   3,   4,
     196             :     5,   4,  10,   4,  13,   4, -17,   5,  -7,   5,
     197             :    -4,   5,  -2,   5,   0,   5,   2,   5,   4,   5,
     198             :     7,   5,  17,   5, -22,   6,  -9,   6,  -6,   6,
     199             :    -3,   6,  -1,   6,   1,   6,   3,   6,   6,   6,
     200             :     9,   6,  22,   6,  -5,   7,  -2,   7,   0,   7,
     201             :     2,   7,   5,   7, -29,   8, -11,   8,  -8,   8,
     202             :    -3,   8,   3,   8,   8,   8,  11,   8,  29,   8,
     203             :    -6,   9,  -1,   9,   1,   9,   6,   9, -15,  10,
     204             :    -4,  10,   4,  10,  15,  10,  -8,  11,  -2,  11,
     205             :     0,  11,   2,  11,   8,  11,  19,  12, -19,  13,
     206             :    -4,  13,   4,  13,   0,  14, -10,  15,  10,  15,
     207             :    -5,  17,   5,  17,  25,  17, -25,  18,   0,  18,
     208             :   -12,  19,  13,  19,  -6,  22,   6,  22,   0,  23,
     209             :   -17,  25,  18,  25,  -8,  29,   8,  29,   0,  31,
     210             :     0,   0,  -6, -22,   6, -22, -13, -19,  12, -19,
     211             :     0, -18,  -5, -17,   5, -17, -10, -15,  10, -15,
     212             :     0, -14,  -4, -13,   4, -13,  19, -13, -19, -12,
     213             :    -8, -11,  -2, -11,   0, -11,   2, -11,   8, -11,
     214             :   -15, -10,  -4, -10,   4, -10,  15, -10,  -6,  -9,
     215             :    -1,  -9,   1,  -9,   6,  -9, -11,  -8,  -8,  -8,
     216             :    -3,  -8,   0,  -8,   3,  -8,   8,  -8,  11,  -8,
     217             :    -5,  -7,  -2,  -7,   0,  -7,   2,  -7,   5,  -7,
     218             :   -22,  -6,  -9,  -6,  -6,  -6,  -3,  -6,  -1,  -6,
     219             :     1,  -6,   3,  -6,   6,  -6,   9,  -6,  22,  -6,
     220             :   -17,  -5,  -7,  -5,  -4,  -5,  -2,  -5,  -1,  -5,
     221             :     0,  -5,   1,  -5,   2,  -5,   4,  -5,   7,  -5,
     222             :    17,  -5, -13,  -4, -10,  -4,  -5,  -4,  -3,  -4,
     223             :    -2,  -4,  -1,  -4,   0,  -4,   1,  -4,   2,  -4,
     224             :     3,  -4,   5,  -4,  10,  -4,  13,  -4,  -8,  -3,
     225             :    -6,  -3,  -4,  -3,  -3,  -3,  -2,  -3,  -1,  -3,
     226             :     0,  -3,   1,  -3,   2,  -3,   3,  -3,   4,  -3,
     227             :     6,  -3,   8,  -3, -11,  -2,  -7,  -2,  -5,  -2,
     228             :    -4,  -2,  -3,  -2,  -2,  -2,  -1,  -2,   0,  -2,
     229             :     1,  -2,   2,  -2,   3,  -2,   4,  -2,   5,  -2,
     230             :     7,  -2,  11,  -2,  -9,  -1,  -6,  -1,  -5,  -1,
     231             :    -4,  -1,  -3,  -1,  -2,  -1,  -1,  -1,   0,  -1,
     232             :     1,  -1,   2,  -1,   3,  -1,   4,  -1,   5,  -1,
     233             :     6,  -1,   9,  -1, -23,   0, -18,   0, -14,   0,
     234             :   -11,   0,  -7,   0,  -5,   0,  -4,   0,  -3,   0,
     235             :    -2,   0,  -1,   0,   0, -23,   1,   0,   2,   0,
     236             :     3,   0,   4,   0,   5,   0,   7,   0,  11,   0,
     237             :    14,   0,  18,   0,  23,   0,  -9,   1,  -6,   1,
     238             :    -5,   1,  -4,   1,  -3,   1,  -2,   1,  -1,   1,
     239             :     0,   1,   1,   1,   2,   1,   3,   1,   4,   1,
     240             :     5,   1,   6,   1,   9,   1, -11,   2,  -7,   2,
     241             :    -5,   2,  -4,   2,  -3,   2,  -2,   2,  -1,   2,
     242             :     0,   2,   1,   2,   2,   2,   3,   2,   4,   2,
     243             :     5,   2,   7,   2,  11,   2,  -8,   3,  -6,   3,
     244             :    -4,   3,  -3,   3,  -2,   3,  -1,   3,   0,   3,
     245             :     1,   3,   2,   3,   3,   3,   4,   3,   6,   3,
     246             :     8,   3, -13,   4, -10,   4,  -5,   4,  -3,   4,
     247             :    -2,   4,  -1,   4,   0,   4,   1,   4,   2,   4,
     248             :     3,   4,   5,   4,  10,   4,  13,   4, -17,   5,
     249             :    -7,   5,  -4,   5,  -2,   5,  -1,   5,   0,   5,
     250             :     1,   5,   2,   5,   4,   5,   7,   5,  17,   5,
     251             :   -22,   6,  -9,   6,  -6,   6,  -3,   6,  -1,   6,
     252             :     1,   6,   3,   6,   6,   6,   9,   6,  22,   6,
     253             :    -5,   7,  -2,   7,   0,   7,   2,   7,   5,   7,
     254             :   -11,   8,  -8,   8,  -3,   8,   0,   8,   3,   8,
     255             :     8,   8,  11,   8,  -6,   9,  -1,   9,   1,   9,
     256             :     6,   9, -15,  10,  -4,  10,   4,  10,  15,  10,
     257             :    -8,  11,  -2,  11,   0,  11,   2,  11,   8,  11,
     258             :    19,  12, -19,  13,  -4,  13,   4,  13,   0,  14,
     259             :   -10,  15,  10,  15,  -5,  17,   5,  17,   0,  18,
     260             :   -12,  19,  13,  19,  -6,  22,   6,  22,   0,  23,
     261             : };
     262             : 
     263             : typedef struct SANMVideoContext {
     264             :     AVCodecContext *avctx;
     265             :     GetByteContext gb;
     266             : 
     267             :     int version, subversion;
     268             :     uint32_t pal[PALETTE_SIZE];
     269             :     int16_t delta_pal[PALETTE_DELTA];
     270             : 
     271             :     ptrdiff_t pitch;
     272             :     int width, height;
     273             :     int aligned_width, aligned_height;
     274             :     int prev_seq;
     275             : 
     276             :     AVFrame *frame;
     277             :     uint16_t *frm0, *frm1, *frm2;
     278             :     uint8_t *stored_frame;
     279             :     uint32_t frm0_size, frm1_size, frm2_size;
     280             :     uint32_t stored_frame_size;
     281             : 
     282             :     uint8_t *rle_buf;
     283             :     unsigned int rle_buf_size;
     284             : 
     285             :     int rotate_code;
     286             : 
     287             :     long npixels, buf_size;
     288             : 
     289             :     uint16_t codebook[256];
     290             :     uint16_t small_codebook[4];
     291             : 
     292             :     int8_t p4x4glyphs[NGLYPHS][16];
     293             :     int8_t p8x8glyphs[NGLYPHS][64];
     294             : } SANMVideoContext;
     295             : 
     296             : typedef struct SANMFrameHeader {
     297             :     int seq_num, codec, rotate_code, rle_output_size;
     298             : 
     299             :     uint16_t bg_color;
     300             :     uint32_t width, height;
     301             : } SANMFrameHeader;
     302             : 
     303             : enum GlyphEdge {
     304             :     LEFT_EDGE,
     305             :     TOP_EDGE,
     306             :     RIGHT_EDGE,
     307             :     BOTTOM_EDGE,
     308             :     NO_EDGE
     309             : };
     310             : 
     311             : enum GlyphDir {
     312             :     DIR_LEFT,
     313             :     DIR_UP,
     314             :     DIR_RIGHT,
     315             :     DIR_DOWN,
     316             :     NO_DIR
     317             : };
     318             : 
     319             : /**
     320             :  * Return enum GlyphEdge of box where point (x, y) lies.
     321             :  *
     322             :  * @param x x point coordinate
     323             :  * @param y y point coordinate
     324             :  * @param edge_size box width/height.
     325             :  */
     326        1632 : static enum GlyphEdge which_edge(int x, int y, int edge_size)
     327             : {
     328        1632 :     const int edge_max = edge_size - 1;
     329             : 
     330        1632 :     if (!y)
     331         408 :         return BOTTOM_EDGE;
     332        1224 :     else if (y == edge_max)
     333         408 :         return TOP_EDGE;
     334         816 :     else if (!x)
     335         306 :         return LEFT_EDGE;
     336         510 :     else if (x == edge_max)
     337         306 :         return RIGHT_EDGE;
     338             :     else
     339         204 :         return NO_EDGE;
     340             : }
     341             : 
     342        1536 : static enum GlyphDir which_direction(enum GlyphEdge edge0, enum GlyphEdge edge1)
     343             : {
     344        1536 :     if ((edge0 == LEFT_EDGE && edge1 == RIGHT_EDGE) ||
     345         288 :         (edge1 == LEFT_EDGE && edge0 == RIGHT_EDGE) ||
     346         384 :         (edge0 == BOTTOM_EDGE && edge1 != TOP_EDGE) ||
     347         288 :         (edge1 == BOTTOM_EDGE && edge0 != TOP_EDGE))
     348         600 :         return DIR_UP;
     349         936 :     else if ((edge0 == TOP_EDGE && edge1 != BOTTOM_EDGE) ||
     350         288 :              (edge1 == TOP_EDGE && edge0 != BOTTOM_EDGE))
     351         480 :         return DIR_DOWN;
     352         456 :     else if ((edge0 == LEFT_EDGE && edge1 != RIGHT_EDGE) ||
     353          24 :              (edge1 == LEFT_EDGE && edge0 != RIGHT_EDGE))
     354         108 :         return DIR_LEFT;
     355         348 :     else if ((edge0 == TOP_EDGE && edge1 == BOTTOM_EDGE) ||
     356          96 :              (edge1 == TOP_EDGE && edge0 == BOTTOM_EDGE) ||
     357          84 :              (edge0 == RIGHT_EDGE && edge1 != LEFT_EDGE) ||
     358          24 :              (edge1 == RIGHT_EDGE && edge0 != LEFT_EDGE))
     359         300 :         return DIR_RIGHT;
     360             : 
     361          48 :     return NO_DIR;
     362             : }
     363             : 
     364             : /* Interpolate two points. */
     365        6600 : static void interp_point(int8_t *points, int x0, int y0, int x1, int y1,
     366             :                          int pos, int npoints)
     367             : {
     368        6600 :     if (npoints) {
     369        6504 :         points[0] = (x0 * pos + x1 * (npoints - pos) + (npoints >> 1)) / npoints;
     370        6504 :         points[1] = (y0 * pos + y1 * (npoints - pos) + (npoints >> 1)) / npoints;
     371             :     } else {
     372          96 :         points[0] = x0;
     373          96 :         points[1] = y0;
     374             :     }
     375        6600 : }
     376             : 
     377             : /**
     378             :  * Construct glyphs by iterating through vector coordinates.
     379             :  *
     380             :  * @param pglyphs pointer to table where glyphs are stored
     381             :  * @param xvec pointer to x component of vector coordinates
     382             :  * @param yvec pointer to y component of vector coordinates
     383             :  * @param side_length glyph width/height.
     384             :  */
     385           6 : static void make_glyphs(int8_t *pglyphs, const int8_t *xvec, const int8_t *yvec,
     386             :                         const int side_length)
     387             : {
     388           6 :     const int glyph_size = side_length * side_length;
     389           6 :     int8_t *pglyph = pglyphs;
     390             : 
     391             :     int i, j;
     392         102 :     for (i = 0; i < GLYPH_COORD_VECT_SIZE; i++) {
     393          96 :         int x0 = xvec[i];
     394          96 :         int y0 = yvec[i];
     395          96 :         enum GlyphEdge edge0 = which_edge(x0, y0, side_length);
     396             : 
     397        1632 :         for (j = 0; j < GLYPH_COORD_VECT_SIZE; j++, pglyph += glyph_size) {
     398        1536 :             int x1 = xvec[j];
     399        1536 :             int y1 = yvec[j];
     400        1536 :             enum GlyphEdge edge1 = which_edge(x1, y1, side_length);
     401        1536 :             enum GlyphDir dir = which_direction(edge0, edge1);
     402        1536 :             int npoints = FFMAX(FFABS(x1 - x0), FFABS(y1 - y0));
     403             :             int ipoint;
     404             : 
     405        8136 :             for (ipoint = 0; ipoint <= npoints; ipoint++) {
     406             :                 int8_t point[2];
     407             :                 int irow, icol;
     408             : 
     409        6600 :                 interp_point(point, x0, y0, x1, y1, ipoint, npoints);
     410             : 
     411        6600 :                 switch (dir) {
     412        2832 :                 case DIR_UP:
     413       11064 :                     for (irow = point[1]; irow >= 0; irow--)
     414        8232 :                         pglyph[point[0] + irow * side_length] = 1;
     415        2832 :                     break;
     416             : 
     417        1968 :                 case DIR_DOWN:
     418        6468 :                     for (irow = point[1]; irow < side_length; irow++)
     419        4500 :                         pglyph[point[0] + irow * side_length] = 1;
     420        1968 :                     break;
     421             : 
     422         282 :                 case DIR_LEFT:
     423         660 :                     for (icol = point[0]; icol >= 0; icol--)
     424         378 :                         pglyph[icol + point[1] * side_length] = 1;
     425         282 :                     break;
     426             : 
     427        1434 :                 case DIR_RIGHT:
     428        6228 :                     for (icol = point[0]; icol < side_length; icol++)
     429        4794 :                         pglyph[icol + point[1] * side_length] = 1;
     430        1434 :                     break;
     431             :                 }
     432             :             }
     433             :         }
     434             :     }
     435           6 : }
     436             : 
     437           6 : static void init_sizes(SANMVideoContext *ctx, int width, int height)
     438             : {
     439           6 :     ctx->width   = width;
     440           6 :     ctx->height  = height;
     441           6 :     ctx->npixels = width * height;
     442             : 
     443           6 :     ctx->aligned_width  = FFALIGN(width, 8);
     444           6 :     ctx->aligned_height = FFALIGN(height, 8);
     445             : 
     446           6 :     ctx->buf_size = ctx->aligned_width * ctx->aligned_height * sizeof(ctx->frm0[0]);
     447           6 :     ctx->pitch    = width;
     448           6 : }
     449             : 
     450           3 : static void destroy_buffers(SANMVideoContext *ctx)
     451             : {
     452           3 :     av_freep(&ctx->frm0);
     453           3 :     av_freep(&ctx->frm1);
     454           3 :     av_freep(&ctx->frm2);
     455           3 :     av_freep(&ctx->stored_frame);
     456           3 :     av_freep(&ctx->rle_buf);
     457           3 :     ctx->frm0_size =
     458           3 :     ctx->frm1_size =
     459           3 :     ctx->frm2_size = 0;
     460           3 :     init_sizes(ctx, 0, 0);
     461           3 : }
     462             : 
     463           3 : static av_cold int init_buffers(SANMVideoContext *ctx)
     464             : {
     465           3 :     av_fast_padded_mallocz(&ctx->frm0, &ctx->frm0_size, ctx->buf_size);
     466           3 :     av_fast_padded_mallocz(&ctx->frm1, &ctx->frm1_size, ctx->buf_size);
     467           3 :     av_fast_padded_mallocz(&ctx->frm2, &ctx->frm2_size, ctx->buf_size);
     468           3 :     if (!ctx->version)
     469           0 :         av_fast_padded_mallocz(&ctx->stored_frame,
     470           0 :                               &ctx->stored_frame_size, ctx->buf_size);
     471             : 
     472           6 :     if (!ctx->frm0 || !ctx->frm1 || !ctx->frm2 ||
     473           6 :         (!ctx->stored_frame && !ctx->version)) {
     474           0 :         destroy_buffers(ctx);
     475           0 :         return AVERROR(ENOMEM);
     476             :     }
     477             : 
     478           3 :     return 0;
     479             : }
     480             : 
     481           9 : static void rotate_bufs(SANMVideoContext *ctx, int rotate_code)
     482             : {
     483           9 :     if (rotate_code == 2)
     484           1 :         FFSWAP(uint16_t*, ctx->frm1, ctx->frm2);
     485           9 :     FFSWAP(uint16_t*, ctx->frm2, ctx->frm0);
     486           9 : }
     487             : 
     488           3 : static av_cold int decode_init(AVCodecContext *avctx)
     489             : {
     490           3 :     SANMVideoContext *ctx = avctx->priv_data;
     491             : 
     492           3 :     ctx->avctx   = avctx;
     493           3 :     ctx->version = !avctx->extradata_size;
     494             : 
     495           3 :     avctx->pix_fmt = ctx->version ? AV_PIX_FMT_RGB565 : AV_PIX_FMT_PAL8;
     496             : 
     497           3 :     init_sizes(ctx, avctx->width, avctx->height);
     498           3 :     if (init_buffers(ctx)) {
     499           0 :         av_log(avctx, AV_LOG_ERROR, "Error allocating buffers.\n");
     500           0 :         return AVERROR(ENOMEM);
     501             :     }
     502             : 
     503           3 :     make_glyphs(ctx->p4x4glyphs[0], glyph4_x, glyph4_y, 4);
     504           3 :     make_glyphs(ctx->p8x8glyphs[0], glyph8_x, glyph8_y, 8);
     505             : 
     506           3 :     if (!ctx->version) {
     507             :         int i;
     508             : 
     509           0 :         if (avctx->extradata_size < 1026) {
     510           0 :             av_log(avctx, AV_LOG_ERROR, "Not enough extradata.\n");
     511           0 :             return AVERROR_INVALIDDATA;
     512             :         }
     513             : 
     514           0 :         ctx->subversion = AV_RL16(avctx->extradata);
     515           0 :         for (i = 0; i < PALETTE_SIZE; i++)
     516           0 :             ctx->pal[i] = 0xFFU << 24 | AV_RL32(avctx->extradata + 2 + i * 4);
     517             :     }
     518             : 
     519           3 :     return 0;
     520             : }
     521             : 
     522           3 : static av_cold int decode_end(AVCodecContext *avctx)
     523             : {
     524           3 :     SANMVideoContext *ctx = avctx->priv_data;
     525             : 
     526           3 :     destroy_buffers(ctx);
     527             : 
     528           3 :     return 0;
     529             : }
     530             : 
     531           1 : static int rle_decode(SANMVideoContext *ctx, uint8_t *dst, const int out_size)
     532             : {
     533           1 :     int opcode, color, run_len, left = out_size;
     534             : 
     535        4802 :     while (left > 0) {
     536        4800 :         opcode = bytestream2_get_byte(&ctx->gb);
     537        4800 :         run_len = (opcode >> 1) + 1;
     538        4800 :         if (run_len > left || bytestream2_get_bytes_left(&ctx->gb) <= 0)
     539           0 :             return AVERROR_INVALIDDATA;
     540             : 
     541        4800 :         if (opcode & 1) {
     542        4800 :             color = bytestream2_get_byte(&ctx->gb);
     543        4800 :             memset(dst, color, run_len);
     544             :         } else {
     545           0 :             if (bytestream2_get_bytes_left(&ctx->gb) < run_len)
     546           0 :                 return AVERROR_INVALIDDATA;
     547           0 :             bytestream2_get_bufferu(&ctx->gb, dst, run_len);
     548             :         }
     549             : 
     550        4800 :         dst  += run_len;
     551        4800 :         left -= run_len;
     552             :     }
     553             : 
     554           1 :     return 0;
     555             : }
     556             : 
     557           0 : static int old_codec1(SANMVideoContext *ctx, int top,
     558             :                       int left, int width, int height)
     559             : {
     560           0 :     uint8_t *dst = ((uint8_t *)ctx->frm0) + left + top * ctx->pitch;
     561             :     int i, j, len, flag, code, val, pos, end;
     562             : 
     563           0 :     for (i = 0; i < height; i++) {
     564           0 :         pos = 0;
     565             : 
     566           0 :         if (bytestream2_get_bytes_left(&ctx->gb) < 2)
     567           0 :             return AVERROR_INVALIDDATA;
     568             : 
     569           0 :         len = bytestream2_get_le16u(&ctx->gb);
     570           0 :         end = bytestream2_tell(&ctx->gb) + len;
     571             : 
     572           0 :         while (bytestream2_tell(&ctx->gb) < end) {
     573           0 :             if (bytestream2_get_bytes_left(&ctx->gb) < 2)
     574           0 :                 return AVERROR_INVALIDDATA;
     575             : 
     576           0 :             code = bytestream2_get_byteu(&ctx->gb);
     577           0 :             flag = code & 1;
     578           0 :             code = (code >> 1) + 1;
     579           0 :             if (pos + code > width)
     580           0 :                 return AVERROR_INVALIDDATA;
     581           0 :             if (flag) {
     582           0 :                 val = bytestream2_get_byteu(&ctx->gb);
     583           0 :                 if (val)
     584           0 :                     memset(dst + pos, val, code);
     585           0 :                 pos += code;
     586             :             } else {
     587           0 :                 if (bytestream2_get_bytes_left(&ctx->gb) < code)
     588           0 :                     return AVERROR_INVALIDDATA;
     589           0 :                 for (j = 0; j < code; j++) {
     590           0 :                     val = bytestream2_get_byteu(&ctx->gb);
     591           0 :                     if (val)
     592           0 :                         dst[pos] = val;
     593           0 :                     pos++;
     594             :                 }
     595             :             }
     596             :         }
     597           0 :         dst += ctx->pitch;
     598             :     }
     599           0 :     ctx->rotate_code = 0;
     600             : 
     601           0 :     return 0;
     602             : }
     603             : 
     604           0 : static inline void codec37_mv(uint8_t *dst, const uint8_t *src,
     605             :                               int height, int stride, int x, int y)
     606             : {
     607             :     int pos, i, j;
     608             : 
     609           0 :     pos = x + y * stride;
     610           0 :     for (j = 0; j < 4; j++) {
     611           0 :         for (i = 0; i < 4; i++) {
     612           0 :             if ((pos + i) < 0 || (pos + i) >= height * stride)
     613           0 :                 dst[i] = 0;
     614             :             else
     615           0 :                 dst[i] = src[i];
     616             :         }
     617           0 :         dst += stride;
     618           0 :         src += stride;
     619           0 :         pos += stride;
     620             :     }
     621           0 : }
     622             : 
     623           0 : static int old_codec37(SANMVideoContext *ctx, int top,
     624             :                        int left, int width, int height)
     625             : {
     626           0 :     ptrdiff_t stride = ctx->pitch;
     627             :     int i, j, k, t;
     628             :     uint8_t *dst, *prev;
     629           0 :     int skip_run = 0;
     630           0 :     int compr = bytestream2_get_byte(&ctx->gb);
     631           0 :     int mvoff = bytestream2_get_byte(&ctx->gb);
     632           0 :     int seq   = bytestream2_get_le16(&ctx->gb);
     633           0 :     uint32_t decoded_size = bytestream2_get_le32(&ctx->gb);
     634             :     int flags;
     635             : 
     636           0 :     bytestream2_skip(&ctx->gb, 4);
     637           0 :     flags = bytestream2_get_byte(&ctx->gb);
     638           0 :     bytestream2_skip(&ctx->gb, 3);
     639             : 
     640           0 :     if (decoded_size > ctx->height * stride - left - top * stride) {
     641           0 :         decoded_size = ctx->height * stride - left - top * stride;
     642           0 :         av_log(ctx->avctx, AV_LOG_WARNING, "Decoded size is too large.\n");
     643             :     }
     644             : 
     645           0 :     ctx->rotate_code = 0;
     646             : 
     647           0 :     if (((seq & 1) || !(flags & 1)) && (compr && compr != 2))
     648           0 :         rotate_bufs(ctx, 1);
     649             : 
     650           0 :     dst  = ((uint8_t*)ctx->frm0) + left + top * stride;
     651           0 :     prev = ((uint8_t*)ctx->frm2) + left + top * stride;
     652             : 
     653           0 :     if (mvoff > 2) {
     654           0 :         av_log(ctx->avctx, AV_LOG_ERROR, "Invalid motion base value %d.\n", mvoff);
     655           0 :         return AVERROR_INVALIDDATA;
     656             :     }
     657             : 
     658           0 :     switch (compr) {
     659           0 :     case 0:
     660           0 :         for (i = 0; i < height; i++) {
     661           0 :             bytestream2_get_buffer(&ctx->gb, dst, width);
     662           0 :             dst += stride;
     663             :         }
     664           0 :         memset(ctx->frm1, 0, ctx->height * stride);
     665           0 :         memset(ctx->frm2, 0, ctx->height * stride);
     666           0 :         break;
     667           0 :     case 2:
     668           0 :         if (rle_decode(ctx, dst, decoded_size))
     669           0 :             return AVERROR_INVALIDDATA;
     670           0 :         memset(ctx->frm1, 0, ctx->frm1_size);
     671           0 :         memset(ctx->frm2, 0, ctx->frm2_size);
     672           0 :         break;
     673           0 :     case 3:
     674             :     case 4:
     675           0 :         if (flags & 4) {
     676           0 :             for (j = 0; j < height; j += 4) {
     677           0 :                 for (i = 0; i < width; i += 4) {
     678             :                     int code;
     679           0 :                     if (skip_run) {
     680           0 :                         skip_run--;
     681           0 :                         copy_block4(dst + i, prev + i, stride, stride, 4);
     682           0 :                         continue;
     683             :                     }
     684           0 :                     if (bytestream2_get_bytes_left(&ctx->gb) < 1)
     685           0 :                         return AVERROR_INVALIDDATA;
     686           0 :                     code = bytestream2_get_byteu(&ctx->gb);
     687           0 :                     switch (code) {
     688           0 :                     case 0xFF:
     689           0 :                         if (bytestream2_get_bytes_left(&ctx->gb) < 16)
     690           0 :                             return AVERROR_INVALIDDATA;
     691           0 :                         for (k = 0; k < 4; k++)
     692           0 :                             bytestream2_get_bufferu(&ctx->gb, dst + i + k * stride, 4);
     693           0 :                         break;
     694           0 :                     case 0xFE:
     695           0 :                         if (bytestream2_get_bytes_left(&ctx->gb) < 4)
     696           0 :                             return AVERROR_INVALIDDATA;
     697           0 :                         for (k = 0; k < 4; k++)
     698           0 :                             memset(dst + i + k * stride, bytestream2_get_byteu(&ctx->gb), 4);
     699           0 :                         break;
     700           0 :                     case 0xFD:
     701           0 :                         if (bytestream2_get_bytes_left(&ctx->gb) < 1)
     702           0 :                             return AVERROR_INVALIDDATA;
     703           0 :                         t = bytestream2_get_byteu(&ctx->gb);
     704           0 :                         for (k = 0; k < 4; k++)
     705           0 :                             memset(dst + i + k * stride, t, 4);
     706           0 :                         break;
     707           0 :                     default:
     708           0 :                         if (compr == 4 && !code) {
     709           0 :                             if (bytestream2_get_bytes_left(&ctx->gb) < 1)
     710           0 :                                 return AVERROR_INVALIDDATA;
     711           0 :                             skip_run = bytestream2_get_byteu(&ctx->gb) + 1;
     712           0 :                             i -= 4;
     713             :                         } else {
     714             :                             int mx, my;
     715             : 
     716           0 :                             mx = c37_mv[(mvoff * 255 + code) * 2];
     717           0 :                             my = c37_mv[(mvoff * 255 + code) * 2 + 1];
     718           0 :                             codec37_mv(dst + i, prev + i + mx + my * stride,
     719             :                                        ctx->height, stride, i + mx, j + my);
     720             :                         }
     721             :                     }
     722             :                 }
     723           0 :                 dst  += stride * 4;
     724           0 :                 prev += stride * 4;
     725             :             }
     726             :         } else {
     727           0 :             for (j = 0; j < height; j += 4) {
     728           0 :                 for (i = 0; i < width; i += 4) {
     729             :                     int code;
     730           0 :                     if (skip_run) {
     731           0 :                         skip_run--;
     732           0 :                         copy_block4(dst + i, prev + i, stride, stride, 4);
     733           0 :                         continue;
     734             :                     }
     735           0 :                     code = bytestream2_get_byte(&ctx->gb);
     736           0 :                     if (code == 0xFF) {
     737           0 :                         if (bytestream2_get_bytes_left(&ctx->gb) < 16)
     738           0 :                             return AVERROR_INVALIDDATA;
     739           0 :                         for (k = 0; k < 4; k++)
     740           0 :                             bytestream2_get_bufferu(&ctx->gb, dst + i + k * stride, 4);
     741           0 :                     } else if (compr == 4 && !code) {
     742           0 :                         if (bytestream2_get_bytes_left(&ctx->gb) < 1)
     743           0 :                             return AVERROR_INVALIDDATA;
     744           0 :                         skip_run = bytestream2_get_byteu(&ctx->gb) + 1;
     745           0 :                         i -= 4;
     746             :                     } else {
     747             :                         int mx, my;
     748             : 
     749           0 :                         mx = c37_mv[(mvoff * 255 + code) * 2];
     750           0 :                         my = c37_mv[(mvoff * 255 + code) * 2 + 1];
     751           0 :                         codec37_mv(dst + i, prev + i + mx + my * stride,
     752             :                                    ctx->height, stride, i + mx, j + my);
     753             :                     }
     754             :                 }
     755           0 :                 dst  += stride * 4;
     756           0 :                 prev += stride * 4;
     757             :             }
     758             :         }
     759           0 :         break;
     760           0 :     default:
     761           0 :         avpriv_report_missing_feature(ctx->avctx,
     762             :                                       "Subcodec 37 compression %d", compr);
     763           0 :         return AVERROR_PATCHWELCOME;
     764             :     }
     765             : 
     766           0 :     return 0;
     767             : }
     768             : 
     769           0 : static int process_block(SANMVideoContext *ctx, uint8_t *dst, uint8_t *prev1,
     770             :                          uint8_t *prev2, int stride, int tbl, int size)
     771             : {
     772             :     int code, k, t;
     773             :     uint8_t colors[2];
     774             :     int8_t *pglyph;
     775             : 
     776           0 :     if (bytestream2_get_bytes_left(&ctx->gb) < 1)
     777           0 :         return AVERROR_INVALIDDATA;
     778             : 
     779           0 :     code = bytestream2_get_byteu(&ctx->gb);
     780           0 :     if (code >= 0xF8) {
     781           0 :         switch (code) {
     782           0 :         case 0xFF:
     783           0 :             if (size == 2) {
     784           0 :                 if (bytestream2_get_bytes_left(&ctx->gb) < 4)
     785           0 :                     return AVERROR_INVALIDDATA;
     786           0 :                 dst[0]          = bytestream2_get_byteu(&ctx->gb);
     787           0 :                 dst[1]          = bytestream2_get_byteu(&ctx->gb);
     788           0 :                 dst[0 + stride] = bytestream2_get_byteu(&ctx->gb);
     789           0 :                 dst[1 + stride] = bytestream2_get_byteu(&ctx->gb);
     790             :             } else {
     791           0 :                 size >>= 1;
     792           0 :                 if (process_block(ctx, dst, prev1, prev2, stride, tbl, size))
     793           0 :                     return AVERROR_INVALIDDATA;
     794           0 :                 if (process_block(ctx, dst + size, prev1 + size, prev2 + size,
     795             :                                   stride, tbl, size))
     796           0 :                     return AVERROR_INVALIDDATA;
     797           0 :                 dst   += size * stride;
     798           0 :                 prev1 += size * stride;
     799           0 :                 prev2 += size * stride;
     800           0 :                 if (process_block(ctx, dst, prev1, prev2, stride, tbl, size))
     801           0 :                     return AVERROR_INVALIDDATA;
     802           0 :                 if (process_block(ctx, dst + size, prev1 + size, prev2 + size,
     803             :                                   stride, tbl, size))
     804           0 :                     return AVERROR_INVALIDDATA;
     805             :             }
     806           0 :             break;
     807           0 :         case 0xFE:
     808           0 :             if (bytestream2_get_bytes_left(&ctx->gb) < 1)
     809           0 :                 return AVERROR_INVALIDDATA;
     810             : 
     811           0 :             t = bytestream2_get_byteu(&ctx->gb);
     812           0 :             for (k = 0; k < size; k++)
     813           0 :                 memset(dst + k * stride, t, size);
     814           0 :             break;
     815           0 :         case 0xFD:
     816           0 :             if (bytestream2_get_bytes_left(&ctx->gb) < 3)
     817           0 :                 return AVERROR_INVALIDDATA;
     818             : 
     819           0 :             code = bytestream2_get_byteu(&ctx->gb);
     820           0 :             pglyph = (size == 8) ? ctx->p8x8glyphs[code] : ctx->p4x4glyphs[code];
     821           0 :             bytestream2_get_bufferu(&ctx->gb, colors, 2);
     822             : 
     823           0 :             for (k = 0; k < size; k++)
     824           0 :                 for (t = 0; t < size; t++)
     825           0 :                     dst[t + k * stride] = colors[!*pglyph++];
     826           0 :             break;
     827           0 :         case 0xFC:
     828           0 :             for (k = 0; k < size; k++)
     829           0 :                 memcpy(dst + k * stride, prev1 + k * stride, size);
     830           0 :             break;
     831           0 :         default:
     832           0 :             k = bytestream2_tell(&ctx->gb);
     833           0 :             bytestream2_seek(&ctx->gb, tbl + (code & 7), SEEK_SET);
     834           0 :             t = bytestream2_get_byte(&ctx->gb);
     835           0 :             bytestream2_seek(&ctx->gb, k, SEEK_SET);
     836           0 :             for (k = 0; k < size; k++)
     837           0 :                 memset(dst + k * stride, t, size);
     838             :         }
     839             :     } else {
     840           0 :         int mx = motion_vectors[code][0];
     841           0 :         int my = motion_vectors[code][1];
     842           0 :         int index = prev2 - (const uint8_t *)ctx->frm2;
     843             : 
     844             :         av_assert2(index >= 0 && index < (ctx->buf_size >> 1));
     845             : 
     846           0 :         if (index < -mx - my * stride ||
     847           0 :             (ctx->buf_size >> 1) - index < mx + size + (my + size - 1) * stride) {
     848           0 :             av_log(ctx->avctx, AV_LOG_ERROR, "MV is invalid.\n");
     849           0 :             return AVERROR_INVALIDDATA;
     850             :         }
     851             : 
     852           0 :         for (k = 0; k < size; k++)
     853           0 :             memcpy(dst + k * stride, prev2 + mx + (my + k) * stride, size);
     854             :     }
     855             : 
     856           0 :     return 0;
     857             : }
     858             : 
     859           0 : static int old_codec47(SANMVideoContext *ctx, int top,
     860             :                        int left, int width, int height)
     861             : {
     862             :     uint32_t decoded_size;
     863             :     int i, j;
     864           0 :     ptrdiff_t stride = ctx->pitch;
     865           0 :     uint8_t *dst   = (uint8_t *)ctx->frm0 + left + top * stride;
     866           0 :     uint8_t *prev1 = (uint8_t *)ctx->frm1;
     867           0 :     uint8_t *prev2 = (uint8_t *)ctx->frm2;
     868           0 :     int tbl_pos = bytestream2_tell(&ctx->gb);
     869           0 :     int seq     = bytestream2_get_le16(&ctx->gb);
     870           0 :     int compr   = bytestream2_get_byte(&ctx->gb);
     871           0 :     int new_rot = bytestream2_get_byte(&ctx->gb);
     872           0 :     int skip    = bytestream2_get_byte(&ctx->gb);
     873             : 
     874           0 :     bytestream2_skip(&ctx->gb, 9);
     875           0 :     decoded_size = bytestream2_get_le32(&ctx->gb);
     876           0 :     bytestream2_skip(&ctx->gb, 8);
     877             : 
     878           0 :     if (decoded_size > ctx->height * stride - left - top * stride) {
     879           0 :         decoded_size = ctx->height * stride - left - top * stride;
     880           0 :         av_log(ctx->avctx, AV_LOG_WARNING, "Decoded size is too large.\n");
     881             :     }
     882             : 
     883           0 :     if (skip & 1)
     884           0 :         bytestream2_skip(&ctx->gb, 0x8080);
     885           0 :     if (!seq) {
     886           0 :         ctx->prev_seq = -1;
     887           0 :         memset(prev1, 0, ctx->height * stride);
     888           0 :         memset(prev2, 0, ctx->height * stride);
     889             :     }
     890             : 
     891           0 :     switch (compr) {
     892           0 :     case 0:
     893           0 :         if (bytestream2_get_bytes_left(&ctx->gb) < width * height)
     894           0 :             return AVERROR_INVALIDDATA;
     895           0 :         for (j = 0; j < height; j++) {
     896           0 :             bytestream2_get_bufferu(&ctx->gb, dst, width);
     897           0 :             dst += stride;
     898             :         }
     899           0 :         break;
     900           0 :     case 1:
     901           0 :         if (bytestream2_get_bytes_left(&ctx->gb) < ((width + 1) >> 1) * ((height + 1) >> 1))
     902           0 :             return AVERROR_INVALIDDATA;
     903           0 :         for (j = 0; j < height; j += 2) {
     904           0 :             for (i = 0; i < width; i += 2) {
     905           0 :                 dst[i] =
     906           0 :                 dst[i + 1] =
     907           0 :                 dst[stride + i] =
     908           0 :                 dst[stride + i + 1] = bytestream2_get_byteu(&ctx->gb);
     909             :             }
     910           0 :             dst += stride * 2;
     911             :         }
     912           0 :         break;
     913           0 :     case 2:
     914           0 :         if (seq == ctx->prev_seq + 1) {
     915           0 :             for (j = 0; j < height; j += 8) {
     916           0 :                 for (i = 0; i < width; i += 8)
     917           0 :                     if (process_block(ctx, dst + i, prev1 + i, prev2 + i, stride,
     918             :                                       tbl_pos + 8, 8))
     919           0 :                         return AVERROR_INVALIDDATA;
     920           0 :                 dst   += stride * 8;
     921           0 :                 prev1 += stride * 8;
     922           0 :                 prev2 += stride * 8;
     923             :             }
     924             :         }
     925           0 :         break;
     926           0 :     case 3:
     927           0 :         memcpy(ctx->frm0, ctx->frm2, ctx->pitch * ctx->height);
     928           0 :         break;
     929           0 :     case 4:
     930           0 :         memcpy(ctx->frm0, ctx->frm1, ctx->pitch * ctx->height);
     931           0 :         break;
     932           0 :     case 5:
     933           0 :         if (rle_decode(ctx, dst, decoded_size))
     934           0 :             return AVERROR_INVALIDDATA;
     935           0 :         break;
     936           0 :     default:
     937           0 :         avpriv_report_missing_feature(ctx->avctx,
     938             :                                       "Subcodec 47 compression %d", compr);
     939           0 :         return AVERROR_PATCHWELCOME;
     940             :     }
     941           0 :     if (seq == ctx->prev_seq + 1)
     942           0 :         ctx->rotate_code = new_rot;
     943             :     else
     944           0 :         ctx->rotate_code = 0;
     945           0 :     ctx->prev_seq = seq;
     946             : 
     947           0 :     return 0;
     948             : }
     949             : 
     950           0 : static int process_frame_obj(SANMVideoContext *ctx)
     951             : {
     952           0 :     uint16_t codec = bytestream2_get_le16u(&ctx->gb);
     953           0 :     uint16_t left  = bytestream2_get_le16u(&ctx->gb);
     954           0 :     uint16_t top   = bytestream2_get_le16u(&ctx->gb);
     955           0 :     uint16_t w     = bytestream2_get_le16u(&ctx->gb);
     956           0 :     uint16_t h     = bytestream2_get_le16u(&ctx->gb);
     957             : 
     958           0 :     if (!w || !h) {
     959           0 :         av_log(ctx->avctx, AV_LOG_ERROR, "Dimensions are invalid.\n");
     960           0 :         return AVERROR_INVALIDDATA;
     961             :     }
     962             : 
     963           0 :     if (ctx->width < left + w || ctx->height < top + h) {
     964           0 :         int ret = ff_set_dimensions(ctx->avctx, FFMAX(left + w, ctx->width),
     965           0 :                                     FFMAX(top + h, ctx->height));
     966           0 :         if (ret < 0)
     967           0 :             return ret;
     968           0 :         init_sizes(ctx, FFMAX(left + w, ctx->width),
     969           0 :                    FFMAX(top + h, ctx->height));
     970           0 :         if (init_buffers(ctx)) {
     971           0 :             av_log(ctx->avctx, AV_LOG_ERROR, "Error resizing buffers.\n");
     972           0 :             return AVERROR(ENOMEM);
     973             :         }
     974             :     }
     975           0 :     bytestream2_skip(&ctx->gb, 4);
     976             : 
     977           0 :     switch (codec) {
     978           0 :     case 1:
     979             :     case 3:
     980           0 :         return old_codec1(ctx, top, left, w, h);
     981           0 :     case 37:
     982           0 :         return old_codec37(ctx, top, left, w, h);
     983           0 :     case 47:
     984           0 :         return old_codec47(ctx, top, left, w, h);
     985           0 :     default:
     986           0 :         avpriv_request_sample(ctx->avctx, "Subcodec %d", codec);
     987           0 :         return AVERROR_PATCHWELCOME;
     988             :     }
     989             : }
     990             : 
     991           0 : static int decode_0(SANMVideoContext *ctx)
     992             : {
     993           0 :     uint16_t *frm = ctx->frm0;
     994             :     int x, y;
     995             : 
     996           0 :     if (bytestream2_get_bytes_left(&ctx->gb) < ctx->width * ctx->height * 2) {
     997           0 :         av_log(ctx->avctx, AV_LOG_ERROR, "Insufficient data for raw frame.\n");
     998           0 :         return AVERROR_INVALIDDATA;
     999             :     }
    1000           0 :     for (y = 0; y < ctx->height; y++) {
    1001           0 :         for (x = 0; x < ctx->width; x++)
    1002           0 :             frm[x] = bytestream2_get_le16u(&ctx->gb);
    1003           0 :         frm += ctx->pitch;
    1004             :     }
    1005           0 :     return 0;
    1006             : }
    1007             : 
    1008           0 : static int decode_nop(SANMVideoContext *ctx)
    1009             : {
    1010           0 :     avpriv_request_sample(ctx->avctx, "Unknown/unsupported compression type");
    1011           0 :     return AVERROR_PATCHWELCOME;
    1012             : }
    1013             : 
    1014       42964 : static void copy_block(uint16_t *pdest, uint16_t *psrc, int block_size, ptrdiff_t pitch)
    1015             : {
    1016       42964 :     uint8_t *dst = (uint8_t *)pdest;
    1017       42964 :     uint8_t *src = (uint8_t *)psrc;
    1018       42964 :     ptrdiff_t stride = pitch * 2;
    1019             : 
    1020       42964 :     switch (block_size) {
    1021       14526 :     case 2:
    1022       14526 :         copy_block4(dst, src, stride, stride, 2);
    1023       14526 :         break;
    1024       12400 :     case 4:
    1025       12400 :         copy_block8(dst, src, stride, stride, 4);
    1026       12400 :         break;
    1027       16038 :     case 8:
    1028       16038 :         copy_block16(dst, src, stride, stride, 8);
    1029       16038 :         break;
    1030             :     }
    1031       42964 : }
    1032             : 
    1033        7913 : static void fill_block(uint16_t *pdest, uint16_t color, int block_size, ptrdiff_t pitch)
    1034             : {
    1035             :     int x, y;
    1036             : 
    1037        7913 :     pitch -= block_size;
    1038       38351 :     for (y = 0; y < block_size; y++, pdest += pitch)
    1039      179978 :         for (x = 0; x < block_size; x++)
    1040      149540 :             *pdest++ = color;
    1041        7913 : }
    1042             : 
    1043        8368 : static int draw_glyph(SANMVideoContext *ctx, uint16_t *dst, int index,
    1044             :                       uint16_t fg_color, uint16_t bg_color, int block_size,
    1045             :                       ptrdiff_t pitch)
    1046             : {
    1047             :     int8_t *pglyph;
    1048        8368 :     uint16_t colors[2] = { fg_color, bg_color };
    1049             :     int x, y;
    1050             : 
    1051        8368 :     if (index >= NGLYPHS) {
    1052           0 :         av_log(ctx->avctx, AV_LOG_ERROR, "Ignoring nonexistent glyph #%u.\n", index);
    1053           0 :         return AVERROR_INVALIDDATA;
    1054             :     }
    1055             : 
    1056        8368 :     pglyph = block_size == 8 ? ctx->p8x8glyphs[index] : ctx->p4x4glyphs[index];
    1057        8368 :     pitch -= block_size;
    1058             : 
    1059       46472 :     for (y = 0; y < block_size; y++, dst += pitch)
    1060      227576 :         for (x = 0; x < block_size; x++)
    1061      189472 :             *dst++ = colors[*pglyph++];
    1062        8368 :     return 0;
    1063             : }
    1064             : 
    1065        8029 : static int opcode_0xf7(SANMVideoContext *ctx, int cx, int cy, int block_size, ptrdiff_t pitch)
    1066             : {
    1067        8029 :     uint16_t *dst = ctx->frm0 + cx + cy * ctx->pitch;
    1068             : 
    1069        8029 :     if (block_size == 2) {
    1070             :         uint32_t indices;
    1071             : 
    1072         825 :         if (bytestream2_get_bytes_left(&ctx->gb) < 4)
    1073           0 :             return AVERROR_INVALIDDATA;
    1074             : 
    1075         825 :         indices        = bytestream2_get_le32u(&ctx->gb);
    1076         825 :         dst[0]         = ctx->codebook[indices & 0xFF];
    1077         825 :         indices      >>= 8;
    1078         825 :         dst[1]         = ctx->codebook[indices & 0xFF];
    1079         825 :         indices      >>= 8;
    1080         825 :         dst[pitch]     = ctx->codebook[indices & 0xFF];
    1081         825 :         indices      >>= 8;
    1082         825 :         dst[pitch + 1] = ctx->codebook[indices & 0xFF];
    1083             :     } else {
    1084             :         uint16_t fgcolor, bgcolor;
    1085             :         int glyph;
    1086             : 
    1087        7204 :         if (bytestream2_get_bytes_left(&ctx->gb) < 3)
    1088           1 :             return AVERROR_INVALIDDATA;
    1089             : 
    1090        7203 :         glyph   = bytestream2_get_byteu(&ctx->gb);
    1091        7203 :         bgcolor = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
    1092        7203 :         fgcolor = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
    1093             : 
    1094        7203 :         draw_glyph(ctx, dst, glyph, fgcolor, bgcolor, block_size, pitch);
    1095             :     }
    1096        8028 :     return 0;
    1097             : }
    1098             : 
    1099        1169 : static int opcode_0xf8(SANMVideoContext *ctx, int cx, int cy, int block_size, ptrdiff_t pitch)
    1100             : {
    1101        1169 :     uint16_t *dst = ctx->frm0 + cx + cy * ctx->pitch;
    1102             : 
    1103        1169 :     if (block_size == 2) {
    1104           4 :         if (bytestream2_get_bytes_left(&ctx->gb) < 8)
    1105           0 :             return AVERROR_INVALIDDATA;
    1106             : 
    1107           4 :         dst[0]         = bytestream2_get_le16u(&ctx->gb);
    1108           4 :         dst[1]         = bytestream2_get_le16u(&ctx->gb);
    1109           4 :         dst[pitch]     = bytestream2_get_le16u(&ctx->gb);
    1110           4 :         dst[pitch + 1] = bytestream2_get_le16u(&ctx->gb);
    1111             :     } else {
    1112             :         uint16_t fgcolor, bgcolor;
    1113             :         int glyph;
    1114             : 
    1115        1165 :         if (bytestream2_get_bytes_left(&ctx->gb) < 5)
    1116           0 :             return AVERROR_INVALIDDATA;
    1117             : 
    1118        1165 :         glyph   = bytestream2_get_byteu(&ctx->gb);
    1119        1165 :         bgcolor = bytestream2_get_le16u(&ctx->gb);
    1120        1165 :         fgcolor = bytestream2_get_le16u(&ctx->gb);
    1121             : 
    1122        1165 :         draw_glyph(ctx, dst, glyph, fgcolor, bgcolor, block_size, pitch);
    1123             :     }
    1124        1169 :     return 0;
    1125             : }
    1126             : 
    1127       30376 : static int good_mvec(SANMVideoContext *ctx, int cx, int cy, int mx, int my,
    1128             :                      int block_size)
    1129             : {
    1130       30376 :     int start_pos = cx + mx + (cy + my) * ctx->pitch;
    1131       30376 :     int end_pos = start_pos + (block_size - 1) * (ctx->pitch + 1);
    1132             : 
    1133       30376 :     int good = start_pos >= 0 && end_pos < (ctx->buf_size >> 1);
    1134             : 
    1135       30376 :     if (!good)
    1136           0 :         av_log(ctx->avctx, AV_LOG_ERROR,
    1137             :                "Ignoring invalid motion vector (%i, %i)->(%u, %u), block size = %u\n",
    1138             :                cx + mx, cy + my, cx, cy, block_size);
    1139             : 
    1140       30376 :     return good;
    1141             : }
    1142             : 
    1143       71636 : static int codec2subblock(SANMVideoContext *ctx, int cx, int cy, int blk_size)
    1144             : {
    1145             :     int16_t mx, my, index;
    1146             :     int opcode;
    1147             : 
    1148       71636 :     if (bytestream2_get_bytes_left(&ctx->gb) < 1)
    1149           1 :         return AVERROR_INVALIDDATA;
    1150             : 
    1151       71635 :     opcode = bytestream2_get_byteu(&ctx->gb);
    1152             : 
    1153       71635 :     switch (opcode) {
    1154       28212 :     default:
    1155       28212 :         mx = motion_vectors[opcode][0];
    1156       28212 :         my = motion_vectors[opcode][1];
    1157             : 
    1158       28212 :         if (good_mvec(ctx, cx, cy, mx, my, blk_size)) {
    1159       56424 :             copy_block(ctx->frm0 + cx      + ctx->pitch *  cy,
    1160       28212 :                        ctx->frm2 + cx + mx + ctx->pitch * (cy + my),
    1161             :                        blk_size, ctx->pitch);
    1162             :         }
    1163       28212 :         break;
    1164        2164 :     case 0xF5:
    1165        2164 :         if (bytestream2_get_bytes_left(&ctx->gb) < 2)
    1166           0 :             return AVERROR_INVALIDDATA;
    1167        2164 :         index = bytestream2_get_le16u(&ctx->gb);
    1168             : 
    1169        2164 :         mx = index % ctx->width;
    1170        2164 :         my = index / ctx->width;
    1171             : 
    1172        2164 :         if (good_mvec(ctx, cx, cy, mx, my, blk_size)) {
    1173        4328 :             copy_block(ctx->frm0 + cx      + ctx->pitch *  cy,
    1174        2164 :                        ctx->frm2 + cx + mx + ctx->pitch * (cy + my),
    1175             :                        blk_size, ctx->pitch);
    1176             :         }
    1177        2164 :         break;
    1178       12588 :     case 0xF6:
    1179       25176 :         copy_block(ctx->frm0 + cx + ctx->pitch * cy,
    1180       12588 :                    ctx->frm1 + cx + ctx->pitch * cy,
    1181             :                    blk_size, ctx->pitch);
    1182       12588 :         break;
    1183        8029 :     case 0xF7:
    1184        8029 :         opcode_0xf7(ctx, cx, cy, blk_size, ctx->pitch);
    1185        8029 :         break;
    1186             : 
    1187        1169 :     case 0xF8:
    1188        1169 :         opcode_0xf8(ctx, cx, cy, blk_size, ctx->pitch);
    1189        1169 :         break;
    1190         315 :     case 0xF9:
    1191             :     case 0xFA:
    1192             :     case 0xFB:
    1193             :     case 0xFC:
    1194         630 :         fill_block(ctx->frm0 + cx + cy * ctx->pitch,
    1195         315 :                    ctx->small_codebook[opcode - 0xf9], blk_size, ctx->pitch);
    1196         315 :         break;
    1197        5496 :     case 0xFD:
    1198        5496 :         if (bytestream2_get_bytes_left(&ctx->gb) < 1)
    1199           0 :             return AVERROR_INVALIDDATA;
    1200       10992 :         fill_block(ctx->frm0 + cx + cy * ctx->pitch,
    1201        5496 :                    ctx->codebook[bytestream2_get_byteu(&ctx->gb)], blk_size, ctx->pitch);
    1202        5496 :         break;
    1203        2102 :     case 0xFE:
    1204        2102 :         if (bytestream2_get_bytes_left(&ctx->gb) < 2)
    1205           0 :             return AVERROR_INVALIDDATA;
    1206        4204 :         fill_block(ctx->frm0 + cx + cy * ctx->pitch,
    1207        2102 :                    bytestream2_get_le16u(&ctx->gb), blk_size, ctx->pitch);
    1208        2102 :         break;
    1209       11560 :     case 0xFF:
    1210       11560 :         if (blk_size == 2) {
    1211           0 :             opcode_0xf8(ctx, cx, cy, blk_size, ctx->pitch);
    1212             :         } else {
    1213       11560 :             blk_size >>= 1;
    1214       11560 :             if (codec2subblock(ctx, cx, cy, blk_size))
    1215           0 :                 return AVERROR_INVALIDDATA;
    1216       11560 :             if (codec2subblock(ctx, cx + blk_size, cy, blk_size))
    1217           0 :                 return AVERROR_INVALIDDATA;
    1218       11560 :             if (codec2subblock(ctx, cx, cy + blk_size, blk_size))
    1219           0 :                 return AVERROR_INVALIDDATA;
    1220       11560 :             if (codec2subblock(ctx, cx + blk_size, cy + blk_size, blk_size))
    1221           0 :                 return AVERROR_INVALIDDATA;
    1222             :         }
    1223       11560 :         break;
    1224             :     }
    1225       71635 :     return 0;
    1226             : }
    1227             : 
    1228           6 : static int decode_2(SANMVideoContext *ctx)
    1229             : {
    1230             :     int cx, cy, ret;
    1231             : 
    1232         323 :     for (cy = 0; cy < ctx->aligned_height; cy += 8)
    1233       25713 :         for (cx = 0; cx < ctx->aligned_width; cx += 8)
    1234       25396 :             if (ret = codec2subblock(ctx, cx, cy, 8))
    1235           1 :                 return ret;
    1236             : 
    1237           5 :     return 0;
    1238             : }
    1239             : 
    1240           0 : static int decode_3(SANMVideoContext *ctx)
    1241             : {
    1242           0 :     memcpy(ctx->frm0, ctx->frm2, ctx->frm2_size);
    1243           0 :     return 0;
    1244             : }
    1245             : 
    1246           9 : static int decode_4(SANMVideoContext *ctx)
    1247             : {
    1248           9 :     memcpy(ctx->frm0, ctx->frm1, ctx->frm1_size);
    1249           9 :     return 0;
    1250             : }
    1251             : 
    1252           1 : static int decode_5(SANMVideoContext *ctx)
    1253             : {
    1254             : #if HAVE_BIGENDIAN
    1255             :     uint16_t *frm;
    1256             :     int npixels;
    1257             : #endif
    1258           1 :     uint8_t *dst = (uint8_t*)ctx->frm0;
    1259             : 
    1260           1 :     if (rle_decode(ctx, dst, ctx->buf_size))
    1261           0 :         return AVERROR_INVALIDDATA;
    1262             : 
    1263             : #if HAVE_BIGENDIAN
    1264             :     npixels = ctx->npixels;
    1265             :     frm = ctx->frm0;
    1266             :     while (npixels--) {
    1267             :         *frm = av_bswap16(*frm);
    1268             :         frm++;
    1269             :     }
    1270             : #endif
    1271             : 
    1272           1 :     return 0;
    1273             : }
    1274             : 
    1275           0 : static int decode_6(SANMVideoContext *ctx)
    1276             : {
    1277           0 :     int npixels = ctx->npixels;
    1278           0 :     uint16_t *frm = ctx->frm0;
    1279             : 
    1280           0 :     if (bytestream2_get_bytes_left(&ctx->gb) < npixels) {
    1281           0 :         av_log(ctx->avctx, AV_LOG_ERROR, "Insufficient data for frame.\n");
    1282           0 :         return AVERROR_INVALIDDATA;
    1283             :     }
    1284           0 :     while (npixels--)
    1285           0 :         *frm++ = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
    1286             : 
    1287           0 :     return 0;
    1288             : }
    1289             : 
    1290           0 : static int decode_8(SANMVideoContext *ctx)
    1291             : {
    1292           0 :     uint16_t *pdest = ctx->frm0;
    1293             :     uint8_t *rsrc;
    1294           0 :     long npixels = ctx->npixels;
    1295             : 
    1296           0 :     av_fast_malloc(&ctx->rle_buf, &ctx->rle_buf_size, npixels);
    1297           0 :     if (!ctx->rle_buf) {
    1298           0 :         av_log(ctx->avctx, AV_LOG_ERROR, "RLE buffer allocation failed.\n");
    1299           0 :         return AVERROR(ENOMEM);
    1300             :     }
    1301           0 :     rsrc = ctx->rle_buf;
    1302             : 
    1303           0 :     if (rle_decode(ctx, rsrc, npixels))
    1304           0 :         return AVERROR_INVALIDDATA;
    1305             : 
    1306           0 :     while (npixels--)
    1307           0 :         *pdest++ = ctx->codebook[*rsrc++];
    1308             : 
    1309           0 :     return 0;
    1310             : }
    1311             : 
    1312             : typedef int (*frm_decoder)(SANMVideoContext *ctx);
    1313             : 
    1314             : static const frm_decoder v1_decoders[] = {
    1315             :     decode_0, decode_nop, decode_2, decode_3, decode_4, decode_5,
    1316             :     decode_6, decode_nop, decode_8
    1317             : };
    1318             : 
    1319          16 : static int read_frame_header(SANMVideoContext *ctx, SANMFrameHeader *hdr)
    1320             : {
    1321             :     int i, ret;
    1322             : 
    1323          16 :     if ((ret = bytestream2_get_bytes_left(&ctx->gb)) < 560) {
    1324           0 :         av_log(ctx->avctx, AV_LOG_ERROR, "Input frame too short (%d bytes).\n",
    1325             :                ret);
    1326           0 :         return AVERROR_INVALIDDATA;
    1327             :     }
    1328          16 :     bytestream2_skip(&ctx->gb, 8); // skip pad
    1329             : 
    1330          16 :     hdr->width  = bytestream2_get_le32u(&ctx->gb);
    1331          16 :     hdr->height = bytestream2_get_le32u(&ctx->gb);
    1332             : 
    1333          16 :     if (hdr->width != ctx->width || hdr->height != ctx->height) {
    1334           0 :         avpriv_report_missing_feature(ctx->avctx, "Variable size frames");
    1335           0 :         return AVERROR_PATCHWELCOME;
    1336             :     }
    1337             : 
    1338          16 :     hdr->seq_num     = bytestream2_get_le16u(&ctx->gb);
    1339          16 :     hdr->codec       = bytestream2_get_byteu(&ctx->gb);
    1340          16 :     hdr->rotate_code = bytestream2_get_byteu(&ctx->gb);
    1341             : 
    1342          16 :     bytestream2_skip(&ctx->gb, 4); // skip pad
    1343             : 
    1344          80 :     for (i = 0; i < 4; i++)
    1345          64 :         ctx->small_codebook[i] = bytestream2_get_le16u(&ctx->gb);
    1346          16 :     hdr->bg_color = bytestream2_get_le16u(&ctx->gb);
    1347             : 
    1348          16 :     bytestream2_skip(&ctx->gb, 2); // skip pad
    1349             : 
    1350          16 :     hdr->rle_output_size = bytestream2_get_le32u(&ctx->gb);
    1351        4112 :     for (i = 0; i < 256; i++)
    1352        4096 :         ctx->codebook[i] = bytestream2_get_le16u(&ctx->gb);
    1353             : 
    1354          16 :     bytestream2_skip(&ctx->gb, 8); // skip pad
    1355             : 
    1356          16 :     return 0;
    1357             : }
    1358             : 
    1359           2 : static void fill_frame(uint16_t *pbuf, int buf_size, uint16_t color)
    1360             : {
    1361      614404 :     while (buf_size--)
    1362      614400 :         *pbuf++ = color;
    1363           2 : }
    1364             : 
    1365          15 : static int copy_output(SANMVideoContext *ctx, SANMFrameHeader *hdr)
    1366             : {
    1367             :     uint8_t *dst;
    1368          15 :     const uint8_t *src = (uint8_t*) ctx->frm0;
    1369          15 :     int ret, height = ctx->height;
    1370          15 :     ptrdiff_t dstpitch, srcpitch = ctx->pitch * (hdr ? sizeof(ctx->frm0[0]) : 1);
    1371             : 
    1372          15 :     if ((ret = ff_get_buffer(ctx->avctx, ctx->frame, 0)) < 0)
    1373           0 :         return ret;
    1374             : 
    1375          15 :     dst      = ctx->frame->data[0];
    1376          15 :     dstpitch = ctx->frame->linesize[0];
    1377             : 
    1378        7230 :     while (height--) {
    1379        7200 :         memcpy(dst, src, srcpitch);
    1380        7200 :         src += srcpitch;
    1381        7200 :         dst += dstpitch;
    1382             :     }
    1383             : 
    1384          15 :     return 0;
    1385             : }
    1386             : 
    1387          16 : static int decode_frame(AVCodecContext *avctx, void *data,
    1388             :                         int *got_frame_ptr, AVPacket *pkt)
    1389             : {
    1390          16 :     SANMVideoContext *ctx = avctx->priv_data;
    1391             :     int i, ret;
    1392             : 
    1393          16 :     ctx->frame = data;
    1394          16 :     bytestream2_init(&ctx->gb, pkt->data, pkt->size);
    1395             : 
    1396          16 :     if (!ctx->version) {
    1397           0 :         int to_store = 0;
    1398             : 
    1399           0 :         while (bytestream2_get_bytes_left(&ctx->gb) >= 8) {
    1400             :             uint32_t sig, size;
    1401             :             int pos;
    1402             : 
    1403           0 :             sig  = bytestream2_get_be32u(&ctx->gb);
    1404           0 :             size = bytestream2_get_be32u(&ctx->gb);
    1405           0 :             pos  = bytestream2_tell(&ctx->gb);
    1406             : 
    1407           0 :             if (bytestream2_get_bytes_left(&ctx->gb) < size) {
    1408           0 :                 av_log(avctx, AV_LOG_ERROR, "Incorrect chunk size %"PRIu32".\n", size);
    1409           0 :                 break;
    1410             :             }
    1411           0 :             switch (sig) {
    1412           0 :             case MKBETAG('N', 'P', 'A', 'L'):
    1413           0 :                 if (size != PALETTE_SIZE * 3) {
    1414           0 :                     av_log(avctx, AV_LOG_ERROR,
    1415             :                            "Incorrect palette block size %"PRIu32".\n", size);
    1416           0 :                     return AVERROR_INVALIDDATA;
    1417             :                 }
    1418           0 :                 for (i = 0; i < PALETTE_SIZE; i++)
    1419           0 :                     ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb);
    1420           0 :                 break;
    1421           0 :             case MKBETAG('F', 'O', 'B', 'J'):
    1422           0 :                 if (size < 16)
    1423           0 :                     return AVERROR_INVALIDDATA;
    1424           0 :                 if (ret = process_frame_obj(ctx))
    1425           0 :                     return ret;
    1426           0 :                 break;
    1427           0 :             case MKBETAG('X', 'P', 'A', 'L'):
    1428           0 :                 if (size == 6 || size == 4) {
    1429             :                     uint8_t tmp[3];
    1430             :                     int j;
    1431             : 
    1432           0 :                     for (i = 0; i < PALETTE_SIZE; i++) {
    1433           0 :                         for (j = 0; j < 3; j++) {
    1434           0 :                             int t = (ctx->pal[i] >> (16 - j * 8)) & 0xFF;
    1435           0 :                             tmp[j] = av_clip_uint8((t * 129 + ctx->delta_pal[i * 3 + j]) >> 7);
    1436             :                         }
    1437           0 :                         ctx->pal[i] = 0xFFU << 24 | AV_RB24(tmp);
    1438             :                     }
    1439             :                 } else {
    1440           0 :                     if (size < PALETTE_DELTA * 2 + 4) {
    1441           0 :                         av_log(avctx, AV_LOG_ERROR,
    1442             :                                "Incorrect palette change block size %"PRIu32".\n",
    1443             :                                size);
    1444           0 :                         return AVERROR_INVALIDDATA;
    1445             :                     }
    1446           0 :                     bytestream2_skipu(&ctx->gb, 4);
    1447           0 :                     for (i = 0; i < PALETTE_DELTA; i++)
    1448           0 :                         ctx->delta_pal[i] = bytestream2_get_le16u(&ctx->gb);
    1449           0 :                     if (size >= PALETTE_DELTA * 5 + 4) {
    1450           0 :                         for (i = 0; i < PALETTE_SIZE; i++)
    1451           0 :                             ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb);
    1452             :                     } else {
    1453           0 :                         memset(ctx->pal, 0, sizeof(ctx->pal));
    1454             :                     }
    1455             :                 }
    1456           0 :                 break;
    1457           0 :             case MKBETAG('S', 'T', 'O', 'R'):
    1458           0 :                 to_store = 1;
    1459           0 :                 break;
    1460           0 :             case MKBETAG('F', 'T', 'C', 'H'):
    1461           0 :                 memcpy(ctx->frm0, ctx->stored_frame, ctx->buf_size);
    1462           0 :                 break;
    1463           0 :             default:
    1464           0 :                 bytestream2_skip(&ctx->gb, size);
    1465           0 :                 av_log(avctx, AV_LOG_DEBUG,
    1466             :                        "Unknown/unsupported chunk %"PRIx32".\n", sig);
    1467           0 :                 break;
    1468             :             }
    1469             : 
    1470           0 :             bytestream2_seek(&ctx->gb, pos + size, SEEK_SET);
    1471           0 :             if (size & 1)
    1472           0 :                 bytestream2_skip(&ctx->gb, 1);
    1473             :         }
    1474           0 :         if (to_store)
    1475           0 :             memcpy(ctx->stored_frame, ctx->frm0, ctx->buf_size);
    1476           0 :         if ((ret = copy_output(ctx, NULL)))
    1477           0 :             return ret;
    1478           0 :         memcpy(ctx->frame->data[1], ctx->pal, 1024);
    1479             :     } else {
    1480             :         SANMFrameHeader header;
    1481             : 
    1482          16 :         if ((ret = read_frame_header(ctx, &header)))
    1483           1 :             return ret;
    1484             : 
    1485          16 :         ctx->rotate_code = header.rotate_code;
    1486          16 :         if ((ctx->frame->key_frame = !header.seq_num)) {
    1487           1 :             ctx->frame->pict_type = AV_PICTURE_TYPE_I;
    1488           1 :             fill_frame(ctx->frm1, ctx->npixels, header.bg_color);
    1489           1 :             fill_frame(ctx->frm2, ctx->npixels, header.bg_color);
    1490             :         } else {
    1491          15 :             ctx->frame->pict_type = AV_PICTURE_TYPE_P;
    1492             :         }
    1493             : 
    1494          16 :         if (header.codec < FF_ARRAY_ELEMS(v1_decoders)) {
    1495          16 :             if ((ret = v1_decoders[header.codec](ctx))) {
    1496           1 :                 av_log(avctx, AV_LOG_ERROR,
    1497             :                        "Subcodec %d: error decoding frame.\n", header.codec);
    1498           1 :                 return ret;
    1499             :             }
    1500             :         } else {
    1501           0 :             avpriv_request_sample(avctx, "Subcodec %d", header.codec);
    1502           0 :             return AVERROR_PATCHWELCOME;
    1503             :         }
    1504             : 
    1505          15 :         if ((ret = copy_output(ctx, &header)))
    1506           0 :             return ret;
    1507             :     }
    1508          15 :     if (ctx->rotate_code)
    1509           9 :         rotate_bufs(ctx, ctx->rotate_code);
    1510             : 
    1511          15 :     *got_frame_ptr = 1;
    1512             : 
    1513          15 :     return pkt->size;
    1514             : }
    1515             : 
    1516             : AVCodec ff_sanm_decoder = {
    1517             :     .name           = "sanm",
    1518             :     .long_name      = NULL_IF_CONFIG_SMALL("LucasArts SANM/Smush video"),
    1519             :     .type           = AVMEDIA_TYPE_VIDEO,
    1520             :     .id             = AV_CODEC_ID_SANM,
    1521             :     .priv_data_size = sizeof(SANMVideoContext),
    1522             :     .init           = decode_init,
    1523             :     .close          = decode_end,
    1524             :     .decode         = decode_frame,
    1525             :     .capabilities   = AV_CODEC_CAP_DR1,
    1526             : };

Generated by: LCOV version 1.13