FFmpeg
sanm.c
Go to the documentation of this file.
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 {
266 
268  uint32_t pal[PALETTE_SIZE];
270 
271  ptrdiff_t pitch;
272  int width, height;
274  int prev_seq;
275 
277  uint16_t *frm0, *frm1, *frm2;
278  uint8_t *stored_frame;
281 
282  uint8_t *rle_buf;
283  unsigned int rle_buf_size;
284 
286 
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];
295 
296 typedef struct SANMFrameHeader {
298 
299  uint16_t bg_color;
300  uint32_t width, height;
302 
303 enum GlyphEdge {
309 };
310 
311 enum GlyphDir {
317 };
318 
319 /**
320  * Return enum GlyphEdge of box where point (x, y) lies.
321  *
322  * @param x x point coordinate
323  * @param y y point coordinate
324  * @param edge_size box width/height.
325  */
326 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 
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. */
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  */
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 
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 
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 
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)) {
475  return AVERROR(ENOMEM);
476  }
477 
478  return 0;
479 }
480 
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 
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 
523 {
524  SANMVideoContext *ctx = avctx->priv_data;
525 
527 
528  return 0;
529 }
530 
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 {
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 
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 
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 
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:
762  "Subcodec 37 compression %d", compr);
763  return AVERROR_PATCHWELCOME;
764  }
765 
766  return 0;
767 }
768 
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 
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:
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:
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 
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 
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 
1009 {
1010  avpriv_request_sample(ctx->avctx, "Unknown/unsupported compression type");
1011  return AVERROR_PATCHWELCOME;
1012 }
1013 
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 
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 
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 
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 
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 
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 
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 
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 
1241 {
1242  memcpy(ctx->frm0, ctx->frm2, ctx->frm2_size);
1243  return 0;
1244 }
1245 
1247 {
1248  memcpy(ctx->frm0, ctx->frm1, ctx->frm1_size);
1249  return 0;
1250 }
1251 
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 
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 
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 
1313 
1314 static const frm_decoder v1_decoders[] = {
1317 };
1318 
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 
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 
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 
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 {
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 
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  .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
1529 };
SANMVideoContext::width
int width
Definition: sanm.c:272
AVCodec
AVCodec.
Definition: codec.h:202
stride
int stride
Definition: mace.c:144
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
AV_CODEC_ID_SANM
@ AV_CODEC_ID_SANM
Definition: codec_id.h:232
motion_vectors
static const int8_t motion_vectors[256][2]
Definition: sanm.c:53
FF_CODEC_CAP_INIT_THREADSAFE
#define FF_CODEC_CAP_INIT_THREADSAFE
The codec does not modify any global variables in the init function, allowing to call the init functi...
Definition: internal.h:42
decode_0
static int decode_0(SANMVideoContext *ctx)
Definition: sanm.c:991
BOTTOM_EDGE
@ BOTTOM_EDGE
Definition: sanm.c:307
SANMVideoContext::rle_buf
uint8_t * rle_buf
Definition: sanm.c:282
decode_5
static int decode_5(SANMVideoContext *ctx)
Definition: sanm.c:1252
fill_block
static void fill_block(uint16_t *pdest, uint16_t color, int block_size, ptrdiff_t pitch)
Definition: sanm.c:1033
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
make_glyphs
static void make_glyphs(int8_t *pglyphs, const int8_t *xvec, const int8_t *yvec, const int side_length)
Construct glyphs by iterating through vector coordinates.
Definition: sanm.c:385
color
Definition: vf_paletteuse.c:599
process_block
static int process_block(SANMVideoContext *ctx, uint8_t *dst, uint8_t *prev1, uint8_t *prev2, int stride, int tbl, int size)
Definition: sanm.c:769
GetByteContext
Definition: bytestream.h:33
SANMVideoContext::pal
uint32_t pal[PALETTE_SIZE]
Definition: sanm.c:268
SANMFrameHeader
Definition: sanm.c:296
SANMVideoContext::stored_frame
uint8_t * stored_frame
Definition: sanm.c:278
bytestream2_skipu
static av_always_inline void bytestream2_skipu(GetByteContext *g, unsigned int size)
Definition: bytestream.h:174
SANMVideoContext::aligned_height
int aligned_height
Definition: sanm.c:273
SANMVideoContext::p4x4glyphs
int8_t p4x4glyphs[NGLYPHS][16]
Definition: sanm.c:292
SANMVideoContext::frm0
uint16_t * frm0
Definition: sanm.c:277
SANMFrameHeader::bg_color
uint16_t bg_color
Definition: sanm.c:299
good_mvec
static int good_mvec(SANMVideoContext *ctx, int cx, int cy, int mx, int my, int block_size)
Definition: sanm.c:1127
out_size
int out_size
Definition: movenc.c:55
bytestream2_seek
static av_always_inline int bytestream2_seek(GetByteContext *g, int offset, int whence)
Definition: bytestream.h:212
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:317
tmp
static uint8_t tmp[11]
Definition: aes_ctr.c:26
index
fg index
Definition: ffmpeg_filter.c:167
w
uint8_t w
Definition: llviddspenc.c:38
internal.h
AVPacket::data
uint8_t * data
Definition: packet.h:373
decode_end
static av_cold int decode_end(AVCodecContext *avctx)
Definition: sanm.c:522
data
const char data[16]
Definition: mxf.c:143
interp_point
static void interp_point(int8_t *points, int x0, int y0, int x1, int y1, int pos, int npoints)
Definition: sanm.c:365
copy_block8
static void copy_block8(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride, int h)
Definition: copy_block.h:47
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
decode_3
static int decode_3(SANMVideoContext *ctx)
Definition: sanm.c:1240
old_codec37
static int old_codec37(SANMVideoContext *ctx, int top, int left, int width, int height)
Definition: sanm.c:623
init
static int init
Definition: av_tx.c:47
bytestream2_skip
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition: bytestream.h:168
SANMVideoContext::frame
AVFrame * frame
Definition: sanm.c:276
SANMFrameHeader::codec
int codec
Definition: sanm.c:297
U
#define U(x)
Definition: vp56_arith.h:37
LEFT_EDGE
@ LEFT_EDGE
Definition: sanm.c:304
old_codec47
static int old_codec47(SANMVideoContext *ctx, int top, int left, int width, int height)
Definition: sanm.c:859
glyph8_x
static const int8_t glyph8_x[GLYPH_COORD_VECT_SIZE]
Definition: sanm.c:45
SANMFrameHeader::rotate_code
int rotate_code
Definition: sanm.c:297
SANMVideoContext::gb
GetByteContext gb
Definition: sanm.c:265
destroy_buffers
static void destroy_buffers(SANMVideoContext *ctx)
Definition: sanm.c:450
val
static double val(void *priv, double ch)
Definition: aeval.c:76
decode_2
static int decode_2(SANMVideoContext *ctx)
Definition: sanm.c:1228
SANMVideoContext::small_codebook
uint16_t small_codebook[4]
Definition: sanm.c:290
DIR_LEFT
@ DIR_LEFT
Definition: sanm.c:312
which_edge
static enum GlyphEdge which_edge(int x, int y, int edge_size)
Return enum GlyphEdge of box where point (x, y) lies.
Definition: sanm.c:326
NO_EDGE
@ NO_EDGE
Definition: sanm.c:308
TOP_EDGE
@ TOP_EDGE
Definition: sanm.c:305
avassert.h
old_codec1
static int old_codec1(SANMVideoContext *ctx, int top, int left, int width, int height)
Definition: sanm.c:557
pkt
AVPacket * pkt
Definition: movenc.c:59
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
av_cold
#define av_cold
Definition: attributes.h:90
SANMFrameHeader::width
uint32_t width
Definition: sanm.c:300
av_memcpy_backptr
void av_memcpy_backptr(uint8_t *dst, int back, int cnt)
Overlapping memcpy() implementation.
Definition: mem.c:454
decode
static void decode(AVCodecContext *dec_ctx, AVPacket *pkt, AVFrame *frame, FILE *outfile)
Definition: decode_audio.c:71
AVCodecContext::extradata_size
int extradata_size
Definition: avcodec.h:485
ff_sanm_decoder
const AVCodec ff_sanm_decoder
Definition: sanm.c:1518
width
#define width
SANMFrameHeader::rle_output_size
int rle_output_size
Definition: sanm.c:297
decode_6
static int decode_6(SANMVideoContext *ctx)
Definition: sanm.c:1275
SANMVideoContext::npixels
long npixels
Definition: sanm.c:287
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:201
opcode_0xf8
static int opcode_0xf8(SANMVideoContext *ctx, int cx, int cy, int block_size, ptrdiff_t pitch)
Definition: sanm.c:1099
ctx
AVFormatContext * ctx
Definition: movenc.c:48
SANMVideoContext::stored_frame_size
uint32_t stored_frame_size
Definition: sanm.c:280
AV_RL16
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_RL16
Definition: bytestream.h:94
FFABS
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
Definition: common.h:65
if
if(ret)
Definition: filter_design.txt:179
GlyphEdge
GlyphEdge
Definition: sanm.c:303
init_sizes
static void init_sizes(SANMVideoContext *ctx, int width, int height)
Definition: sanm.c:437
copy_block16
static void copy_block16(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride, int h)
Definition: copy_block.h:68
NULL
#define NULL
Definition: coverity.c:32
SANMFrameHeader::height
uint32_t height
Definition: sanm.c:300
AVERROR_PATCHWELCOME
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:64
SANMVideoContext::aligned_width
int aligned_width
Definition: sanm.c:273
SANMVideoContext::avctx
AVCodecContext * avctx
Definition: sanm.c:264
SANMVideoContext::subversion
int subversion
Definition: sanm.c:267
draw_glyph
static int draw_glyph(SANMVideoContext *ctx, uint16_t *dst, int index, uint16_t fg_color, uint16_t bg_color, int block_size, ptrdiff_t pitch)
Definition: sanm.c:1043
AV_PICTURE_TYPE_I
@ AV_PICTURE_TYPE_I
Intra.
Definition: avutil.h:274
src
#define src
Definition: vp8dsp.c:255
decode_nop
static int decode_nop(SANMVideoContext *ctx)
Definition: sanm.c:1008
bytestream2_get_buffer
static av_always_inline unsigned int bytestream2_get_buffer(GetByteContext *g, uint8_t *dst, unsigned int size)
Definition: bytestream.h:267
PALETTE_SIZE
#define PALETTE_SIZE
Definition: sanm.c:34
SANMVideoContext::frm1_size
uint32_t frm1_size
Definition: sanm.c:279
SANMVideoContext::frm1
uint16_t * frm1
Definition: sanm.c:277
rotate_bufs
static void rotate_bufs(SANMVideoContext *ctx, int rotate_code)
Definition: sanm.c:481
decode_frame
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame_ptr, AVPacket *pkt)
Definition: sanm.c:1389
bytestream2_get_bytes_left
static av_always_inline int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:158
bytestream2_tell
static av_always_inline int bytestream2_tell(GetByteContext *g)
Definition: bytestream.h:192
glyph4_y
static const int8_t glyph4_y[GLYPH_COORD_VECT_SIZE]
Definition: sanm.c:41
NGLYPHS
#define NGLYPHS
Definition: sanm.c:32
SANMVideoContext::frm2_size
uint32_t frm2_size
Definition: sanm.c:279
ff_get_buffer
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1652
AV_CODEC_CAP_DR1
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() or get_encode_buffer() for allocating buffers and supports custom allocators.
Definition: codec.h:52
AVPacket::size
int size
Definition: packet.h:374
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:117
SANMVideoContext
Definition: sanm.c:263
codec37_mv
static void codec37_mv(uint8_t *dst, const uint8_t *src, int height, int stride, int x, int y)
Definition: sanm.c:604
glyph8_y
static const int8_t glyph8_y[GLYPH_COORD_VECT_SIZE]
Definition: sanm.c:49
decode_4
static int decode_4(SANMVideoContext *ctx)
Definition: sanm.c:1246
size
int size
Definition: twinvq_data.h:10344
color
static const uint32_t color[16+AV_CLASS_CATEGORY_NB]
Definition: log.c:92
MKBETAG
#define MKBETAG(a, b, c, d)
Definition: macros.h:56
avpriv_report_missing_feature
void avpriv_report_missing_feature(void *avc, const char *msg,...) av_printf_format(2
Log a generic warning message about a missing feature.
SANMVideoContext::version
int version
Definition: sanm.c:267
header
static const uint8_t header[24]
Definition: sdr2.c:67
height
#define height
decode_init
static av_cold int decode_init(AVCodecContext *avctx)
Definition: sanm.c:488
av_bswap16
#define av_bswap16
Definition: bswap.h:31
rle_decode
static int rle_decode(SANMVideoContext *ctx, uint8_t *dst, const int out_size)
Definition: sanm.c:531
PALETTE_DELTA
#define PALETTE_DELTA
Definition: sanm.c:35
flag
#define flag(name)
Definition: cbs_av1.c:553
copy_block4
static void copy_block4(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride, int h)
Definition: copy_block.h:37
av_assert2
#define av_assert2(cond)
assert() equivalent, that does lie in speed critical code.
Definition: avassert.h:64
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:271
code
and forward the test the status of outputs and forward it to the corresponding return FFERROR_NOT_READY If the filters stores internally one or a few frame for some it can consider them to be part of the FIFO and delay acknowledging a status change accordingly Example code
Definition: filter_design.txt:178
fill_frame
static void fill_frame(uint16_t *pbuf, int buf_size, uint16_t color)
Definition: sanm.c:1359
copy_block.h
copy_block
static void copy_block(uint16_t *pdest, uint16_t *psrc, int block_size, ptrdiff_t pitch)
Definition: sanm.c:1014
AVCodecContext::extradata
uint8_t * extradata
some codecs need / can use extradata like Huffman tables.
Definition: avcodec.h:484
SANMFrameHeader::seq_num
int seq_num
Definition: sanm.c:297
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:209
len
int len
Definition: vorbis_enc_data.h:426
AVCodecContext::height
int height
Definition: avcodec.h:556
AVCodecContext::pix_fmt
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:593
AV_PIX_FMT_RGB565
#define AV_PIX_FMT_RGB565
Definition: pixfmt.h:391
avcodec.h
SANMVideoContext::codebook
uint16_t codebook[256]
Definition: sanm.c:289
read_frame_header
static int read_frame_header(SANMVideoContext *ctx, SANMFrameHeader *hdr)
Definition: sanm.c:1319
GlyphDir
GlyphDir
Definition: sanm.c:311
AV_PIX_FMT_PAL8
@ AV_PIX_FMT_PAL8
8 bits with AV_PIX_FMT_RGB32 palette
Definition: pixfmt.h:77
DIR_DOWN
@ DIR_DOWN
Definition: sanm.c:315
ret
ret
Definition: filter_design.txt:187
bswap.h
glyph4_x
static const int8_t glyph4_x[GLYPH_COORD_VECT_SIZE]
Definition: sanm.c:37
FFSWAP
#define FFSWAP(type, a, b)
Definition: macros.h:52
SANMVideoContext::frm2
uint16_t * frm2
Definition: sanm.c:277
DIR_RIGHT
@ DIR_RIGHT
Definition: sanm.c:314
pos
unsigned int pos
Definition: spdifenc.c:412
process_frame_obj
static int process_frame_obj(SANMVideoContext *ctx)
Definition: sanm.c:950
c37_mv
static const int8_t c37_mv[]
Definition: sanm.c:107
left
Tag MUST be and< 10hcoeff half pel interpolation filter coefficients, hcoeff[0] are the 2 middle coefficients[1] are the next outer ones and so on, resulting in a filter like:...eff[2], hcoeff[1], hcoeff[0], hcoeff[0], hcoeff[1], hcoeff[2] ... the sign of the coefficients is not explicitly stored but alternates after each coeff and coeff[0] is positive, so ...,+,-,+,-,+,+,-,+,-,+,... hcoeff[0] is not explicitly stored but found by subtracting the sum of all stored coefficients with signs from 32 hcoeff[0]=32 - hcoeff[1] - hcoeff[2] - ... a good choice for hcoeff and htaps is htaps=6 hcoeff={40,-10, 2} an alternative which requires more computations at both encoder and decoder side and may or may not be better is htaps=8 hcoeff={42,-14, 6,-2}ref_frames minimum of the number of available reference frames and max_ref_frames for example the first frame after a key frame always has ref_frames=1spatial_decomposition_type wavelet type 0 is a 9/7 symmetric compact integer wavelet 1 is a 5/3 symmetric compact integer wavelet others are reserved stored as delta from last, last is reset to 0 if always_reset||keyframeqlog quality(logarithmic quantizer scale) stored as delta from last, last is reset to 0 if always_reset||keyframemv_scale stored as delta from last, last is reset to 0 if always_reset||keyframe FIXME check that everything works fine if this changes between framesqbias dequantization bias stored as delta from last, last is reset to 0 if always_reset||keyframeblock_max_depth maximum depth of the block tree stored as delta from last, last is reset to 0 if always_reset||keyframequant_table quantization tableHighlevel bitstream structure:==============================--------------------------------------------|Header|--------------------------------------------|------------------------------------|||Block0||||split?||||yes no||||......... intra?||||:Block01 :yes no||||:Block02 :....... ..........||||:Block03 ::y DC ::ref index:||||:Block04 ::cb DC ::motion x :||||......... :cr DC ::motion y :||||....... ..........|||------------------------------------||------------------------------------|||Block1|||...|--------------------------------------------|------------ ------------ ------------|||Y subbands||Cb subbands||Cr subbands||||--- ---||--- ---||--- ---|||||LL0||HL0||||LL0||HL0||||LL0||HL0|||||--- ---||--- ---||--- ---||||--- ---||--- ---||--- ---|||||LH0||HH0||||LH0||HH0||||LH0||HH0|||||--- ---||--- ---||--- ---||||--- ---||--- ---||--- ---|||||HL1||LH1||||HL1||LH1||||HL1||LH1|||||--- ---||--- ---||--- ---||||--- ---||--- ---||--- ---|||||HH1||HL2||||HH1||HL2||||HH1||HL2|||||...||...||...|||------------ ------------ ------------|--------------------------------------------Decoding process:=================------------|||Subbands|------------||||------------|Intra DC||||LL0 subband prediction ------------|\ Dequantization ------------------- \||Reference frames|\ IDWT|------- -------|Motion \|||Frame 0||Frame 1||Compensation . OBMC v -------|------- -------|--------------. \------> Frame n output Frame Frame<----------------------------------/|...|------------------- Range Coder:============Binary Range Coder:------------------- The implemented range coder is an adapted version based upon "Range encoding: an algorithm for removing redundancy from a digitised message." by G. N. N. Martin. The symbols encoded by the Snow range coder are bits(0|1). The associated probabilities are not fix but change depending on the symbol mix seen so far. bit seen|new state ---------+----------------------------------------------- 0|256 - state_transition_table[256 - old_state];1|state_transition_table[old_state];state_transition_table={ 0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 190, 191, 192, 194, 194, 195, 196, 197, 198, 199, 200, 201, 202, 202, 204, 205, 206, 207, 208, 209, 209, 210, 211, 212, 213, 215, 215, 216, 217, 218, 219, 220, 220, 222, 223, 224, 225, 226, 227, 227, 229, 229, 230, 231, 232, 234, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 248, 0, 0, 0, 0, 0, 0, 0};FIXME Range Coding of integers:------------------------- FIXME Neighboring Blocks:===================left and top are set to the respective blocks unless they are outside of the image in which case they are set to the Null block top-left is set to the top left block unless it is outside of the image in which case it is set to the left block if this block has no larger parent block or it is at the left side of its parent block and the top right block is not outside of the image then the top right block is used for top-right else the top-left block is used Null block y, cb, cr are 128 level, ref, mx and my are 0 Motion Vector Prediction:=========================1. the motion vectors of all the neighboring blocks are scaled to compensate for the difference of reference frames scaled_mv=(mv *(256 *(current_reference+1)/(mv.reference+1))+128)> the median of the scaled left
Definition: snow.txt:386
run_len
static const uint8_t run_len[7][16]
Definition: h264_cavlc.c:218
AV_RL32
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_RL32
Definition: bytestream.h:92
GLYPH_COORD_VECT_SIZE
#define GLYPH_COORD_VECT_SIZE
Definition: sanm.c:33
AVCodecContext
main external API structure.
Definition: avcodec.h:383
copy_output
static int copy_output(SANMVideoContext *ctx, SANMFrameHeader *hdr)
Definition: sanm.c:1367
SANMVideoContext::rle_buf_size
unsigned int rle_buf_size
Definition: sanm.c:283
SANMVideoContext::buf_size
long buf_size
Definition: sanm.c:287
av_fast_padded_mallocz
void av_fast_padded_mallocz(void *ptr, unsigned int *size, size_t min_size)
Same behaviour av_fast_padded_malloc except that buffer will always be 0-initialized after call.
Definition: utils.c:63
which_direction
static enum GlyphDir which_direction(enum GlyphEdge edge0, enum GlyphEdge edge1)
Definition: sanm.c:342
av_clip_uint8
#define av_clip_uint8
Definition: common.h:102
RIGHT_EDGE
@ RIGHT_EDGE
Definition: sanm.c:306
AV_PICTURE_TYPE_P
@ AV_PICTURE_TYPE_P
Predicted.
Definition: avutil.h:275
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
SANMVideoContext::p8x8glyphs
int8_t p8x8glyphs[NGLYPHS][64]
Definition: sanm.c:293
ff_set_dimensions
int ff_set_dimensions(AVCodecContext *s, int width, int height)
Check that the provided frame dimensions are valid and set them on the codec context.
Definition: utils.c:86
bytestream2_get_bufferu
static av_always_inline unsigned int bytestream2_get_bufferu(GetByteContext *g, uint8_t *dst, unsigned int size)
Definition: bytestream.h:277
avpriv_request_sample
#define avpriv_request_sample(...)
Definition: tableprint_vlc.h:37
opcode_0xf7
static int opcode_0xf7(SANMVideoContext *ctx, int cx, int cy, int block_size, ptrdiff_t pitch)
Definition: sanm.c:1065
FFALIGN
#define FFALIGN(x, a)
Definition: macros.h:78
AVPacket
This structure stores compressed data.
Definition: packet.h:350
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:410
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
av_fast_malloc
void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size)
Allocate a buffer, reusing the given one if large enough.
Definition: mem.c:560
codec2subblock
static int codec2subblock(SANMVideoContext *ctx, int cx, int cy, int blk_size)
Definition: sanm.c:1143
frm_decoder
int(* frm_decoder)(SANMVideoContext *ctx)
Definition: sanm.c:1312
AVCodecContext::width
int width
picture width / height.
Definition: avcodec.h:556
bytestream.h
imgutils.h
bytestream2_init
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:137
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:561
DIR_UP
@ DIR_UP
Definition: sanm.c:313
v1_decoders
static const frm_decoder v1_decoders[]
Definition: sanm.c:1314
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
h
h
Definition: vp9dsp_template.c:2038
SANMVideoContext::delta_pal
int16_t delta_pal[PALETTE_DELTA]
Definition: sanm.c:269
NO_DIR
@ NO_DIR
Definition: sanm.c:316
AV_RB24
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_WB32 unsigned int_TMPL AV_RB24
Definition: bytestream.h:97
int
int
Definition: ffmpeg_filter.c:153
SANMVideoContext::rotate_code
int rotate_code
Definition: sanm.c:285
SANMVideoContext::pitch
ptrdiff_t pitch
Definition: sanm.c:271
SANMVideoContext::frm0_size
uint32_t frm0_size
Definition: sanm.c:279
SANMVideoContext::prev_seq
int prev_seq
Definition: sanm.c:274
SANMVideoContext::height
int height
Definition: sanm.c:272
decode_8
static int decode_8(SANMVideoContext *ctx)
Definition: sanm.c:1290
init_buffers
static av_cold int init_buffers(SANMVideoContext *ctx)
Definition: sanm.c:463