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     int 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  */
which_edge(int x,int y,int edge_size)326 static enum GlyphEdge which_edge(int x, int y, int edge_size)
327 {
328     const int edge_max = edge_size - 1;
329 
330     if (!y)
331         return BOTTOM_EDGE;
332     else if (y == edge_max)
333         return TOP_EDGE;
334     else if (!x)
335         return LEFT_EDGE;
336     else if (x == edge_max)
337         return RIGHT_EDGE;
338     else
339         return NO_EDGE;
340 }
341 
which_direction(enum GlyphEdge edge0,enum GlyphEdge edge1)342 static enum GlyphDir which_direction(enum GlyphEdge edge0, enum GlyphEdge edge1)
343 {
344     if ((edge0 == LEFT_EDGE && edge1 == RIGHT_EDGE) ||
345         (edge1 == LEFT_EDGE && edge0 == RIGHT_EDGE) ||
346         (edge0 == BOTTOM_EDGE && edge1 != TOP_EDGE) ||
347         (edge1 == BOTTOM_EDGE && edge0 != TOP_EDGE))
348         return DIR_UP;
349     else if ((edge0 == TOP_EDGE && edge1 != BOTTOM_EDGE) ||
350              (edge1 == TOP_EDGE && edge0 != BOTTOM_EDGE))
351         return DIR_DOWN;
352     else if ((edge0 == LEFT_EDGE && edge1 != RIGHT_EDGE) ||
353              (edge1 == LEFT_EDGE && edge0 != RIGHT_EDGE))
354         return DIR_LEFT;
355     else if ((edge0 == TOP_EDGE && edge1 == BOTTOM_EDGE) ||
356              (edge1 == TOP_EDGE && edge0 == BOTTOM_EDGE) ||
357              (edge0 == RIGHT_EDGE && edge1 != LEFT_EDGE) ||
358              (edge1 == RIGHT_EDGE && edge0 != LEFT_EDGE))
359         return DIR_RIGHT;
360 
361     return NO_DIR;
362 }
363 
364 /* Interpolate two points. */
interp_point(int8_t * points,int x0,int y0,int x1,int y1,int pos,int npoints)365 static void interp_point(int8_t *points, int x0, int y0, int x1, int y1,
366                          int pos, int npoints)
367 {
368     if (npoints) {
369         points[0] = (x0 * pos + x1 * (npoints - pos) + (npoints >> 1)) / npoints;
370         points[1] = (y0 * pos + y1 * (npoints - pos) + (npoints >> 1)) / npoints;
371     } else {
372         points[0] = x0;
373         points[1] = y0;
374     }
375 }
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  */
make_glyphs(int8_t * pglyphs,const int8_t * xvec,const int8_t * yvec,const int side_length)385 static void make_glyphs(int8_t *pglyphs, const int8_t *xvec, const int8_t *yvec,
386                         const int side_length)
387 {
388     const int glyph_size = side_length * side_length;
389     int8_t *pglyph = pglyphs;
390 
391     int i, j;
392     for (i = 0; i < GLYPH_COORD_VECT_SIZE; i++) {
393         int x0 = xvec[i];
394         int y0 = yvec[i];
395         enum GlyphEdge edge0 = which_edge(x0, y0, side_length);
396 
397         for (j = 0; j < GLYPH_COORD_VECT_SIZE; j++, pglyph += glyph_size) {
398             int x1 = xvec[j];
399             int y1 = yvec[j];
400             enum GlyphEdge edge1 = which_edge(x1, y1, side_length);
401             enum GlyphDir dir = which_direction(edge0, edge1);
402             int npoints = FFMAX(FFABS(x1 - x0), FFABS(y1 - y0));
403             int ipoint;
404 
405             for (ipoint = 0; ipoint <= npoints; ipoint++) {
406                 int8_t point[2];
407                 int irow, icol;
408 
409                 interp_point(point, x0, y0, x1, y1, ipoint, npoints);
410 
411                 switch (dir) {
412                 case DIR_UP:
413                     for (irow = point[1]; irow >= 0; irow--)
414                         pglyph[point[0] + irow * side_length] = 1;
415                     break;
416 
417                 case DIR_DOWN:
418                     for (irow = point[1]; irow < side_length; irow++)
419                         pglyph[point[0] + irow * side_length] = 1;
420                     break;
421 
422                 case DIR_LEFT:
423                     for (icol = point[0]; icol >= 0; icol--)
424                         pglyph[icol + point[1] * side_length] = 1;
425                     break;
426 
427                 case DIR_RIGHT:
428                     for (icol = point[0]; icol < side_length; icol++)
429                         pglyph[icol + point[1] * side_length] = 1;
430                     break;
431                 }
432             }
433         }
434     }
435 }
436 
init_sizes(SANMVideoContext * ctx,int width,int height)437 static void init_sizes(SANMVideoContext *ctx, int width, int height)
438 {
439     ctx->width   = width;
440     ctx->height  = height;
441     ctx->npixels = width * height;
442 
443     ctx->aligned_width  = FFALIGN(width, 8);
444     ctx->aligned_height = FFALIGN(height, 8);
445 
446     ctx->buf_size = ctx->aligned_width * ctx->aligned_height * sizeof(ctx->frm0[0]);
447     ctx->pitch    = width;
448 }
449 
destroy_buffers(SANMVideoContext * ctx)450 static void destroy_buffers(SANMVideoContext *ctx)
451 {
452     av_freep(&ctx->frm0);
453     av_freep(&ctx->frm1);
454     av_freep(&ctx->frm2);
455     av_freep(&ctx->stored_frame);
456     av_freep(&ctx->rle_buf);
457     ctx->frm0_size =
458     ctx->frm1_size =
459     ctx->frm2_size = 0;
460 }
461 
init_buffers(SANMVideoContext * ctx)462 static av_cold int init_buffers(SANMVideoContext *ctx)
463 {
464     av_fast_padded_malloc(&ctx->frm0, &ctx->frm0_size, ctx->buf_size);
465     av_fast_padded_malloc(&ctx->frm1, &ctx->frm1_size, ctx->buf_size);
466     av_fast_padded_malloc(&ctx->frm2, &ctx->frm2_size, ctx->buf_size);
467     if (!ctx->version)
468         av_fast_padded_malloc(&ctx->stored_frame,
469                               &ctx->stored_frame_size, ctx->buf_size);
470 
471     if (!ctx->frm0 || !ctx->frm1 || !ctx->frm2 ||
472         (!ctx->stored_frame && !ctx->version)) {
473         destroy_buffers(ctx);
474         return AVERROR(ENOMEM);
475     }
476 
477     return 0;
478 }
479 
rotate_bufs(SANMVideoContext * ctx,int rotate_code)480 static void rotate_bufs(SANMVideoContext *ctx, int rotate_code)
481 {
482     if (rotate_code == 2)
483         FFSWAP(uint16_t*, ctx->frm1, ctx->frm2);
484     FFSWAP(uint16_t*, ctx->frm2, ctx->frm0);
485 }
486 
decode_init(AVCodecContext * avctx)487 static av_cold int decode_init(AVCodecContext *avctx)
488 {
489     SANMVideoContext *ctx = avctx->priv_data;
490 
491     ctx->avctx   = avctx;
492     ctx->version = !avctx->extradata_size;
493 
494     avctx->pix_fmt = ctx->version ? AV_PIX_FMT_RGB565 : AV_PIX_FMT_PAL8;
495 
496     init_sizes(ctx, avctx->width, avctx->height);
497     if (init_buffers(ctx)) {
498         av_log(avctx, AV_LOG_ERROR, "Error allocating buffers.\n");
499         return AVERROR(ENOMEM);
500     }
501 
502     make_glyphs(ctx->p4x4glyphs[0], glyph4_x, glyph4_y, 4);
503     make_glyphs(ctx->p8x8glyphs[0], glyph8_x, glyph8_y, 8);
504 
505     if (!ctx->version) {
506         int i;
507 
508         if (avctx->extradata_size < 1026) {
509             av_log(avctx, AV_LOG_ERROR, "Not enough extradata.\n");
510             return AVERROR_INVALIDDATA;
511         }
512 
513         ctx->subversion = AV_RL16(avctx->extradata);
514         for (i = 0; i < PALETTE_SIZE; i++)
515             ctx->pal[i] = 0xFFU << 24 | AV_RL32(avctx->extradata + 2 + i * 4);
516     }
517 
518     return 0;
519 }
520 
decode_end(AVCodecContext * avctx)521 static av_cold int decode_end(AVCodecContext *avctx)
522 {
523     SANMVideoContext *ctx = avctx->priv_data;
524 
525     destroy_buffers(ctx);
526 
527     return 0;
528 }
529 
rle_decode(SANMVideoContext * ctx,uint8_t * dst,const int out_size)530 static int rle_decode(SANMVideoContext *ctx, uint8_t *dst, const int out_size)
531 {
532     int opcode, color, run_len, left = out_size;
533 
534     while (left > 0) {
535         opcode = bytestream2_get_byte(&ctx->gb);
536         run_len = (opcode >> 1) + 1;
537         if (run_len > left || bytestream2_get_bytes_left(&ctx->gb) <= 0)
538             return AVERROR_INVALIDDATA;
539 
540         if (opcode & 1) {
541             color = bytestream2_get_byte(&ctx->gb);
542             memset(dst, color, run_len);
543         } else {
544             if (bytestream2_get_bytes_left(&ctx->gb) < run_len)
545                 return AVERROR_INVALIDDATA;
546             bytestream2_get_bufferu(&ctx->gb, dst, run_len);
547         }
548 
549         dst  += run_len;
550         left -= run_len;
551     }
552 
553     return 0;
554 }
555 
old_codec1(SANMVideoContext * ctx,int top,int left,int width,int height)556 static int old_codec1(SANMVideoContext *ctx, int top,
557                       int left, int width, int height)
558 {
559     uint8_t *dst = ((uint8_t *)ctx->frm0) + left + top * ctx->pitch;
560     int i, j, len, flag, code, val, pos, end;
561 
562     for (i = 0; i < height; i++) {
563         pos = 0;
564 
565         if (bytestream2_get_bytes_left(&ctx->gb) < 2)
566             return AVERROR_INVALIDDATA;
567 
568         len = bytestream2_get_le16u(&ctx->gb);
569         end = bytestream2_tell(&ctx->gb) + len;
570 
571         while (bytestream2_tell(&ctx->gb) < end) {
572             if (bytestream2_get_bytes_left(&ctx->gb) < 2)
573                 return AVERROR_INVALIDDATA;
574 
575             code = bytestream2_get_byteu(&ctx->gb);
576             flag = code & 1;
577             code = (code >> 1) + 1;
578             if (pos + code > width)
579                 return AVERROR_INVALIDDATA;
580             if (flag) {
581                 val = bytestream2_get_byteu(&ctx->gb);
582                 if (val)
583                     memset(dst + pos, val, code);
584                 pos += code;
585             } else {
586                 if (bytestream2_get_bytes_left(&ctx->gb) < code)
587                     return AVERROR_INVALIDDATA;
588                 for (j = 0; j < code; j++) {
589                     val = bytestream2_get_byteu(&ctx->gb);
590                     if (val)
591                         dst[pos] = val;
592                     pos++;
593                 }
594             }
595         }
596         dst += ctx->pitch;
597     }
598     ctx->rotate_code = 0;
599 
600     return 0;
601 }
602 
codec37_mv(uint8_t * dst,const uint8_t * src,int height,int stride,int x,int y)603 static inline void codec37_mv(uint8_t *dst, const uint8_t *src,
604                               int height, int stride, int x, int y)
605 {
606     int pos, i, j;
607 
608     pos = x + y * stride;
609     for (j = 0; j < 4; j++) {
610         for (i = 0; i < 4; i++) {
611             if ((pos + i) < 0 || (pos + i) >= height * stride)
612                 dst[i] = 0;
613             else
614                 dst[i] = src[i];
615         }
616         dst += stride;
617         src += stride;
618         pos += stride;
619     }
620 }
621 
old_codec37(SANMVideoContext * ctx,int top,int left,int width,int height)622 static int old_codec37(SANMVideoContext *ctx, int top,
623                        int left, int width, int height)
624 {
625     int stride = ctx->pitch;
626     int i, j, k, t;
627     uint8_t *dst, *prev;
628     int skip_run = 0;
629     int compr = bytestream2_get_byte(&ctx->gb);
630     int mvoff = bytestream2_get_byte(&ctx->gb);
631     int seq   = bytestream2_get_le16(&ctx->gb);
632     uint32_t decoded_size = bytestream2_get_le32(&ctx->gb);
633     int flags;
634 
635     bytestream2_skip(&ctx->gb, 4);
636     flags = bytestream2_get_byte(&ctx->gb);
637     bytestream2_skip(&ctx->gb, 3);
638 
639     if (decoded_size > ctx->height * stride - left - top * stride) {
640         decoded_size = ctx->height * stride - left - top * stride;
641         av_log(ctx->avctx, AV_LOG_WARNING, "Decoded size is too large.\n");
642     }
643 
644     ctx->rotate_code = 0;
645 
646     if (((seq & 1) || !(flags & 1)) && (compr && compr != 2))
647         rotate_bufs(ctx, 1);
648 
649     dst  = ((uint8_t*)ctx->frm0) + left + top * stride;
650     prev = ((uint8_t*)ctx->frm2) + left + top * stride;
651 
652     if (mvoff > 2) {
653         av_log(ctx->avctx, AV_LOG_ERROR, "Invalid motion base value %d.\n", mvoff);
654         return AVERROR_INVALIDDATA;
655     }
656 
657     switch (compr) {
658     case 0:
659         for (i = 0; i < height; i++) {
660             bytestream2_get_buffer(&ctx->gb, dst, width);
661             dst += stride;
662         }
663         memset(ctx->frm1, 0, ctx->height * stride);
664         memset(ctx->frm2, 0, ctx->height * stride);
665         break;
666     case 2:
667         if (rle_decode(ctx, dst, decoded_size))
668             return AVERROR_INVALIDDATA;
669         memset(ctx->frm1, 0, ctx->frm1_size);
670         memset(ctx->frm2, 0, ctx->frm2_size);
671         break;
672     case 3:
673     case 4:
674         if (flags & 4) {
675             for (j = 0; j < height; j += 4) {
676                 for (i = 0; i < width; i += 4) {
677                     int code;
678                     if (skip_run) {
679                         skip_run--;
680                         copy_block4(dst + i, prev + i, stride, stride, 4);
681                         continue;
682                     }
683                     if (bytestream2_get_bytes_left(&ctx->gb) < 1)
684                         return AVERROR_INVALIDDATA;
685                     code = bytestream2_get_byteu(&ctx->gb);
686                     switch (code) {
687                     case 0xFF:
688                         if (bytestream2_get_bytes_left(&ctx->gb) < 16)
689                             return AVERROR_INVALIDDATA;
690                         for (k = 0; k < 4; k++)
691                             bytestream2_get_bufferu(&ctx->gb, dst + i + k * stride, 4);
692                         break;
693                     case 0xFE:
694                         if (bytestream2_get_bytes_left(&ctx->gb) < 4)
695                             return AVERROR_INVALIDDATA;
696                         for (k = 0; k < 4; k++)
697                             memset(dst + i + k * stride, bytestream2_get_byteu(&ctx->gb), 4);
698                         break;
699                     case 0xFD:
700                         if (bytestream2_get_bytes_left(&ctx->gb) < 1)
701                             return AVERROR_INVALIDDATA;
702                         t = bytestream2_get_byteu(&ctx->gb);
703                         for (k = 0; k < 4; k++)
704                             memset(dst + i + k * stride, t, 4);
705                         break;
706                     default:
707                         if (compr == 4 && !code) {
708                             if (bytestream2_get_bytes_left(&ctx->gb) < 1)
709                                 return AVERROR_INVALIDDATA;
710                             skip_run = bytestream2_get_byteu(&ctx->gb) + 1;
711                             i -= 4;
712                         } else {
713                             int mx, my;
714 
715                             mx = c37_mv[(mvoff * 255 + code) * 2];
716                             my = c37_mv[(mvoff * 255 + code) * 2 + 1];
717                             codec37_mv(dst + i, prev + i + mx + my * stride,
718                                        ctx->height, stride, i + mx, j + my);
719                         }
720                     }
721                 }
722                 dst  += stride * 4;
723                 prev += stride * 4;
724             }
725         } else {
726             for (j = 0; j < height; j += 4) {
727                 for (i = 0; i < width; i += 4) {
728                     int code;
729                     if (skip_run) {
730                         skip_run--;
731                         copy_block4(dst + i, prev + i, stride, stride, 4);
732                         continue;
733                     }
734                     code = bytestream2_get_byte(&ctx->gb);
735                     if (code == 0xFF) {
736                         if (bytestream2_get_bytes_left(&ctx->gb) < 16)
737                             return AVERROR_INVALIDDATA;
738                         for (k = 0; k < 4; k++)
739                             bytestream2_get_bufferu(&ctx->gb, dst + i + k * stride, 4);
740                     } else if (compr == 4 && !code) {
741                         if (bytestream2_get_bytes_left(&ctx->gb) < 1)
742                             return AVERROR_INVALIDDATA;
743                         skip_run = bytestream2_get_byteu(&ctx->gb) + 1;
744                         i -= 4;
745                     } else {
746                         int mx, my;
747 
748                         mx = c37_mv[(mvoff * 255 + code) * 2];
749                         my = c37_mv[(mvoff * 255 + code) * 2 + 1];
750                         codec37_mv(dst + i, prev + i + mx + my * stride,
751                                    ctx->height, stride, i + mx, j + my);
752                     }
753                 }
754                 dst  += stride * 4;
755                 prev += stride * 4;
756             }
757         }
758         break;
759     default:
760         avpriv_report_missing_feature(ctx->avctx,
761                                       "Subcodec 37 compression %d", compr);
762         return AVERROR_PATCHWELCOME;
763     }
764 
765     return 0;
766 }
767 
process_block(SANMVideoContext * ctx,uint8_t * dst,uint8_t * prev1,uint8_t * prev2,int stride,int tbl,int size)768 static int process_block(SANMVideoContext *ctx, uint8_t *dst, uint8_t *prev1,
769                          uint8_t *prev2, int stride, int tbl, int size)
770 {
771     int code, k, t;
772     uint8_t colors[2];
773     int8_t *pglyph;
774 
775     if (bytestream2_get_bytes_left(&ctx->gb) < 1)
776         return AVERROR_INVALIDDATA;
777 
778     code = bytestream2_get_byteu(&ctx->gb);
779     if (code >= 0xF8) {
780         switch (code) {
781         case 0xFF:
782             if (size == 2) {
783                 if (bytestream2_get_bytes_left(&ctx->gb) < 4)
784                     return AVERROR_INVALIDDATA;
785                 dst[0]          = bytestream2_get_byteu(&ctx->gb);
786                 dst[1]          = bytestream2_get_byteu(&ctx->gb);
787                 dst[0 + stride] = bytestream2_get_byteu(&ctx->gb);
788                 dst[1 + stride] = bytestream2_get_byteu(&ctx->gb);
789             } else {
790                 size >>= 1;
791                 if (process_block(ctx, dst, prev1, prev2, stride, tbl, size))
792                     return AVERROR_INVALIDDATA;
793                 if (process_block(ctx, dst + size, prev1 + size, prev2 + size,
794                                   stride, tbl, size))
795                     return AVERROR_INVALIDDATA;
796                 dst   += size * stride;
797                 prev1 += size * stride;
798                 prev2 += size * stride;
799                 if (process_block(ctx, dst, prev1, prev2, stride, tbl, size))
800                     return AVERROR_INVALIDDATA;
801                 if (process_block(ctx, dst + size, prev1 + size, prev2 + size,
802                                   stride, tbl, size))
803                     return AVERROR_INVALIDDATA;
804             }
805             break;
806         case 0xFE:
807             if (bytestream2_get_bytes_left(&ctx->gb) < 1)
808                 return AVERROR_INVALIDDATA;
809 
810             t = bytestream2_get_byteu(&ctx->gb);
811             for (k = 0; k < size; k++)
812                 memset(dst + k * stride, t, size);
813             break;
814         case 0xFD:
815             if (bytestream2_get_bytes_left(&ctx->gb) < 3)
816                 return AVERROR_INVALIDDATA;
817 
818             code = bytestream2_get_byteu(&ctx->gb);
819             pglyph = (size == 8) ? ctx->p8x8glyphs[code] : ctx->p4x4glyphs[code];
820             bytestream2_get_bufferu(&ctx->gb, colors, 2);
821 
822             for (k = 0; k < size; k++)
823                 for (t = 0; t < size; t++)
824                     dst[t + k * stride] = colors[!*pglyph++];
825             break;
826         case 0xFC:
827             for (k = 0; k < size; k++)
828                 memcpy(dst + k * stride, prev1 + k * stride, size);
829             break;
830         default:
831             k = bytestream2_tell(&ctx->gb);
832             bytestream2_seek(&ctx->gb, tbl + (code & 7), SEEK_SET);
833             t = bytestream2_get_byte(&ctx->gb);
834             bytestream2_seek(&ctx->gb, k, SEEK_SET);
835             for (k = 0; k < size; k++)
836                 memset(dst + k * stride, t, size);
837         }
838     } else {
839         int mx = motion_vectors[code][0];
840         int my = motion_vectors[code][1];
841         int index = prev2 - (const uint8_t *)ctx->frm2;
842 
843         av_assert2(index >= 0 && index < (ctx->buf_size >> 1));
844 
845         if (index < -mx - my * stride ||
846             (ctx->buf_size >> 1) - index < mx + size + (my + size - 1) * stride) {
847             av_log(ctx->avctx, AV_LOG_ERROR, "MV is invalid.\n");
848             return AVERROR_INVALIDDATA;
849         }
850 
851         for (k = 0; k < size; k++)
852             memcpy(dst + k * stride, prev2 + mx + (my + k) * stride, size);
853     }
854 
855     return 0;
856 }
857 
old_codec47(SANMVideoContext * ctx,int top,int left,int width,int height)858 static int old_codec47(SANMVideoContext *ctx, int top,
859                        int left, int width, int height)
860 {
861     uint32_t decoded_size;
862     int i, j;
863     int stride     = ctx->pitch;
864     uint8_t *dst   = (uint8_t *)ctx->frm0 + left + top * stride;
865     uint8_t *prev1 = (uint8_t *)ctx->frm1;
866     uint8_t *prev2 = (uint8_t *)ctx->frm2;
867     int tbl_pos = bytestream2_tell(&ctx->gb);
868     int seq     = bytestream2_get_le16(&ctx->gb);
869     int compr   = bytestream2_get_byte(&ctx->gb);
870     int new_rot = bytestream2_get_byte(&ctx->gb);
871     int skip    = bytestream2_get_byte(&ctx->gb);
872 
873     bytestream2_skip(&ctx->gb, 9);
874     decoded_size = bytestream2_get_le32(&ctx->gb);
875     bytestream2_skip(&ctx->gb, 8);
876 
877     if (decoded_size > ctx->height * stride - left - top * stride) {
878         decoded_size = ctx->height * stride - left - top * stride;
879         av_log(ctx->avctx, AV_LOG_WARNING, "Decoded size is too large.\n");
880     }
881 
882     if (skip & 1)
883         bytestream2_skip(&ctx->gb, 0x8080);
884     if (!seq) {
885         ctx->prev_seq = -1;
886         memset(prev1, 0, ctx->height * stride);
887         memset(prev2, 0, ctx->height * stride);
888     }
889 
890     switch (compr) {
891     case 0:
892         if (bytestream2_get_bytes_left(&ctx->gb) < width * height)
893             return AVERROR_INVALIDDATA;
894         for (j = 0; j < height; j++) {
895             bytestream2_get_bufferu(&ctx->gb, dst, width);
896             dst += stride;
897         }
898         break;
899     case 1:
900         if (bytestream2_get_bytes_left(&ctx->gb) < ((width + 1) >> 1) * ((height + 1) >> 1))
901             return AVERROR_INVALIDDATA;
902         for (j = 0; j < height; j += 2) {
903             for (i = 0; i < width; i += 2) {
904                 dst[i] =
905                 dst[i + 1] =
906                 dst[stride + i] =
907                 dst[stride + i + 1] = bytestream2_get_byteu(&ctx->gb);
908             }
909             dst += stride * 2;
910         }
911         break;
912     case 2:
913         if (seq == ctx->prev_seq + 1) {
914             for (j = 0; j < height; j += 8) {
915                 for (i = 0; i < width; i += 8)
916                     if (process_block(ctx, dst + i, prev1 + i, prev2 + i, stride,
917                                       tbl_pos + 8, 8))
918                         return AVERROR_INVALIDDATA;
919                 dst   += stride * 8;
920                 prev1 += stride * 8;
921                 prev2 += stride * 8;
922             }
923         }
924         break;
925     case 3:
926         memcpy(ctx->frm0, ctx->frm2, ctx->pitch * ctx->height);
927         break;
928     case 4:
929         memcpy(ctx->frm0, ctx->frm1, ctx->pitch * ctx->height);
930         break;
931     case 5:
932         if (rle_decode(ctx, dst, decoded_size))
933             return AVERROR_INVALIDDATA;
934         break;
935     default:
936         avpriv_report_missing_feature(ctx->avctx,
937                                       "Subcodec 47 compression %d", compr);
938         return AVERROR_PATCHWELCOME;
939     }
940     if (seq == ctx->prev_seq + 1)
941         ctx->rotate_code = new_rot;
942     else
943         ctx->rotate_code = 0;
944     ctx->prev_seq = seq;
945 
946     return 0;
947 }
948 
process_frame_obj(SANMVideoContext * ctx)949 static int process_frame_obj(SANMVideoContext *ctx)
950 {
951     uint16_t codec = bytestream2_get_le16u(&ctx->gb);
952     uint16_t left  = bytestream2_get_le16u(&ctx->gb);
953     uint16_t top   = bytestream2_get_le16u(&ctx->gb);
954     uint16_t w     = bytestream2_get_le16u(&ctx->gb);
955     uint16_t h     = bytestream2_get_le16u(&ctx->gb);
956 
957     if (!w || !h) {
958         av_log(ctx->avctx, AV_LOG_ERROR, "Dimensions are invalid.\n");
959         return AVERROR_INVALIDDATA;
960     }
961 
962     if (ctx->width < left + w || ctx->height < top + h) {
963         int ret = ff_set_dimensions(ctx->avctx, FFMAX(left + w, ctx->width),
964                                     FFMAX(top + h, ctx->height));
965         if (ret < 0)
966             return ret;
967         init_sizes(ctx, FFMAX(left + w, ctx->width),
968                    FFMAX(top + h, ctx->height));
969         if (init_buffers(ctx)) {
970             av_log(ctx->avctx, AV_LOG_ERROR, "Error resizing buffers.\n");
971             return AVERROR(ENOMEM);
972         }
973     }
974     bytestream2_skip(&ctx->gb, 4);
975 
976     switch (codec) {
977     case 1:
978     case 3:
979         return old_codec1(ctx, top, left, w, h);
980         break;
981     case 37:
982         return old_codec37(ctx, top, left, w, h);
983         break;
984     case 47:
985         return old_codec47(ctx, top, left, w, h);
986         break;
987     default:
988         avpriv_request_sample(ctx->avctx, "Subcodec %d", codec);
989         return AVERROR_PATCHWELCOME;
990     }
991 }
992 
decode_0(SANMVideoContext * ctx)993 static int decode_0(SANMVideoContext *ctx)
994 {
995     uint16_t *frm = ctx->frm0;
996     int x, y;
997 
998     if (bytestream2_get_bytes_left(&ctx->gb) < ctx->width * ctx->height * 2) {
999         av_log(ctx->avctx, AV_LOG_ERROR, "Insufficient data for raw frame.\n");
1000         return AVERROR_INVALIDDATA;
1001     }
1002     for (y = 0; y < ctx->height; y++) {
1003         for (x = 0; x < ctx->width; x++)
1004             frm[x] = bytestream2_get_le16u(&ctx->gb);
1005         frm += ctx->pitch;
1006     }
1007     return 0;
1008 }
1009 
decode_nop(SANMVideoContext * ctx)1010 static int decode_nop(SANMVideoContext *ctx)
1011 {
1012     avpriv_request_sample(ctx->avctx, "Unknown/unsupported compression type");
1013     return AVERROR_PATCHWELCOME;
1014 }
1015 
copy_block(uint16_t * pdest,uint16_t * psrc,int block_size,int pitch)1016 static void copy_block(uint16_t *pdest, uint16_t *psrc, int block_size, int pitch)
1017 {
1018     uint8_t *dst = (uint8_t *)pdest;
1019     uint8_t *src = (uint8_t *)psrc;
1020     int stride = pitch * 2;
1021 
1022     switch (block_size) {
1023     case 2:
1024         copy_block4(dst, src, stride, stride, 2);
1025         break;
1026     case 4:
1027         copy_block8(dst, src, stride, stride, 4);
1028         break;
1029     case 8:
1030         copy_block16(dst, src, stride, stride, 8);
1031         break;
1032     }
1033 }
1034 
fill_block(uint16_t * pdest,uint16_t color,int block_size,int pitch)1035 static void fill_block(uint16_t *pdest, uint16_t color, int block_size, int pitch)
1036 {
1037     int x, y;
1038 
1039     pitch -= block_size;
1040     for (y = 0; y < block_size; y++, pdest += pitch)
1041         for (x = 0; x < block_size; x++)
1042             *pdest++ = color;
1043 }
1044 
draw_glyph(SANMVideoContext * ctx,uint16_t * dst,int index,uint16_t fg_color,uint16_t bg_color,int block_size,int pitch)1045 static int draw_glyph(SANMVideoContext *ctx, uint16_t *dst, int index,
1046                       uint16_t fg_color, uint16_t bg_color, int block_size,
1047                       int pitch)
1048 {
1049     int8_t *pglyph;
1050     uint16_t colors[2] = { fg_color, bg_color };
1051     int x, y;
1052 
1053     if (index >= NGLYPHS) {
1054         av_log(ctx->avctx, AV_LOG_ERROR, "Ignoring nonexistent glyph #%u.\n", index);
1055         return AVERROR_INVALIDDATA;
1056     }
1057 
1058     pglyph = block_size == 8 ? ctx->p8x8glyphs[index] : ctx->p4x4glyphs[index];
1059     pitch -= block_size;
1060 
1061     for (y = 0; y < block_size; y++, dst += pitch)
1062         for (x = 0; x < block_size; x++)
1063             *dst++ = colors[*pglyph++];
1064     return 0;
1065 }
1066 
opcode_0xf7(SANMVideoContext * ctx,int cx,int cy,int block_size,int pitch)1067 static int opcode_0xf7(SANMVideoContext *ctx, int cx, int cy, int block_size, int pitch)
1068 {
1069     uint16_t *dst = ctx->frm0 + cx + cy * ctx->pitch;
1070 
1071     if (block_size == 2) {
1072         uint32_t indices;
1073 
1074         if (bytestream2_get_bytes_left(&ctx->gb) < 4)
1075             return AVERROR_INVALIDDATA;
1076 
1077         indices        = bytestream2_get_le32u(&ctx->gb);
1078         dst[0]         = ctx->codebook[indices & 0xFF];
1079         indices      >>= 8;
1080         dst[1]         = ctx->codebook[indices & 0xFF];
1081         indices      >>= 8;
1082         dst[pitch]     = ctx->codebook[indices & 0xFF];
1083         indices      >>= 8;
1084         dst[pitch + 1] = ctx->codebook[indices & 0xFF];
1085     } else {
1086         uint16_t fgcolor, bgcolor;
1087         int glyph;
1088 
1089         if (bytestream2_get_bytes_left(&ctx->gb) < 3)
1090             return AVERROR_INVALIDDATA;
1091 
1092         glyph   = bytestream2_get_byteu(&ctx->gb);
1093         bgcolor = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
1094         fgcolor = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
1095 
1096         draw_glyph(ctx, dst, glyph, fgcolor, bgcolor, block_size, pitch);
1097     }
1098     return 0;
1099 }
1100 
opcode_0xf8(SANMVideoContext * ctx,int cx,int cy,int block_size,int pitch)1101 static int opcode_0xf8(SANMVideoContext *ctx, int cx, int cy, int block_size, int pitch)
1102 {
1103     uint16_t *dst = ctx->frm0 + cx + cy * ctx->pitch;
1104 
1105     if (block_size == 2) {
1106         if (bytestream2_get_bytes_left(&ctx->gb) < 8)
1107             return AVERROR_INVALIDDATA;
1108 
1109         dst[0]         = bytestream2_get_le16u(&ctx->gb);
1110         dst[1]         = bytestream2_get_le16u(&ctx->gb);
1111         dst[pitch]     = bytestream2_get_le16u(&ctx->gb);
1112         dst[pitch + 1] = bytestream2_get_le16u(&ctx->gb);
1113     } else {
1114         uint16_t fgcolor, bgcolor;
1115         int glyph;
1116 
1117         if (bytestream2_get_bytes_left(&ctx->gb) < 5)
1118             return AVERROR_INVALIDDATA;
1119 
1120         glyph   = bytestream2_get_byteu(&ctx->gb);
1121         bgcolor = bytestream2_get_le16u(&ctx->gb);
1122         fgcolor = bytestream2_get_le16u(&ctx->gb);
1123 
1124         draw_glyph(ctx, dst, glyph, fgcolor, bgcolor, block_size, pitch);
1125     }
1126     return 0;
1127 }
1128 
good_mvec(SANMVideoContext * ctx,int cx,int cy,int mx,int my,int block_size)1129 static int good_mvec(SANMVideoContext *ctx, int cx, int cy, int mx, int my,
1130                      int block_size)
1131 {
1132     int start_pos = cx + mx + (cy + my) * ctx->pitch;
1133     int end_pos = start_pos + (block_size - 1) * (ctx->pitch + 1);
1134 
1135     int good = start_pos >= 0 && end_pos < (ctx->buf_size >> 1);
1136 
1137     if (!good)
1138         av_log(ctx->avctx, AV_LOG_ERROR,
1139                "Ignoring invalid motion vector (%i, %i)->(%u, %u), block size = %u\n",
1140                cx + mx, cy + my, cx, cy, block_size);
1141 
1142     return good;
1143 }
1144 
codec2subblock(SANMVideoContext * ctx,int cx,int cy,int blk_size)1145 static int codec2subblock(SANMVideoContext *ctx, int cx, int cy, int blk_size)
1146 {
1147     int16_t mx, my, index;
1148     int opcode;
1149 
1150     if (bytestream2_get_bytes_left(&ctx->gb) < 1)
1151         return AVERROR_INVALIDDATA;
1152 
1153     opcode = bytestream2_get_byteu(&ctx->gb);
1154 
1155     switch (opcode) {
1156     default:
1157         mx = motion_vectors[opcode][0];
1158         my = motion_vectors[opcode][1];
1159 
1160         if (good_mvec(ctx, cx, cy, mx, my, blk_size)) {
1161             copy_block(ctx->frm0 + cx      + ctx->pitch *  cy,
1162                        ctx->frm2 + cx + mx + ctx->pitch * (cy + my),
1163                        blk_size, ctx->pitch);
1164         }
1165         break;
1166     case 0xF5:
1167         if (bytestream2_get_bytes_left(&ctx->gb) < 2)
1168             return AVERROR_INVALIDDATA;
1169         index = bytestream2_get_le16u(&ctx->gb);
1170 
1171         mx = index % ctx->width;
1172         my = index / ctx->width;
1173 
1174         if (good_mvec(ctx, cx, cy, mx, my, blk_size)) {
1175             copy_block(ctx->frm0 + cx      + ctx->pitch *  cy,
1176                        ctx->frm2 + cx + mx + ctx->pitch * (cy + my),
1177                        blk_size, ctx->pitch);
1178         }
1179         break;
1180     case 0xF6:
1181         copy_block(ctx->frm0 + cx + ctx->pitch * cy,
1182                    ctx->frm1 + cx + ctx->pitch * cy,
1183                    blk_size, ctx->pitch);
1184         break;
1185     case 0xF7:
1186         opcode_0xf7(ctx, cx, cy, blk_size, ctx->pitch);
1187         break;
1188 
1189     case 0xF8:
1190         opcode_0xf8(ctx, cx, cy, blk_size, ctx->pitch);
1191         break;
1192     case 0xF9:
1193     case 0xFA:
1194     case 0xFB:
1195     case 0xFC:
1196         fill_block(ctx->frm0 + cx + cy * ctx->pitch,
1197                    ctx->small_codebook[opcode - 0xf9], blk_size, ctx->pitch);
1198         break;
1199     case 0xFD:
1200         if (bytestream2_get_bytes_left(&ctx->gb) < 1)
1201             return AVERROR_INVALIDDATA;
1202         fill_block(ctx->frm0 + cx + cy * ctx->pitch,
1203                    ctx->codebook[bytestream2_get_byteu(&ctx->gb)], blk_size, ctx->pitch);
1204         break;
1205     case 0xFE:
1206         if (bytestream2_get_bytes_left(&ctx->gb) < 2)
1207             return AVERROR_INVALIDDATA;
1208         fill_block(ctx->frm0 + cx + cy * ctx->pitch,
1209                    bytestream2_get_le16u(&ctx->gb), blk_size, ctx->pitch);
1210         break;
1211     case 0xFF:
1212         if (blk_size == 2) {
1213             opcode_0xf8(ctx, cx, cy, blk_size, ctx->pitch);
1214         } else {
1215             blk_size >>= 1;
1216             if (codec2subblock(ctx, cx, cy, blk_size))
1217                 return AVERROR_INVALIDDATA;
1218             if (codec2subblock(ctx, cx + blk_size, cy, blk_size))
1219                 return AVERROR_INVALIDDATA;
1220             if (codec2subblock(ctx, cx, cy + blk_size, blk_size))
1221                 return AVERROR_INVALIDDATA;
1222             if (codec2subblock(ctx, cx + blk_size, cy + blk_size, blk_size))
1223                 return AVERROR_INVALIDDATA;
1224         }
1225         break;
1226     }
1227     return 0;
1228 }
1229 
decode_2(SANMVideoContext * ctx)1230 static int decode_2(SANMVideoContext *ctx)
1231 {
1232     int cx, cy, ret;
1233 
1234     for (cy = 0; cy < ctx->aligned_height; cy += 8)
1235         for (cx = 0; cx < ctx->aligned_width; cx += 8)
1236             if (ret = codec2subblock(ctx, cx, cy, 8))
1237                 return ret;
1238 
1239     return 0;
1240 }
1241 
decode_3(SANMVideoContext * ctx)1242 static int decode_3(SANMVideoContext *ctx)
1243 {
1244     memcpy(ctx->frm0, ctx->frm2, ctx->frm2_size);
1245     return 0;
1246 }
1247 
decode_4(SANMVideoContext * ctx)1248 static int decode_4(SANMVideoContext *ctx)
1249 {
1250     memcpy(ctx->frm0, ctx->frm1, ctx->frm1_size);
1251     return 0;
1252 }
1253 
decode_5(SANMVideoContext * ctx)1254 static int decode_5(SANMVideoContext *ctx)
1255 {
1256 #if HAVE_BIGENDIAN
1257     uint16_t *frm;
1258     int npixels;
1259 #endif
1260     uint8_t *dst = (uint8_t*)ctx->frm0;
1261 
1262     if (rle_decode(ctx, dst, ctx->buf_size))
1263         return AVERROR_INVALIDDATA;
1264 
1265 #if HAVE_BIGENDIAN
1266     npixels = ctx->npixels;
1267     frm = ctx->frm0;
1268     while (npixels--) {
1269         *frm = av_bswap16(*frm);
1270         frm++;
1271     }
1272 #endif
1273 
1274     return 0;
1275 }
1276 
decode_6(SANMVideoContext * ctx)1277 static int decode_6(SANMVideoContext *ctx)
1278 {
1279     int npixels = ctx->npixels;
1280     uint16_t *frm = ctx->frm0;
1281 
1282     if (bytestream2_get_bytes_left(&ctx->gb) < npixels) {
1283         av_log(ctx->avctx, AV_LOG_ERROR, "Insufficient data for frame.\n");
1284         return AVERROR_INVALIDDATA;
1285     }
1286     while (npixels--)
1287         *frm++ = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
1288 
1289     return 0;
1290 }
1291 
decode_8(SANMVideoContext * ctx)1292 static int decode_8(SANMVideoContext *ctx)
1293 {
1294     uint16_t *pdest = ctx->frm0;
1295     uint8_t *rsrc;
1296     long npixels = ctx->npixels;
1297 
1298     av_fast_malloc(&ctx->rle_buf, &ctx->rle_buf_size, npixels);
1299     if (!ctx->rle_buf) {
1300         av_log(ctx->avctx, AV_LOG_ERROR, "RLE buffer allocation failed.\n");
1301         return AVERROR(ENOMEM);
1302     }
1303     rsrc = ctx->rle_buf;
1304 
1305     if (rle_decode(ctx, rsrc, npixels))
1306         return AVERROR_INVALIDDATA;
1307 
1308     while (npixels--)
1309         *pdest++ = ctx->codebook[*rsrc++];
1310 
1311     return 0;
1312 }
1313 
1314 typedef int (*frm_decoder)(SANMVideoContext *ctx);
1315 
1316 static const frm_decoder v1_decoders[] = {
1317     decode_0, decode_nop, decode_2, decode_3, decode_4, decode_5,
1318     decode_6, decode_nop, decode_8
1319 };
1320 
read_frame_header(SANMVideoContext * ctx,SANMFrameHeader * hdr)1321 static int read_frame_header(SANMVideoContext *ctx, SANMFrameHeader *hdr)
1322 {
1323     int i, ret;
1324 
1325     if ((ret = bytestream2_get_bytes_left(&ctx->gb)) < 560) {
1326         av_log(ctx->avctx, AV_LOG_ERROR, "Input frame too short (%d bytes).\n",
1327                ret);
1328         return AVERROR_INVALIDDATA;
1329     }
1330     bytestream2_skip(&ctx->gb, 8); // skip pad
1331 
1332     hdr->width  = bytestream2_get_le32u(&ctx->gb);
1333     hdr->height = bytestream2_get_le32u(&ctx->gb);
1334 
1335     if (hdr->width != ctx->width || hdr->height != ctx->height) {
1336         avpriv_report_missing_feature(ctx->avctx, "Variable size frames");
1337         return AVERROR_PATCHWELCOME;
1338     }
1339 
1340     hdr->seq_num     = bytestream2_get_le16u(&ctx->gb);
1341     hdr->codec       = bytestream2_get_byteu(&ctx->gb);
1342     hdr->rotate_code = bytestream2_get_byteu(&ctx->gb);
1343 
1344     bytestream2_skip(&ctx->gb, 4); // skip pad
1345 
1346     for (i = 0; i < 4; i++)
1347         ctx->small_codebook[i] = bytestream2_get_le16u(&ctx->gb);
1348     hdr->bg_color = bytestream2_get_le16u(&ctx->gb);
1349 
1350     bytestream2_skip(&ctx->gb, 2); // skip pad
1351 
1352     hdr->rle_output_size = bytestream2_get_le32u(&ctx->gb);
1353     for (i = 0; i < 256; i++)
1354         ctx->codebook[i] = bytestream2_get_le16u(&ctx->gb);
1355 
1356     bytestream2_skip(&ctx->gb, 8); // skip pad
1357 
1358     return 0;
1359 }
1360 
fill_frame(uint16_t * pbuf,int buf_size,uint16_t color)1361 static void fill_frame(uint16_t *pbuf, int buf_size, uint16_t color)
1362 {
1363     while (buf_size--)
1364         *pbuf++ = color;
1365 }
1366 
copy_output(SANMVideoContext * ctx,SANMFrameHeader * hdr)1367 static int copy_output(SANMVideoContext *ctx, SANMFrameHeader *hdr)
1368 {
1369     uint8_t *dst;
1370     const uint8_t *src = (uint8_t*) ctx->frm0;
1371     int ret, dstpitch, height = ctx->height;
1372     int srcpitch = ctx->pitch * (hdr ? sizeof(ctx->frm0[0]) : 1);
1373 
1374     if ((ret = ff_get_buffer(ctx->avctx, ctx->frame, 0)) < 0)
1375         return ret;
1376 
1377     dst      = ctx->frame->data[0];
1378     dstpitch = ctx->frame->linesize[0];
1379 
1380     while (height--) {
1381         memcpy(dst, src, srcpitch);
1382         src += srcpitch;
1383         dst += dstpitch;
1384     }
1385 
1386     return 0;
1387 }
1388 
decode_frame(AVCodecContext * avctx,void * data,int * got_frame_ptr,AVPacket * pkt)1389 static int decode_frame(AVCodecContext *avctx, void *data,
1390                         int *got_frame_ptr, AVPacket *pkt)
1391 {
1392     SANMVideoContext *ctx = avctx->priv_data;
1393     int i, ret;
1394 
1395     ctx->frame = data;
1396     bytestream2_init(&ctx->gb, pkt->data, pkt->size);
1397 
1398     if (!ctx->version) {
1399         int to_store = 0;
1400 
1401         while (bytestream2_get_bytes_left(&ctx->gb) >= 8) {
1402             uint32_t sig, size;
1403             int pos;
1404 
1405             sig  = bytestream2_get_be32u(&ctx->gb);
1406             size = bytestream2_get_be32u(&ctx->gb);
1407             pos  = bytestream2_tell(&ctx->gb);
1408 
1409             if (bytestream2_get_bytes_left(&ctx->gb) < size) {
1410                 av_log(avctx, AV_LOG_ERROR, "Incorrect chunk size %"PRIu32".\n", size);
1411                 break;
1412             }
1413             switch (sig) {
1414             case MKBETAG('N', 'P', 'A', 'L'):
1415                 if (size != PALETTE_SIZE * 3) {
1416                     av_log(avctx, AV_LOG_ERROR,
1417                            "Incorrect palette block size %"PRIu32".\n", size);
1418                     return AVERROR_INVALIDDATA;
1419                 }
1420                 for (i = 0; i < PALETTE_SIZE; i++)
1421                     ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb);
1422                 break;
1423             case MKBETAG('F', 'O', 'B', 'J'):
1424                 if (size < 16)
1425                     return AVERROR_INVALIDDATA;
1426                 if (ret = process_frame_obj(ctx))
1427                     return ret;
1428                 break;
1429             case MKBETAG('X', 'P', 'A', 'L'):
1430                 if (size == 6 || size == 4) {
1431                     uint8_t tmp[3];
1432                     int j;
1433 
1434                     for (i = 0; i < PALETTE_SIZE; i++) {
1435                         for (j = 0; j < 3; j++) {
1436                             int t = (ctx->pal[i] >> (16 - j * 8)) & 0xFF;
1437                             tmp[j] = av_clip_uint8((t * 129 + ctx->delta_pal[i * 3 + j]) >> 7);
1438                         }
1439                         ctx->pal[i] = 0xFFU << 24 | AV_RB24(tmp);
1440                     }
1441                 } else {
1442                     if (size < PALETTE_DELTA * 2 + 4) {
1443                         av_log(avctx, AV_LOG_ERROR,
1444                                "Incorrect palette change block size %"PRIu32".\n",
1445                                size);
1446                         return AVERROR_INVALIDDATA;
1447                     }
1448                     bytestream2_skipu(&ctx->gb, 4);
1449                     for (i = 0; i < PALETTE_DELTA; i++)
1450                         ctx->delta_pal[i] = bytestream2_get_le16u(&ctx->gb);
1451                     if (size >= PALETTE_DELTA * 5 + 4) {
1452                         for (i = 0; i < PALETTE_SIZE; i++)
1453                             ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb);
1454                     } else {
1455                         memset(ctx->pal, 0, sizeof(ctx->pal));
1456                     }
1457                 }
1458                 break;
1459             case MKBETAG('S', 'T', 'O', 'R'):
1460                 to_store = 1;
1461                 break;
1462             case MKBETAG('F', 'T', 'C', 'H'):
1463                 memcpy(ctx->frm0, ctx->stored_frame, ctx->buf_size);
1464                 break;
1465             default:
1466                 bytestream2_skip(&ctx->gb, size);
1467                 av_log(avctx, AV_LOG_DEBUG,
1468                        "Unknown/unsupported chunk %"PRIx32".\n", sig);
1469                 break;
1470             }
1471 
1472             bytestream2_seek(&ctx->gb, pos + size, SEEK_SET);
1473             if (size & 1)
1474                 bytestream2_skip(&ctx->gb, 1);
1475         }
1476         if (to_store)
1477             memcpy(ctx->stored_frame, ctx->frm0, ctx->buf_size);
1478         if ((ret = copy_output(ctx, NULL)))
1479             return ret;
1480         memcpy(ctx->frame->data[1], ctx->pal, 1024);
1481     } else {
1482         SANMFrameHeader header;
1483 
1484         if ((ret = read_frame_header(ctx, &header)))
1485             return ret;
1486 
1487         ctx->rotate_code = header.rotate_code;
1488         if ((ctx->frame->key_frame = !header.seq_num)) {
1489             ctx->frame->pict_type = AV_PICTURE_TYPE_I;
1490             fill_frame(ctx->frm1, ctx->npixels, header.bg_color);
1491             fill_frame(ctx->frm2, ctx->npixels, header.bg_color);
1492         } else {
1493             ctx->frame->pict_type = AV_PICTURE_TYPE_P;
1494         }
1495 
1496         if (header.codec < FF_ARRAY_ELEMS(v1_decoders)) {
1497             if ((ret = v1_decoders[header.codec](ctx))) {
1498                 av_log(avctx, AV_LOG_ERROR,
1499                        "Subcodec %d: error decoding frame.\n", header.codec);
1500                 return ret;
1501             }
1502         } else {
1503             avpriv_request_sample(avctx, "Subcodec %d", header.codec);
1504             return AVERROR_PATCHWELCOME;
1505         }
1506 
1507         if ((ret = copy_output(ctx, &header)))
1508             return ret;
1509     }
1510     if (ctx->rotate_code)
1511         rotate_bufs(ctx, ctx->rotate_code);
1512 
1513     *got_frame_ptr = 1;
1514 
1515     return pkt->size;
1516 }
1517 
1518 AVCodec ff_sanm_decoder = {
1519 	.name           = "sanm",
1520     .long_name      = NULL_IF_CONFIG_SMALL("LucasArts SANM/Smush video"),
1521     .type           = AVMEDIA_TYPE_VIDEO,
1522     .id             = AV_CODEC_ID_SANM,
1523     .priv_data_size = sizeof(SANMVideoContext),
1524     .init           = decode_init,
1525     .close          = decode_end,
1526     .decode         = decode_frame,
1527     .capabilities   = CODEC_CAP_DR1,
1528 };
1529