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  */
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     init_sizes(ctx, 0, 0);
461 }
462 
init_buffers(SANMVideoContext * ctx)463 static av_cold int init_buffers(SANMVideoContext *ctx)
464 {
465     av_fast_padded_mallocz(&ctx->frm0, &ctx->frm0_size, ctx->buf_size);
466     av_fast_padded_mallocz(&ctx->frm1, &ctx->frm1_size, ctx->buf_size);
467     av_fast_padded_mallocz(&ctx->frm2, &ctx->frm2_size, ctx->buf_size);
468     if (!ctx->version)
469         av_fast_padded_mallocz(&ctx->stored_frame,
470                               &ctx->stored_frame_size, ctx->buf_size);
471 
472     if (!ctx->frm0 || !ctx->frm1 || !ctx->frm2 ||
473         (!ctx->stored_frame && !ctx->version)) {
474         destroy_buffers(ctx);
475         return AVERROR(ENOMEM);
476     }
477 
478     return 0;
479 }
480 
rotate_bufs(SANMVideoContext * ctx,int rotate_code)481 static void rotate_bufs(SANMVideoContext *ctx, int rotate_code)
482 {
483     if (rotate_code == 2)
484         FFSWAP(uint16_t*, ctx->frm1, ctx->frm2);
485     FFSWAP(uint16_t*, ctx->frm2, ctx->frm0);
486 }
487 
decode_init(AVCodecContext * avctx)488 static av_cold int decode_init(AVCodecContext *avctx)
489 {
490     SANMVideoContext *ctx = avctx->priv_data;
491 
492     ctx->avctx   = avctx;
493     ctx->version = !avctx->extradata_size;
494     // early sanity check before allocations to avoid need for deallocation code.
495     if (!ctx->version && avctx->extradata_size < 1026) {
496         av_log(avctx, AV_LOG_ERROR, "Not enough extradata.\n");
497         return AVERROR_INVALIDDATA;
498     }
499 
500     avctx->pix_fmt = ctx->version ? AV_PIX_FMT_RGB565 : AV_PIX_FMT_PAL8;
501 
502     init_sizes(ctx, avctx->width, avctx->height);
503     if (init_buffers(ctx)) {
504         av_log(avctx, AV_LOG_ERROR, "Error allocating buffers.\n");
505         return AVERROR(ENOMEM);
506     }
507 
508     make_glyphs(ctx->p4x4glyphs[0], glyph4_x, glyph4_y, 4);
509     make_glyphs(ctx->p8x8glyphs[0], glyph8_x, glyph8_y, 8);
510 
511     if (!ctx->version) {
512         int i;
513 
514         ctx->subversion = AV_RL16(avctx->extradata);
515         for (i = 0; i < PALETTE_SIZE; i++)
516             ctx->pal[i] = 0xFFU << 24 | AV_RL32(avctx->extradata + 2 + i * 4);
517     }
518 
519     return 0;
520 }
521 
decode_end(AVCodecContext * avctx)522 static av_cold int decode_end(AVCodecContext *avctx)
523 {
524     SANMVideoContext *ctx = avctx->priv_data;
525 
526     destroy_buffers(ctx);
527 
528     return 0;
529 }
530 
rle_decode(SANMVideoContext * ctx,uint8_t * dst,const int out_size)531 static int rle_decode(SANMVideoContext *ctx, uint8_t *dst, const int out_size)
532 {
533     int opcode, color, run_len, left = out_size;
534 
535     while (left > 0) {
536         opcode = bytestream2_get_byte(&ctx->gb);
537         run_len = (opcode >> 1) + 1;
538         if (run_len > left || bytestream2_get_bytes_left(&ctx->gb) <= 0)
539             return AVERROR_INVALIDDATA;
540 
541         if (opcode & 1) {
542             color = bytestream2_get_byte(&ctx->gb);
543             memset(dst, color, run_len);
544         } else {
545             if (bytestream2_get_bytes_left(&ctx->gb) < run_len)
546                 return AVERROR_INVALIDDATA;
547             bytestream2_get_bufferu(&ctx->gb, dst, run_len);
548         }
549 
550         dst  += run_len;
551         left -= run_len;
552     }
553 
554     return 0;
555 }
556 
old_codec1(SANMVideoContext * ctx,int top,int left,int width,int height)557 static int old_codec1(SANMVideoContext *ctx, int top,
558                       int left, int width, int height)
559 {
560     uint8_t *dst = ((uint8_t *)ctx->frm0) + left + top * ctx->pitch;
561     int i, j, len, flag, code, val, pos, end;
562 
563     for (i = 0; i < height; i++) {
564         pos = 0;
565 
566         if (bytestream2_get_bytes_left(&ctx->gb) < 2)
567             return AVERROR_INVALIDDATA;
568 
569         len = bytestream2_get_le16u(&ctx->gb);
570         end = bytestream2_tell(&ctx->gb) + len;
571 
572         while (bytestream2_tell(&ctx->gb) < end) {
573             if (bytestream2_get_bytes_left(&ctx->gb) < 2)
574                 return AVERROR_INVALIDDATA;
575 
576             code = bytestream2_get_byteu(&ctx->gb);
577             flag = code & 1;
578             code = (code >> 1) + 1;
579             if (pos + code > width)
580                 return AVERROR_INVALIDDATA;
581             if (flag) {
582                 val = bytestream2_get_byteu(&ctx->gb);
583                 if (val)
584                     memset(dst + pos, val, code);
585                 pos += code;
586             } else {
587                 if (bytestream2_get_bytes_left(&ctx->gb) < code)
588                     return AVERROR_INVALIDDATA;
589                 for (j = 0; j < code; j++) {
590                     val = bytestream2_get_byteu(&ctx->gb);
591                     if (val)
592                         dst[pos] = val;
593                     pos++;
594                 }
595             }
596         }
597         dst += ctx->pitch;
598     }
599     ctx->rotate_code = 0;
600 
601     return 0;
602 }
603 
codec37_mv(uint8_t * dst,const uint8_t * src,int height,int stride,int x,int y)604 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     pos = x + y * stride;
610     for (j = 0; j < 4; j++) {
611         for (i = 0; i < 4; i++) {
612             if ((pos + i) < 0 || (pos + i) >= height * stride)
613                 dst[i] = 0;
614             else
615                 dst[i] = src[i];
616         }
617         dst += stride;
618         src += stride;
619         pos += stride;
620     }
621 }
622 
old_codec37(SANMVideoContext * ctx,int top,int left,int width,int height)623 static int old_codec37(SANMVideoContext *ctx, int top,
624                        int left, int width, int height)
625 {
626     ptrdiff_t stride = ctx->pitch;
627     int i, j, k, t;
628     uint8_t *dst, *prev;
629     int skip_run = 0;
630     int compr = bytestream2_get_byte(&ctx->gb);
631     int mvoff = bytestream2_get_byte(&ctx->gb);
632     int seq   = bytestream2_get_le16(&ctx->gb);
633     uint32_t decoded_size = bytestream2_get_le32(&ctx->gb);
634     int flags;
635 
636     bytestream2_skip(&ctx->gb, 4);
637     flags = bytestream2_get_byte(&ctx->gb);
638     bytestream2_skip(&ctx->gb, 3);
639 
640     if (decoded_size > ctx->height * stride - left - top * stride) {
641         decoded_size = ctx->height * stride - left - top * stride;
642         av_log(ctx->avctx, AV_LOG_WARNING, "Decoded size is too large.\n");
643     }
644 
645     ctx->rotate_code = 0;
646 
647     if (((seq & 1) || !(flags & 1)) && (compr && compr != 2))
648         rotate_bufs(ctx, 1);
649 
650     dst  = ((uint8_t*)ctx->frm0) + left + top * stride;
651     prev = ((uint8_t*)ctx->frm2) + left + top * stride;
652 
653     if (mvoff > 2) {
654         av_log(ctx->avctx, AV_LOG_ERROR, "Invalid motion base value %d.\n", mvoff);
655         return AVERROR_INVALIDDATA;
656     }
657 
658     switch (compr) {
659     case 0:
660         for (i = 0; i < height; i++) {
661             bytestream2_get_buffer(&ctx->gb, dst, width);
662             dst += stride;
663         }
664         memset(ctx->frm1, 0, ctx->height * stride);
665         memset(ctx->frm2, 0, ctx->height * stride);
666         break;
667     case 2:
668         if (rle_decode(ctx, dst, decoded_size))
669             return AVERROR_INVALIDDATA;
670         memset(ctx->frm1, 0, ctx->frm1_size);
671         memset(ctx->frm2, 0, ctx->frm2_size);
672         break;
673     case 3:
674     case 4:
675         if (flags & 4) {
676             for (j = 0; j < height; j += 4) {
677                 for (i = 0; i < width; i += 4) {
678                     int code;
679                     if (skip_run) {
680                         skip_run--;
681                         copy_block4(dst + i, prev + i, stride, stride, 4);
682                         continue;
683                     }
684                     if (bytestream2_get_bytes_left(&ctx->gb) < 1)
685                         return AVERROR_INVALIDDATA;
686                     code = bytestream2_get_byteu(&ctx->gb);
687                     switch (code) {
688                     case 0xFF:
689                         if (bytestream2_get_bytes_left(&ctx->gb) < 16)
690                             return AVERROR_INVALIDDATA;
691                         for (k = 0; k < 4; k++)
692                             bytestream2_get_bufferu(&ctx->gb, dst + i + k * stride, 4);
693                         break;
694                     case 0xFE:
695                         if (bytestream2_get_bytes_left(&ctx->gb) < 4)
696                             return AVERROR_INVALIDDATA;
697                         for (k = 0; k < 4; k++)
698                             memset(dst + i + k * stride, bytestream2_get_byteu(&ctx->gb), 4);
699                         break;
700                     case 0xFD:
701                         if (bytestream2_get_bytes_left(&ctx->gb) < 1)
702                             return AVERROR_INVALIDDATA;
703                         t = bytestream2_get_byteu(&ctx->gb);
704                         for (k = 0; k < 4; k++)
705                             memset(dst + i + k * stride, t, 4);
706                         break;
707                     default:
708                         if (compr == 4 && !code) {
709                             if (bytestream2_get_bytes_left(&ctx->gb) < 1)
710                                 return AVERROR_INVALIDDATA;
711                             skip_run = bytestream2_get_byteu(&ctx->gb) + 1;
712                             i -= 4;
713                         } else {
714                             int mx, my;
715 
716                             mx = c37_mv[(mvoff * 255 + code) * 2];
717                             my = c37_mv[(mvoff * 255 + code) * 2 + 1];
718                             codec37_mv(dst + i, prev + i + mx + my * stride,
719                                        ctx->height, stride, i + mx, j + my);
720                         }
721                     }
722                 }
723                 dst  += stride * 4;
724                 prev += stride * 4;
725             }
726         } else {
727             for (j = 0; j < height; j += 4) {
728                 for (i = 0; i < width; i += 4) {
729                     int code;
730                     if (skip_run) {
731                         skip_run--;
732                         copy_block4(dst + i, prev + i, stride, stride, 4);
733                         continue;
734                     }
735                     code = bytestream2_get_byte(&ctx->gb);
736                     if (code == 0xFF) {
737                         if (bytestream2_get_bytes_left(&ctx->gb) < 16)
738                             return AVERROR_INVALIDDATA;
739                         for (k = 0; k < 4; k++)
740                             bytestream2_get_bufferu(&ctx->gb, dst + i + k * stride, 4);
741                     } else if (compr == 4 && !code) {
742                         if (bytestream2_get_bytes_left(&ctx->gb) < 1)
743                             return AVERROR_INVALIDDATA;
744                         skip_run = bytestream2_get_byteu(&ctx->gb) + 1;
745                         i -= 4;
746                     } else {
747                         int mx, my;
748 
749                         mx = c37_mv[(mvoff * 255 + code) * 2];
750                         my = c37_mv[(mvoff * 255 + code) * 2 + 1];
751                         codec37_mv(dst + i, prev + i + mx + my * stride,
752                                    ctx->height, stride, i + mx, j + my);
753                     }
754                 }
755                 dst  += stride * 4;
756                 prev += stride * 4;
757             }
758         }
759         break;
760     default:
761         avpriv_report_missing_feature(ctx->avctx,
762                                       "Subcodec 37 compression %d", compr);
763         return AVERROR_PATCHWELCOME;
764     }
765 
766     return 0;
767 }
768 
process_block(SANMVideoContext * ctx,uint8_t * dst,uint8_t * prev1,uint8_t * prev2,int stride,int tbl,int size)769 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     if (bytestream2_get_bytes_left(&ctx->gb) < 1)
777         return AVERROR_INVALIDDATA;
778 
779     code = bytestream2_get_byteu(&ctx->gb);
780     if (code >= 0xF8) {
781         switch (code) {
782         case 0xFF:
783             if (size == 2) {
784                 if (bytestream2_get_bytes_left(&ctx->gb) < 4)
785                     return AVERROR_INVALIDDATA;
786                 dst[0]          = bytestream2_get_byteu(&ctx->gb);
787                 dst[1]          = bytestream2_get_byteu(&ctx->gb);
788                 dst[0 + stride] = bytestream2_get_byteu(&ctx->gb);
789                 dst[1 + stride] = bytestream2_get_byteu(&ctx->gb);
790             } else {
791                 size >>= 1;
792                 if (process_block(ctx, dst, prev1, prev2, stride, tbl, size))
793                     return AVERROR_INVALIDDATA;
794                 if (process_block(ctx, dst + size, prev1 + size, prev2 + size,
795                                   stride, tbl, size))
796                     return AVERROR_INVALIDDATA;
797                 dst   += size * stride;
798                 prev1 += size * stride;
799                 prev2 += size * stride;
800                 if (process_block(ctx, dst, prev1, prev2, stride, tbl, size))
801                     return AVERROR_INVALIDDATA;
802                 if (process_block(ctx, dst + size, prev1 + size, prev2 + size,
803                                   stride, tbl, size))
804                     return AVERROR_INVALIDDATA;
805             }
806             break;
807         case 0xFE:
808             if (bytestream2_get_bytes_left(&ctx->gb) < 1)
809                 return AVERROR_INVALIDDATA;
810 
811             t = bytestream2_get_byteu(&ctx->gb);
812             for (k = 0; k < size; k++)
813                 memset(dst + k * stride, t, size);
814             break;
815         case 0xFD:
816             if (bytestream2_get_bytes_left(&ctx->gb) < 3)
817                 return AVERROR_INVALIDDATA;
818 
819             code = bytestream2_get_byteu(&ctx->gb);
820             pglyph = (size == 8) ? ctx->p8x8glyphs[code] : ctx->p4x4glyphs[code];
821             bytestream2_get_bufferu(&ctx->gb, colors, 2);
822 
823             for (k = 0; k < size; k++)
824                 for (t = 0; t < size; t++)
825                     dst[t + k * stride] = colors[!*pglyph++];
826             break;
827         case 0xFC:
828             for (k = 0; k < size; k++)
829                 memcpy(dst + k * stride, prev1 + k * stride, size);
830             break;
831         default:
832             k = bytestream2_tell(&ctx->gb);
833             bytestream2_seek(&ctx->gb, tbl + (code & 7), SEEK_SET);
834             t = bytestream2_get_byte(&ctx->gb);
835             bytestream2_seek(&ctx->gb, k, SEEK_SET);
836             for (k = 0; k < size; k++)
837                 memset(dst + k * stride, t, size);
838         }
839     } else {
840         int mx = motion_vectors[code][0];
841         int my = motion_vectors[code][1];
842         int index = prev2 - (const uint8_t *)ctx->frm2;
843 
844         av_assert2(index >= 0 && index < (ctx->buf_size >> 1));
845 
846         if (index < -mx - my * stride ||
847             (ctx->buf_size >> 1) - index < mx + size + (my + size - 1) * stride) {
848             av_log(ctx->avctx, AV_LOG_ERROR, "MV is invalid.\n");
849             return AVERROR_INVALIDDATA;
850         }
851 
852         for (k = 0; k < size; k++)
853             memcpy(dst + k * stride, prev2 + mx + (my + k) * stride, size);
854     }
855 
856     return 0;
857 }
858 
old_codec47(SANMVideoContext * ctx,int top,int left,int width,int height)859 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     ptrdiff_t stride = ctx->pitch;
865     uint8_t *dst   = (uint8_t *)ctx->frm0 + left + top * stride;
866     uint8_t *prev1 = (uint8_t *)ctx->frm1;
867     uint8_t *prev2 = (uint8_t *)ctx->frm2;
868     int tbl_pos = bytestream2_tell(&ctx->gb);
869     int seq     = bytestream2_get_le16(&ctx->gb);
870     int compr   = bytestream2_get_byte(&ctx->gb);
871     int new_rot = bytestream2_get_byte(&ctx->gb);
872     int skip    = bytestream2_get_byte(&ctx->gb);
873 
874     bytestream2_skip(&ctx->gb, 9);
875     decoded_size = bytestream2_get_le32(&ctx->gb);
876     bytestream2_skip(&ctx->gb, 8);
877 
878     if (decoded_size > ctx->height * stride - left - top * stride) {
879         decoded_size = ctx->height * stride - left - top * stride;
880         av_log(ctx->avctx, AV_LOG_WARNING, "Decoded size is too large.\n");
881     }
882 
883     if (skip & 1)
884         bytestream2_skip(&ctx->gb, 0x8080);
885     if (!seq) {
886         ctx->prev_seq = -1;
887         memset(prev1, 0, ctx->height * stride);
888         memset(prev2, 0, ctx->height * stride);
889     }
890 
891     switch (compr) {
892     case 0:
893         if (bytestream2_get_bytes_left(&ctx->gb) < width * height)
894             return AVERROR_INVALIDDATA;
895         for (j = 0; j < height; j++) {
896             bytestream2_get_bufferu(&ctx->gb, dst, width);
897             dst += stride;
898         }
899         break;
900     case 1:
901         if (bytestream2_get_bytes_left(&ctx->gb) < ((width + 1) >> 1) * ((height + 1) >> 1))
902             return AVERROR_INVALIDDATA;
903         for (j = 0; j < height; j += 2) {
904             for (i = 0; i < width; i += 2) {
905                 dst[i] =
906                 dst[i + 1] =
907                 dst[stride + i] =
908                 dst[stride + i + 1] = bytestream2_get_byteu(&ctx->gb);
909             }
910             dst += stride * 2;
911         }
912         break;
913     case 2:
914         if (seq == ctx->prev_seq + 1) {
915             for (j = 0; j < height; j += 8) {
916                 for (i = 0; i < width; i += 8)
917                     if (process_block(ctx, dst + i, prev1 + i, prev2 + i, stride,
918                                       tbl_pos + 8, 8))
919                         return AVERROR_INVALIDDATA;
920                 dst   += stride * 8;
921                 prev1 += stride * 8;
922                 prev2 += stride * 8;
923             }
924         }
925         break;
926     case 3:
927         memcpy(ctx->frm0, ctx->frm2, ctx->pitch * ctx->height);
928         break;
929     case 4:
930         memcpy(ctx->frm0, ctx->frm1, ctx->pitch * ctx->height);
931         break;
932     case 5:
933         if (rle_decode(ctx, dst, decoded_size))
934             return AVERROR_INVALIDDATA;
935         break;
936     default:
937         avpriv_report_missing_feature(ctx->avctx,
938                                       "Subcodec 47 compression %d", compr);
939         return AVERROR_PATCHWELCOME;
940     }
941     if (seq == ctx->prev_seq + 1)
942         ctx->rotate_code = new_rot;
943     else
944         ctx->rotate_code = 0;
945     ctx->prev_seq = seq;
946 
947     return 0;
948 }
949 
process_frame_obj(SANMVideoContext * ctx)950 static int process_frame_obj(SANMVideoContext *ctx)
951 {
952     uint16_t codec = bytestream2_get_le16u(&ctx->gb);
953     uint16_t left  = bytestream2_get_le16u(&ctx->gb);
954     uint16_t top   = bytestream2_get_le16u(&ctx->gb);
955     uint16_t w     = bytestream2_get_le16u(&ctx->gb);
956     uint16_t h     = bytestream2_get_le16u(&ctx->gb);
957 
958     if (!w || !h) {
959         av_log(ctx->avctx, AV_LOG_ERROR, "Dimensions are invalid.\n");
960         return AVERROR_INVALIDDATA;
961     }
962 
963     if (ctx->width < left + w || ctx->height < top + h) {
964         int ret = ff_set_dimensions(ctx->avctx, FFMAX(left + w, ctx->width),
965                                     FFMAX(top + h, ctx->height));
966         if (ret < 0)
967             return ret;
968         init_sizes(ctx, FFMAX(left + w, ctx->width),
969                    FFMAX(top + h, ctx->height));
970         if (init_buffers(ctx)) {
971             av_log(ctx->avctx, AV_LOG_ERROR, "Error resizing buffers.\n");
972             return AVERROR(ENOMEM);
973         }
974     }
975     bytestream2_skip(&ctx->gb, 4);
976 
977     switch (codec) {
978     case 1:
979     case 3:
980         return old_codec1(ctx, top, left, w, h);
981     case 37:
982         return old_codec37(ctx, top, left, w, h);
983     case 47:
984         return old_codec47(ctx, top, left, w, h);
985     default:
986         avpriv_request_sample(ctx->avctx, "Subcodec %d", codec);
987         return AVERROR_PATCHWELCOME;
988     }
989 }
990 
decode_0(SANMVideoContext * ctx)991 static int decode_0(SANMVideoContext *ctx)
992 {
993     uint16_t *frm = ctx->frm0;
994     int x, y;
995 
996     if (bytestream2_get_bytes_left(&ctx->gb) < ctx->width * ctx->height * 2) {
997         av_log(ctx->avctx, AV_LOG_ERROR, "Insufficient data for raw frame.\n");
998         return AVERROR_INVALIDDATA;
999     }
1000     for (y = 0; y < ctx->height; y++) {
1001         for (x = 0; x < ctx->width; x++)
1002             frm[x] = bytestream2_get_le16u(&ctx->gb);
1003         frm += ctx->pitch;
1004     }
1005     return 0;
1006 }
1007 
decode_nop(SANMVideoContext * ctx)1008 static int decode_nop(SANMVideoContext *ctx)
1009 {
1010     avpriv_request_sample(ctx->avctx, "Unknown/unsupported compression type");
1011     return AVERROR_PATCHWELCOME;
1012 }
1013 
copy_block(uint16_t * pdest,uint16_t * psrc,int block_size,ptrdiff_t pitch)1014 static void copy_block(uint16_t *pdest, uint16_t *psrc, int block_size, ptrdiff_t pitch)
1015 {
1016     uint8_t *dst = (uint8_t *)pdest;
1017     uint8_t *src = (uint8_t *)psrc;
1018     ptrdiff_t stride = pitch * 2;
1019 
1020     switch (block_size) {
1021     case 2:
1022         copy_block4(dst, src, stride, stride, 2);
1023         break;
1024     case 4:
1025         copy_block8(dst, src, stride, stride, 4);
1026         break;
1027     case 8:
1028         copy_block16(dst, src, stride, stride, 8);
1029         break;
1030     }
1031 }
1032 
fill_block(uint16_t * pdest,uint16_t color,int block_size,ptrdiff_t pitch)1033 static void fill_block(uint16_t *pdest, uint16_t color, int block_size, ptrdiff_t pitch)
1034 {
1035     int x, y;
1036 
1037     pitch -= block_size;
1038     for (y = 0; y < block_size; y++, pdest += pitch)
1039         for (x = 0; x < block_size; x++)
1040             *pdest++ = color;
1041 }
1042 
draw_glyph(SANMVideoContext * ctx,uint16_t * dst,int index,uint16_t fg_color,uint16_t bg_color,int block_size,ptrdiff_t pitch)1043 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     uint16_t colors[2] = { fg_color, bg_color };
1049     int x, y;
1050 
1051     if (index >= NGLYPHS) {
1052         av_log(ctx->avctx, AV_LOG_ERROR, "Ignoring nonexistent glyph #%u.\n", index);
1053         return AVERROR_INVALIDDATA;
1054     }
1055 
1056     pglyph = block_size == 8 ? ctx->p8x8glyphs[index] : ctx->p4x4glyphs[index];
1057     pitch -= block_size;
1058 
1059     for (y = 0; y < block_size; y++, dst += pitch)
1060         for (x = 0; x < block_size; x++)
1061             *dst++ = colors[*pglyph++];
1062     return 0;
1063 }
1064 
opcode_0xf7(SANMVideoContext * ctx,int cx,int cy,int block_size,ptrdiff_t pitch)1065 static int opcode_0xf7(SANMVideoContext *ctx, int cx, int cy, int block_size, ptrdiff_t pitch)
1066 {
1067     uint16_t *dst = ctx->frm0 + cx + cy * ctx->pitch;
1068 
1069     if (block_size == 2) {
1070         uint32_t indices;
1071 
1072         if (bytestream2_get_bytes_left(&ctx->gb) < 4)
1073             return AVERROR_INVALIDDATA;
1074 
1075         indices        = bytestream2_get_le32u(&ctx->gb);
1076         dst[0]         = ctx->codebook[indices & 0xFF];
1077         indices      >>= 8;
1078         dst[1]         = ctx->codebook[indices & 0xFF];
1079         indices      >>= 8;
1080         dst[pitch]     = ctx->codebook[indices & 0xFF];
1081         indices      >>= 8;
1082         dst[pitch + 1] = ctx->codebook[indices & 0xFF];
1083     } else {
1084         uint16_t fgcolor, bgcolor;
1085         int glyph;
1086 
1087         if (bytestream2_get_bytes_left(&ctx->gb) < 3)
1088             return AVERROR_INVALIDDATA;
1089 
1090         glyph   = bytestream2_get_byteu(&ctx->gb);
1091         bgcolor = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
1092         fgcolor = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
1093 
1094         draw_glyph(ctx, dst, glyph, fgcolor, bgcolor, block_size, pitch);
1095     }
1096     return 0;
1097 }
1098 
opcode_0xf8(SANMVideoContext * ctx,int cx,int cy,int block_size,ptrdiff_t pitch)1099 static int opcode_0xf8(SANMVideoContext *ctx, int cx, int cy, int block_size, ptrdiff_t pitch)
1100 {
1101     uint16_t *dst = ctx->frm0 + cx + cy * ctx->pitch;
1102 
1103     if (block_size == 2) {
1104         if (bytestream2_get_bytes_left(&ctx->gb) < 8)
1105             return AVERROR_INVALIDDATA;
1106 
1107         dst[0]         = bytestream2_get_le16u(&ctx->gb);
1108         dst[1]         = bytestream2_get_le16u(&ctx->gb);
1109         dst[pitch]     = bytestream2_get_le16u(&ctx->gb);
1110         dst[pitch + 1] = bytestream2_get_le16u(&ctx->gb);
1111     } else {
1112         uint16_t fgcolor, bgcolor;
1113         int glyph;
1114 
1115         if (bytestream2_get_bytes_left(&ctx->gb) < 5)
1116             return AVERROR_INVALIDDATA;
1117 
1118         glyph   = bytestream2_get_byteu(&ctx->gb);
1119         bgcolor = bytestream2_get_le16u(&ctx->gb);
1120         fgcolor = bytestream2_get_le16u(&ctx->gb);
1121 
1122         draw_glyph(ctx, dst, glyph, fgcolor, bgcolor, block_size, pitch);
1123     }
1124     return 0;
1125 }
1126 
good_mvec(SANMVideoContext * ctx,int cx,int cy,int mx,int my,int block_size)1127 static int good_mvec(SANMVideoContext *ctx, int cx, int cy, int mx, int my,
1128                      int block_size)
1129 {
1130     int start_pos = cx + mx + (cy + my) * ctx->pitch;
1131     int end_pos = start_pos + (block_size - 1) * (ctx->pitch + 1);
1132 
1133     int good = start_pos >= 0 && end_pos < (ctx->buf_size >> 1);
1134 
1135     if (!good)
1136         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     return good;
1141 }
1142 
codec2subblock(SANMVideoContext * ctx,int cx,int cy,int blk_size)1143 static int codec2subblock(SANMVideoContext *ctx, int cx, int cy, int blk_size)
1144 {
1145     int16_t mx, my, index;
1146     int opcode;
1147 
1148     if (bytestream2_get_bytes_left(&ctx->gb) < 1)
1149         return AVERROR_INVALIDDATA;
1150 
1151     opcode = bytestream2_get_byteu(&ctx->gb);
1152 
1153     switch (opcode) {
1154     default:
1155         mx = motion_vectors[opcode][0];
1156         my = motion_vectors[opcode][1];
1157 
1158         if (good_mvec(ctx, cx, cy, mx, my, blk_size)) {
1159             copy_block(ctx->frm0 + cx      + ctx->pitch *  cy,
1160                        ctx->frm2 + cx + mx + ctx->pitch * (cy + my),
1161                        blk_size, ctx->pitch);
1162         }
1163         break;
1164     case 0xF5:
1165         if (bytestream2_get_bytes_left(&ctx->gb) < 2)
1166             return AVERROR_INVALIDDATA;
1167         index = bytestream2_get_le16u(&ctx->gb);
1168 
1169         mx = index % ctx->width;
1170         my = index / ctx->width;
1171 
1172         if (good_mvec(ctx, cx, cy, mx, my, blk_size)) {
1173             copy_block(ctx->frm0 + cx      + ctx->pitch *  cy,
1174                        ctx->frm2 + cx + mx + ctx->pitch * (cy + my),
1175                        blk_size, ctx->pitch);
1176         }
1177         break;
1178     case 0xF6:
1179         copy_block(ctx->frm0 + cx + ctx->pitch * cy,
1180                    ctx->frm1 + cx + ctx->pitch * cy,
1181                    blk_size, ctx->pitch);
1182         break;
1183     case 0xF7:
1184         opcode_0xf7(ctx, cx, cy, blk_size, ctx->pitch);
1185         break;
1186 
1187     case 0xF8:
1188         opcode_0xf8(ctx, cx, cy, blk_size, ctx->pitch);
1189         break;
1190     case 0xF9:
1191     case 0xFA:
1192     case 0xFB:
1193     case 0xFC:
1194         fill_block(ctx->frm0 + cx + cy * ctx->pitch,
1195                    ctx->small_codebook[opcode - 0xf9], blk_size, ctx->pitch);
1196         break;
1197     case 0xFD:
1198         if (bytestream2_get_bytes_left(&ctx->gb) < 1)
1199             return AVERROR_INVALIDDATA;
1200         fill_block(ctx->frm0 + cx + cy * ctx->pitch,
1201                    ctx->codebook[bytestream2_get_byteu(&ctx->gb)], blk_size, ctx->pitch);
1202         break;
1203     case 0xFE:
1204         if (bytestream2_get_bytes_left(&ctx->gb) < 2)
1205             return AVERROR_INVALIDDATA;
1206         fill_block(ctx->frm0 + cx + cy * ctx->pitch,
1207                    bytestream2_get_le16u(&ctx->gb), blk_size, ctx->pitch);
1208         break;
1209     case 0xFF:
1210         if (blk_size == 2) {
1211             opcode_0xf8(ctx, cx, cy, blk_size, ctx->pitch);
1212         } else {
1213             blk_size >>= 1;
1214             if (codec2subblock(ctx, cx, cy, blk_size))
1215                 return AVERROR_INVALIDDATA;
1216             if (codec2subblock(ctx, cx + blk_size, cy, blk_size))
1217                 return AVERROR_INVALIDDATA;
1218             if (codec2subblock(ctx, cx, cy + blk_size, blk_size))
1219                 return AVERROR_INVALIDDATA;
1220             if (codec2subblock(ctx, cx + blk_size, cy + blk_size, blk_size))
1221                 return AVERROR_INVALIDDATA;
1222         }
1223         break;
1224     }
1225     return 0;
1226 }
1227 
decode_2(SANMVideoContext * ctx)1228 static int decode_2(SANMVideoContext *ctx)
1229 {
1230     int cx, cy, ret;
1231 
1232     for (cy = 0; cy < ctx->aligned_height; cy += 8)
1233         for (cx = 0; cx < ctx->aligned_width; cx += 8)
1234             if (ret = codec2subblock(ctx, cx, cy, 8))
1235                 return ret;
1236 
1237     return 0;
1238 }
1239 
decode_3(SANMVideoContext * ctx)1240 static int decode_3(SANMVideoContext *ctx)
1241 {
1242     memcpy(ctx->frm0, ctx->frm2, ctx->frm2_size);
1243     return 0;
1244 }
1245 
decode_4(SANMVideoContext * ctx)1246 static int decode_4(SANMVideoContext *ctx)
1247 {
1248     memcpy(ctx->frm0, ctx->frm1, ctx->frm1_size);
1249     return 0;
1250 }
1251 
decode_5(SANMVideoContext * ctx)1252 static int decode_5(SANMVideoContext *ctx)
1253 {
1254 #if HAVE_BIGENDIAN
1255     uint16_t *frm;
1256     int npixels;
1257 #endif
1258     uint8_t *dst = (uint8_t*)ctx->frm0;
1259 
1260     if (rle_decode(ctx, dst, ctx->buf_size))
1261         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     return 0;
1273 }
1274 
decode_6(SANMVideoContext * ctx)1275 static int decode_6(SANMVideoContext *ctx)
1276 {
1277     int npixels = ctx->npixels;
1278     uint16_t *frm = ctx->frm0;
1279 
1280     if (bytestream2_get_bytes_left(&ctx->gb) < npixels) {
1281         av_log(ctx->avctx, AV_LOG_ERROR, "Insufficient data for frame.\n");
1282         return AVERROR_INVALIDDATA;
1283     }
1284     while (npixels--)
1285         *frm++ = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
1286 
1287     return 0;
1288 }
1289 
decode_8(SANMVideoContext * ctx)1290 static int decode_8(SANMVideoContext *ctx)
1291 {
1292     uint16_t *pdest = ctx->frm0;
1293     uint8_t *rsrc;
1294     long npixels = ctx->npixels;
1295 
1296     av_fast_malloc(&ctx->rle_buf, &ctx->rle_buf_size, npixels);
1297     if (!ctx->rle_buf) {
1298         av_log(ctx->avctx, AV_LOG_ERROR, "RLE buffer allocation failed.\n");
1299         return AVERROR(ENOMEM);
1300     }
1301     rsrc = ctx->rle_buf;
1302 
1303     if (rle_decode(ctx, rsrc, npixels))
1304         return AVERROR_INVALIDDATA;
1305 
1306     while (npixels--)
1307         *pdest++ = ctx->codebook[*rsrc++];
1308 
1309     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 
read_frame_header(SANMVideoContext * ctx,SANMFrameHeader * hdr)1319 static int read_frame_header(SANMVideoContext *ctx, SANMFrameHeader *hdr)
1320 {
1321     int i, ret;
1322 
1323     if ((ret = bytestream2_get_bytes_left(&ctx->gb)) < 560) {
1324         av_log(ctx->avctx, AV_LOG_ERROR, "Input frame too short (%d bytes).\n",
1325                ret);
1326         return AVERROR_INVALIDDATA;
1327     }
1328     bytestream2_skip(&ctx->gb, 8); // skip pad
1329 
1330     hdr->width  = bytestream2_get_le32u(&ctx->gb);
1331     hdr->height = bytestream2_get_le32u(&ctx->gb);
1332 
1333     if (hdr->width != ctx->width || hdr->height != ctx->height) {
1334         avpriv_report_missing_feature(ctx->avctx, "Variable size frames");
1335         return AVERROR_PATCHWELCOME;
1336     }
1337 
1338     hdr->seq_num     = bytestream2_get_le16u(&ctx->gb);
1339     hdr->codec       = bytestream2_get_byteu(&ctx->gb);
1340     hdr->rotate_code = bytestream2_get_byteu(&ctx->gb);
1341 
1342     bytestream2_skip(&ctx->gb, 4); // skip pad
1343 
1344     for (i = 0; i < 4; i++)
1345         ctx->small_codebook[i] = bytestream2_get_le16u(&ctx->gb);
1346     hdr->bg_color = bytestream2_get_le16u(&ctx->gb);
1347 
1348     bytestream2_skip(&ctx->gb, 2); // skip pad
1349 
1350     hdr->rle_output_size = bytestream2_get_le32u(&ctx->gb);
1351     for (i = 0; i < 256; i++)
1352         ctx->codebook[i] = bytestream2_get_le16u(&ctx->gb);
1353 
1354     bytestream2_skip(&ctx->gb, 8); // skip pad
1355 
1356     return 0;
1357 }
1358 
fill_frame(uint16_t * pbuf,int buf_size,uint16_t color)1359 static void fill_frame(uint16_t *pbuf, int buf_size, uint16_t color)
1360 {
1361     if (buf_size--) {
1362         *pbuf++ = color;
1363         av_memcpy_backptr((uint8_t*)pbuf, 2, 2*buf_size);
1364     }
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, height = ctx->height;
1372     ptrdiff_t dstpitch, 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   = AV_CODEC_CAP_DR1,
1528 };
1529