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/mem.h"
25 
26 #include "avcodec.h"
27 #include "bytestream.h"
28 #include "copy_block.h"
29 #include "codec_internal.h"
30 #include "decode.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];
294  uint8_t c47itbl[0x10000];
296 
297 typedef struct SANMFrameHeader {
299 
300  uint16_t bg_color;
301  uint32_t width, height;
303 
304 enum GlyphEdge {
310 };
311 
312 enum GlyphDir {
318 };
319 
320 /**
321  * Return enum GlyphEdge of box where point (x, y) lies.
322  *
323  * @param x x point coordinate
324  * @param y y point coordinate
325  * @param edge_size box width/height.
326  */
327 static enum GlyphEdge which_edge(int x, int y, int edge_size)
328 {
329  const int edge_max = edge_size - 1;
330 
331  if (!y)
332  return BOTTOM_EDGE;
333  else if (y == edge_max)
334  return TOP_EDGE;
335  else if (!x)
336  return LEFT_EDGE;
337  else if (x == edge_max)
338  return RIGHT_EDGE;
339  else
340  return NO_EDGE;
341 }
342 
343 static enum GlyphDir which_direction(enum GlyphEdge edge0, enum GlyphEdge edge1)
344 {
345  if ((edge0 == LEFT_EDGE && edge1 == RIGHT_EDGE) ||
346  (edge1 == LEFT_EDGE && edge0 == RIGHT_EDGE) ||
347  (edge0 == BOTTOM_EDGE && edge1 != TOP_EDGE) ||
348  (edge1 == BOTTOM_EDGE && edge0 != TOP_EDGE))
349  return DIR_UP;
350  else if ((edge0 == TOP_EDGE && edge1 != BOTTOM_EDGE) ||
351  (edge1 == TOP_EDGE && edge0 != BOTTOM_EDGE))
352  return DIR_DOWN;
353  else if ((edge0 == LEFT_EDGE && edge1 != RIGHT_EDGE) ||
354  (edge1 == LEFT_EDGE && edge0 != RIGHT_EDGE))
355  return DIR_LEFT;
356  else if ((edge0 == TOP_EDGE && edge1 == BOTTOM_EDGE) ||
357  (edge1 == TOP_EDGE && edge0 == BOTTOM_EDGE) ||
358  (edge0 == RIGHT_EDGE && edge1 != LEFT_EDGE) ||
359  (edge1 == RIGHT_EDGE && edge0 != LEFT_EDGE))
360  return DIR_RIGHT;
361 
362  return NO_DIR;
363 }
364 
365 /* Interpolate two points. */
366 static void interp_point(int8_t *points, int x0, int y0, int x1, int y1,
367  int pos, int npoints)
368 {
369  if (npoints) {
370  points[0] = (x0 * pos + x1 * (npoints - pos) + (npoints >> 1)) / npoints;
371  points[1] = (y0 * pos + y1 * (npoints - pos) + (npoints >> 1)) / npoints;
372  } else {
373  points[0] = x0;
374  points[1] = y0;
375  }
376 }
377 
378 /**
379  * Construct glyphs by iterating through vector coordinates.
380  *
381  * @param pglyphs pointer to table where glyphs are stored
382  * @param xvec pointer to x component of vector coordinates
383  * @param yvec pointer to y component of vector coordinates
384  * @param side_length glyph width/height.
385  */
386 static void make_glyphs(int8_t *pglyphs, const int8_t *xvec, const int8_t *yvec,
387  const int side_length)
388 {
389  const int glyph_size = side_length * side_length;
390  int8_t *pglyph = pglyphs;
391 
392  int i, j;
393  for (i = 0; i < GLYPH_COORD_VECT_SIZE; i++) {
394  int x0 = xvec[i];
395  int y0 = yvec[i];
396  enum GlyphEdge edge0 = which_edge(x0, y0, side_length);
397 
398  for (j = 0; j < GLYPH_COORD_VECT_SIZE; j++, pglyph += glyph_size) {
399  int x1 = xvec[j];
400  int y1 = yvec[j];
401  enum GlyphEdge edge1 = which_edge(x1, y1, side_length);
402  enum GlyphDir dir = which_direction(edge0, edge1);
403  int npoints = FFMAX(FFABS(x1 - x0), FFABS(y1 - y0));
404  int ipoint;
405 
406  for (ipoint = 0; ipoint <= npoints; ipoint++) {
407  int8_t point[2];
408  int irow, icol;
409 
410  interp_point(point, x0, y0, x1, y1, ipoint, npoints);
411 
412  switch (dir) {
413  case DIR_UP:
414  for (irow = point[1]; irow >= 0; irow--)
415  pglyph[point[0] + irow * side_length] = 1;
416  break;
417 
418  case DIR_DOWN:
419  for (irow = point[1]; irow < side_length; irow++)
420  pglyph[point[0] + irow * side_length] = 1;
421  break;
422 
423  case DIR_LEFT:
424  for (icol = point[0]; icol >= 0; icol--)
425  pglyph[icol + point[1] * side_length] = 1;
426  break;
427 
428  case DIR_RIGHT:
429  for (icol = point[0]; icol < side_length; icol++)
430  pglyph[icol + point[1] * side_length] = 1;
431  break;
432  }
433  }
434  }
435  }
436 }
437 
438 static void init_sizes(SANMVideoContext *ctx, int width, int height)
439 {
440  ctx->width = width;
441  ctx->height = height;
442  ctx->npixels = width * height;
443 
444  ctx->aligned_width = FFALIGN(width, 8);
445  ctx->aligned_height = FFALIGN(height, 8);
446 
447  ctx->buf_size = ctx->aligned_width * ctx->aligned_height * sizeof(ctx->frm0[0]);
448  ctx->pitch = width;
449 }
450 
452 {
453  av_freep(&ctx->frm0);
454  av_freep(&ctx->frm1);
455  av_freep(&ctx->frm2);
456  av_freep(&ctx->stored_frame);
457  av_freep(&ctx->rle_buf);
458  ctx->frm0_size =
459  ctx->frm1_size =
460  ctx->frm2_size = 0;
461  init_sizes(ctx, 0, 0);
462 }
463 
465 {
466  av_fast_padded_mallocz(&ctx->frm0, &ctx->frm0_size, ctx->buf_size);
467  av_fast_padded_mallocz(&ctx->frm1, &ctx->frm1_size, ctx->buf_size);
468  av_fast_padded_mallocz(&ctx->frm2, &ctx->frm2_size, ctx->buf_size);
469  if (!ctx->version)
470  av_fast_padded_mallocz(&ctx->stored_frame,
471  &ctx->stored_frame_size, ctx->buf_size);
472 
473  if (!ctx->frm0 || !ctx->frm1 || !ctx->frm2 ||
474  (!ctx->stored_frame && !ctx->version)) {
476  return AVERROR(ENOMEM);
477  }
478 
479  return 0;
480 }
481 
482 static void rotate_bufs(SANMVideoContext *ctx, int rotate_code)
483 {
484  if (rotate_code == 2)
485  FFSWAP(uint16_t*, ctx->frm1, ctx->frm2);
486  FFSWAP(uint16_t*, ctx->frm2, ctx->frm0);
487 }
488 
490 {
491  SANMVideoContext *ctx = avctx->priv_data;
492 
493  ctx->avctx = avctx;
494  ctx->version = !avctx->extradata_size;
495  // early sanity check before allocations to avoid need for deallocation code.
496  if (!ctx->version && avctx->extradata_size < 1026) {
497  av_log(avctx, AV_LOG_ERROR, "Not enough extradata.\n");
498  return AVERROR_INVALIDDATA;
499  }
500 
501  avctx->pix_fmt = ctx->version ? AV_PIX_FMT_RGB565 : AV_PIX_FMT_PAL8;
502 
503  init_sizes(ctx, avctx->width, avctx->height);
504  if (init_buffers(ctx)) {
505  av_log(avctx, AV_LOG_ERROR, "Error allocating buffers.\n");
506  return AVERROR(ENOMEM);
507  }
508 
509  make_glyphs(ctx->p4x4glyphs[0], glyph4_x, glyph4_y, 4);
510  make_glyphs(ctx->p8x8glyphs[0], glyph8_x, glyph8_y, 8);
511 
512  if (!ctx->version) {
513  int i;
514 
515  ctx->subversion = AV_RL16(avctx->extradata);
516  for (i = 0; i < PALETTE_SIZE; i++)
517  ctx->pal[i] = 0xFFU << 24 | AV_RL32(avctx->extradata + 2 + i * 4);
518  }
519 
520  return 0;
521 }
522 
524 {
525  SANMVideoContext *ctx = avctx->priv_data;
526 
528 
529  return 0;
530 }
531 
532 static int rle_decode(SANMVideoContext *ctx, uint8_t *dst, const int out_size)
533 {
534  int opcode, color, run_len, left = out_size;
535 
536  while (left > 0) {
537  opcode = bytestream2_get_byte(&ctx->gb);
538  run_len = (opcode >> 1) + 1;
539  if (run_len > left || bytestream2_get_bytes_left(&ctx->gb) <= 0)
540  return AVERROR_INVALIDDATA;
541 
542  if (opcode & 1) {
543  color = bytestream2_get_byte(&ctx->gb);
544  memset(dst, color, run_len);
545  } else {
547  return AVERROR_INVALIDDATA;
549  }
550 
551  dst += run_len;
552  left -= run_len;
553  }
554 
555  return 0;
556 }
557 
558 static int old_codec1(SANMVideoContext *ctx, int top,
559  int left, int width, int height)
560 {
561  uint8_t *dst = ((uint8_t *)ctx->frm0) + left + top * ctx->pitch;
562  int i, j, len, flag, code, val, pos, end;
563 
564  for (i = 0; i < height; i++) {
565  pos = 0;
566 
567  if (bytestream2_get_bytes_left(&ctx->gb) < 2)
568  return AVERROR_INVALIDDATA;
569 
570  len = bytestream2_get_le16u(&ctx->gb);
571  end = bytestream2_tell(&ctx->gb) + len;
572 
573  while (bytestream2_tell(&ctx->gb) < end) {
574  if (bytestream2_get_bytes_left(&ctx->gb) < 2)
575  return AVERROR_INVALIDDATA;
576 
577  code = bytestream2_get_byteu(&ctx->gb);
578  flag = code & 1;
579  code = (code >> 1) + 1;
580  if (pos + code > width)
581  return AVERROR_INVALIDDATA;
582  if (flag) {
583  val = bytestream2_get_byteu(&ctx->gb);
584  if (val)
585  memset(dst + pos, val, code);
586  pos += code;
587  } else {
588  if (bytestream2_get_bytes_left(&ctx->gb) < code)
589  return AVERROR_INVALIDDATA;
590  for (j = 0; j < code; j++) {
591  val = bytestream2_get_byteu(&ctx->gb);
592  if (val)
593  dst[pos] = val;
594  pos++;
595  }
596  }
597  }
598  dst += ctx->pitch;
599  }
600  ctx->rotate_code = 0;
601 
602  return 0;
603 }
604 
605 static inline void codec37_mv(uint8_t *dst, const uint8_t *src,
606  int height, int stride, int x, int y)
607 {
608  int pos, i, j;
609 
610  pos = x + y * stride;
611  for (j = 0; j < 4; j++) {
612  for (i = 0; i < 4; i++) {
613  if ((pos + i) < 0 || (pos + i) >= height * stride)
614  dst[i] = 0;
615  else
616  dst[i] = src[i];
617  }
618  dst += stride;
619  src += stride;
620  pos += stride;
621  }
622 }
623 
624 static int old_codec37(SANMVideoContext *ctx, int top,
625  int left, int width, int height)
626 {
627  ptrdiff_t stride = ctx->pitch;
628  int i, j, k, t;
629  uint8_t *dst, *prev;
630  int skip_run = 0;
631  int compr = bytestream2_get_byte(&ctx->gb);
632  int mvoff = bytestream2_get_byte(&ctx->gb);
633  int seq = bytestream2_get_le16(&ctx->gb);
634  uint32_t decoded_size = bytestream2_get_le32(&ctx->gb);
635  int flags;
636 
637  bytestream2_skip(&ctx->gb, 4);
638  flags = bytestream2_get_byte(&ctx->gb);
639  bytestream2_skip(&ctx->gb, 3);
640 
641  if (decoded_size > ctx->height * stride - left - top * stride) {
642  decoded_size = ctx->height * stride - left - top * stride;
643  av_log(ctx->avctx, AV_LOG_WARNING, "Decoded size is too large.\n");
644  }
645 
646  ctx->rotate_code = 0;
647 
648  if (((seq & 1) || !(flags & 1)) && (compr && compr != 2))
649  rotate_bufs(ctx, 1);
650 
651  dst = ((uint8_t*)ctx->frm0) + left + top * stride;
652  prev = ((uint8_t*)ctx->frm2) + left + top * stride;
653 
654  if (mvoff > 2) {
655  av_log(ctx->avctx, AV_LOG_ERROR, "Invalid motion base value %d.\n", mvoff);
656  return AVERROR_INVALIDDATA;
657  }
658 
659  switch (compr) {
660  case 0:
661  for (i = 0; i < height; i++) {
663  dst += stride;
664  }
665  memset(ctx->frm1, 0, ctx->height * stride);
666  memset(ctx->frm2, 0, ctx->height * stride);
667  break;
668  case 2:
669  if (rle_decode(ctx, dst, decoded_size))
670  return AVERROR_INVALIDDATA;
671  memset(ctx->frm1, 0, ctx->frm1_size);
672  memset(ctx->frm2, 0, ctx->frm2_size);
673  break;
674  case 3:
675  case 4:
676  if (flags & 4) {
677  for (j = 0; j < height; j += 4) {
678  for (i = 0; i < width; i += 4) {
679  int code;
680  if (skip_run) {
681  skip_run--;
682  copy_block4(dst + i, prev + i, stride, stride, 4);
683  continue;
684  }
685  if (bytestream2_get_bytes_left(&ctx->gb) < 1)
686  return AVERROR_INVALIDDATA;
687  code = bytestream2_get_byteu(&ctx->gb);
688  switch (code) {
689  case 0xFF:
690  if (bytestream2_get_bytes_left(&ctx->gb) < 16)
691  return AVERROR_INVALIDDATA;
692  for (k = 0; k < 4; k++)
693  bytestream2_get_bufferu(&ctx->gb, dst + i + k * stride, 4);
694  break;
695  case 0xFE:
696  if (bytestream2_get_bytes_left(&ctx->gb) < 4)
697  return AVERROR_INVALIDDATA;
698  for (k = 0; k < 4; k++)
699  memset(dst + i + k * stride, bytestream2_get_byteu(&ctx->gb), 4);
700  break;
701  case 0xFD:
702  if (bytestream2_get_bytes_left(&ctx->gb) < 1)
703  return AVERROR_INVALIDDATA;
704  t = bytestream2_get_byteu(&ctx->gb);
705  for (k = 0; k < 4; k++)
706  memset(dst + i + k * stride, t, 4);
707  break;
708  default:
709  if (compr == 4 && !code) {
710  if (bytestream2_get_bytes_left(&ctx->gb) < 1)
711  return AVERROR_INVALIDDATA;
712  skip_run = bytestream2_get_byteu(&ctx->gb) + 1;
713  i -= 4;
714  } else {
715  int mx, my;
716 
717  mx = c37_mv[(mvoff * 255 + code) * 2];
718  my = c37_mv[(mvoff * 255 + code) * 2 + 1];
719  codec37_mv(dst + i, prev + i + mx + my * stride,
720  ctx->height, stride, i + mx, j + my);
721  }
722  }
723  }
724  dst += stride * 4;
725  prev += stride * 4;
726  }
727  } else {
728  for (j = 0; j < height; j += 4) {
729  for (i = 0; i < width; i += 4) {
730  int code;
731  if (skip_run) {
732  skip_run--;
733  copy_block4(dst + i, prev + i, stride, stride, 4);
734  continue;
735  }
736  code = bytestream2_get_byte(&ctx->gb);
737  if (code == 0xFF) {
738  if (bytestream2_get_bytes_left(&ctx->gb) < 16)
739  return AVERROR_INVALIDDATA;
740  for (k = 0; k < 4; k++)
741  bytestream2_get_bufferu(&ctx->gb, dst + i + k * stride, 4);
742  } else if (compr == 4 && !code) {
743  if (bytestream2_get_bytes_left(&ctx->gb) < 1)
744  return AVERROR_INVALIDDATA;
745  skip_run = bytestream2_get_byteu(&ctx->gb) + 1;
746  i -= 4;
747  } else {
748  int mx, my;
749 
750  mx = c37_mv[(mvoff * 255 + code) * 2];
751  my = c37_mv[(mvoff * 255 + code) * 2 + 1];
752  codec37_mv(dst + i, prev + i + mx + my * stride,
753  ctx->height, stride, i + mx, j + my);
754  }
755  }
756  dst += stride * 4;
757  prev += stride * 4;
758  }
759  }
760  break;
761  default:
763  "Subcodec 37 compression %d", compr);
764  return AVERROR_PATCHWELCOME;
765  }
766 
767  return 0;
768 }
769 
770 static int process_block(SANMVideoContext *ctx, uint8_t *dst, uint8_t *prev1,
771  uint8_t *prev2, int stride, int tbl, int size)
772 {
773  int code, k, t;
774  uint8_t colors[2];
775  int8_t *pglyph;
776 
777  if (bytestream2_get_bytes_left(&ctx->gb) < 1)
778  return AVERROR_INVALIDDATA;
779 
780  code = bytestream2_get_byteu(&ctx->gb);
781  if (code >= 0xF8) {
782  switch (code) {
783  case 0xFF:
784  if (size == 2) {
785  if (bytestream2_get_bytes_left(&ctx->gb) < 4)
786  return AVERROR_INVALIDDATA;
787  dst[0] = bytestream2_get_byteu(&ctx->gb);
788  dst[1] = bytestream2_get_byteu(&ctx->gb);
789  dst[0 + stride] = bytestream2_get_byteu(&ctx->gb);
790  dst[1 + stride] = bytestream2_get_byteu(&ctx->gb);
791  } else {
792  size >>= 1;
793  if (process_block(ctx, dst, prev1, prev2, stride, tbl, size))
794  return AVERROR_INVALIDDATA;
795  if (process_block(ctx, dst + size, prev1 + size, prev2 + size,
796  stride, tbl, size))
797  return AVERROR_INVALIDDATA;
798  dst += size * stride;
799  prev1 += size * stride;
800  prev2 += size * stride;
801  if (process_block(ctx, dst, prev1, prev2, stride, tbl, size))
802  return AVERROR_INVALIDDATA;
803  if (process_block(ctx, dst + size, prev1 + size, prev2 + size,
804  stride, tbl, size))
805  return AVERROR_INVALIDDATA;
806  }
807  break;
808  case 0xFE:
809  if (bytestream2_get_bytes_left(&ctx->gb) < 1)
810  return AVERROR_INVALIDDATA;
811 
812  t = bytestream2_get_byteu(&ctx->gb);
813  for (k = 0; k < size; k++)
814  memset(dst + k * stride, t, size);
815  break;
816  case 0xFD:
817  if (bytestream2_get_bytes_left(&ctx->gb) < 3)
818  return AVERROR_INVALIDDATA;
819 
820  code = bytestream2_get_byteu(&ctx->gb);
821  pglyph = (size == 8) ? ctx->p8x8glyphs[code] : ctx->p4x4glyphs[code];
822  bytestream2_get_bufferu(&ctx->gb, colors, 2);
823 
824  for (k = 0; k < size; k++)
825  for (t = 0; t < size; t++)
826  dst[t + k * stride] = colors[!*pglyph++];
827  break;
828  case 0xFC:
829  for (k = 0; k < size; k++)
830  memcpy(dst + k * stride, prev1 + k * stride, size);
831  break;
832  default:
833  k = bytestream2_tell(&ctx->gb);
834  bytestream2_seek(&ctx->gb, tbl + (code & 7), SEEK_SET);
835  t = bytestream2_get_byte(&ctx->gb);
836  bytestream2_seek(&ctx->gb, k, SEEK_SET);
837  for (k = 0; k < size; k++)
838  memset(dst + k * stride, t, size);
839  }
840  } else {
841  int mx = motion_vectors[code][0];
842  int my = motion_vectors[code][1];
843  int index = prev2 - (const uint8_t *)ctx->frm2;
844 
845  av_assert2(index >= 0 && index < (ctx->buf_size >> 1));
846 
847  if (index < -mx - my * stride ||
848  (ctx->buf_size >> 1) - index < mx + size + (my + size - 1) * stride) {
849  av_log(ctx->avctx, AV_LOG_ERROR, "MV is invalid.\n");
850  return AVERROR_INVALIDDATA;
851  }
852 
853  for (k = 0; k < size; k++)
854  memcpy(dst + k * stride, prev2 + mx + (my + k) * stride, size);
855  }
856 
857  return 0;
858 }
859 
861 {
862  uint8_t *p1, *p2, *itbl = ctx->c47itbl;
863  int i, j;
864 
865  for (i = 0; i < 256; i++) {
866  p1 = p2 = itbl + i;
867  for (j = 256 - i; j; j--) {
868  *p1 = *p2 = bytestream2_get_byte(&ctx->gb);
869  p1 += 1;
870  p2 += 256;
871  }
872  itbl += 256;
873  }
874 }
875 
876 static void codec47_comp1(SANMVideoContext *ctx, uint8_t *dst_in, int width,
877  int height, ptrdiff_t stride)
878 {
879  uint8_t p1, *dst, *itbl = ctx->c47itbl;
880  uint16_t px;
881  int i, j;
882 
883  dst = dst_in + stride;
884  for (i = 0; i < height; i += 2) {
885  p1 = bytestream2_get_byte(&ctx->gb);
886  *dst++ = p1;
887  *dst++ = p1;
888  px = p1;
889  for (j = 2; j < width; j += 2) {
890  p1 = bytestream2_get_byte(&ctx->gb);
891  px = (px << 8) | p1;
892  *dst++ = itbl[px];
893  *dst++ = p1;
894  }
895  dst += stride;
896  }
897 
898  memcpy(dst_in, dst_in + stride, width);
899  dst = dst_in + stride + stride;
900  for (i = 2; i < height - 1; i += 2) {
901  for (j = 0; j < width; j++) {
902  px = (*(dst - stride) << 8) | *(dst + stride);
903  *dst++ = itbl[px];
904  }
905  dst += stride;
906  }
907 }
908 
909 static int old_codec47(SANMVideoContext *ctx, int top,
910  int left, int width, int height)
911 {
912  uint32_t decoded_size;
913  int i, j;
914  ptrdiff_t stride = ctx->pitch;
915  uint8_t *dst = (uint8_t *)ctx->frm0 + left + top * stride;
916  uint8_t *prev1 = (uint8_t *)ctx->frm1 + left + top * stride;
917  uint8_t *prev2 = (uint8_t *)ctx->frm2 + left + top * stride;
918  uint8_t auxcol[2];
919  int tbl_pos = bytestream2_tell(&ctx->gb);
920  int seq = bytestream2_get_le16(&ctx->gb);
921  int compr = bytestream2_get_byte(&ctx->gb);
922  int new_rot = bytestream2_get_byte(&ctx->gb);
923  int skip = bytestream2_get_byte(&ctx->gb);
924 
925  bytestream2_skip(&ctx->gb, 7);
926  auxcol[0] = bytestream2_get_byteu(&ctx->gb);
927  auxcol[1] = bytestream2_get_byteu(&ctx->gb);
928  decoded_size = bytestream2_get_le32(&ctx->gb);
929  bytestream2_skip(&ctx->gb, 8);
930 
931  if (decoded_size > ctx->height * stride - left - top * stride) {
932  decoded_size = ctx->height * stride - left - top * stride;
933  av_log(ctx->avctx, AV_LOG_WARNING, "Decoded size is too large.\n");
934  }
935 
936  if (skip & 1) {
937  if (bytestream2_get_bytes_left(&ctx->gb) < 0x8080)
938  return AVERROR_INVALIDDATA;
940  }
941  if (!seq) {
942  ctx->prev_seq = -1;
943  memset(prev1, auxcol[0], (ctx->height - top) * stride);
944  memset(prev2, auxcol[1], (ctx->height - top) * stride);
945  }
946 
947  switch (compr) {
948  case 0:
950  return AVERROR_INVALIDDATA;
951  for (j = 0; j < height; j++) {
953  dst += stride;
954  }
955  break;
956  case 1:
957  if (bytestream2_get_bytes_left(&ctx->gb) < ((width + 1) >> 1) * ((height + 1) >> 1))
958  return AVERROR_INVALIDDATA;
960  break;
961  case 2:
962  if (seq == ctx->prev_seq + 1) {
963  for (j = 0; j < height; j += 8) {
964  for (i = 0; i < width; i += 8)
965  if (process_block(ctx, dst + i, prev1 + i, prev2 + i, stride,
966  tbl_pos + 8, 8))
967  return AVERROR_INVALIDDATA;
968  dst += stride * 8;
969  prev1 += stride * 8;
970  prev2 += stride * 8;
971  }
972  }
973  break;
974  case 3:
975  memcpy(ctx->frm0, ctx->frm2, ctx->pitch * ctx->height);
976  break;
977  case 4:
978  memcpy(ctx->frm0, ctx->frm1, ctx->pitch * ctx->height);
979  break;
980  case 5:
981  if (rle_decode(ctx, dst, decoded_size))
982  return AVERROR_INVALIDDATA;
983  break;
984  default:
986  "Subcodec 47 compression %d", compr);
987  return AVERROR_PATCHWELCOME;
988  }
989  if (seq == ctx->prev_seq + 1)
990  ctx->rotate_code = new_rot;
991  else
992  ctx->rotate_code = 0;
993  ctx->prev_seq = seq;
994 
995  return 0;
996 }
997 
999 {
1000  uint16_t codec = bytestream2_get_le16u(&ctx->gb);
1001  uint16_t left = bytestream2_get_le16u(&ctx->gb);
1002  uint16_t top = bytestream2_get_le16u(&ctx->gb);
1003  uint16_t w = bytestream2_get_le16u(&ctx->gb);
1004  uint16_t h = bytestream2_get_le16u(&ctx->gb);
1005 
1006  if (!w || !h) {
1007  av_log(ctx->avctx, AV_LOG_ERROR, "Dimensions are invalid.\n");
1008  return AVERROR_INVALIDDATA;
1009  }
1010 
1011  if (ctx->width < left + w || ctx->height < top + h) {
1012  int ret = ff_set_dimensions(ctx->avctx, FFMAX(left + w, ctx->width),
1013  FFMAX(top + h, ctx->height));
1014  if (ret < 0)
1015  return ret;
1016  init_sizes(ctx, FFMAX(left + w, ctx->width),
1017  FFMAX(top + h, ctx->height));
1018  if (init_buffers(ctx)) {
1019  av_log(ctx->avctx, AV_LOG_ERROR, "Error resizing buffers.\n");
1020  return AVERROR(ENOMEM);
1021  }
1022  }
1023  bytestream2_skip(&ctx->gb, 4);
1024 
1025  switch (codec) {
1026  case 1:
1027  case 3:
1028  return old_codec1(ctx, top, left, w, h);
1029  case 37:
1030  return old_codec37(ctx, top, left, w, h);
1031  case 47:
1032  return old_codec47(ctx, top, left, w, h);
1033  default:
1034  avpriv_request_sample(ctx->avctx, "Subcodec %d", codec);
1035  return AVERROR_PATCHWELCOME;
1036  }
1037 }
1038 
1040 {
1041  int16_t *dp = ctx->delta_pal;
1042  uint32_t *pal = ctx->pal;
1043  uint16_t cmd;
1044  uint8_t c[3];
1045  int i, j;
1046 
1047  bytestream2_skip(&ctx->gb, 2);
1048  cmd = bytestream2_get_be16(&ctx->gb);
1049 
1050  if (cmd == 1) {
1051  for (i = 0; i < PALETTE_DELTA; i += 3) {
1052  c[0] = (*pal >> 16) & 0xFF;
1053  c[1] = (*pal >> 8) & 0xFF;
1054  c[2] = (*pal >> 0) & 0xFF;
1055  for (j = 0; j < 3; j++) {
1056  int cl = (c[j] * 129) + *dp++;
1057  c[j] = av_clip_uint8(cl / 128) & 0xFF;
1058  }
1059  *pal++ = 0xFFU << 24 | c[0] << 16 | c[1] << 8 | c[2];
1060  }
1061  } else if (cmd == 2) {
1062  if (size < PALETTE_DELTA * 2 + 4) {
1063  av_log(ctx->avctx, AV_LOG_ERROR,
1064  "Incorrect palette change block size %"PRIu32".\n", size);
1065  return AVERROR_INVALIDDATA;
1066  }
1067  for (i = 0; i < PALETTE_DELTA; i++)
1068  dp[i] = bytestream2_get_le16u(&ctx->gb);
1069 
1070  if (size >= PALETTE_DELTA * 2 + 4 + PALETTE_SIZE * 3) {
1071  for (i = 0; i < PALETTE_SIZE; i++)
1072  ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb);
1073  }
1074  }
1075  return 0;
1076 }
1077 
1079 {
1080  uint16_t *frm = ctx->frm0;
1081  int x, y;
1082 
1083  if (bytestream2_get_bytes_left(&ctx->gb) < ctx->width * ctx->height * 2) {
1084  av_log(ctx->avctx, AV_LOG_ERROR, "Insufficient data for raw frame.\n");
1085  return AVERROR_INVALIDDATA;
1086  }
1087  for (y = 0; y < ctx->height; y++) {
1088  for (x = 0; x < ctx->width; x++)
1089  frm[x] = bytestream2_get_le16u(&ctx->gb);
1090  frm += ctx->pitch;
1091  }
1092  return 0;
1093 }
1094 
1096 {
1097  avpriv_request_sample(ctx->avctx, "Unknown/unsupported compression type");
1098  return AVERROR_PATCHWELCOME;
1099 }
1100 
1101 static void copy_block(uint16_t *pdest, uint16_t *psrc, int block_size, ptrdiff_t pitch)
1102 {
1103  uint8_t *dst = (uint8_t *)pdest;
1104  uint8_t *src = (uint8_t *)psrc;
1105  ptrdiff_t stride = pitch * 2;
1106 
1107  switch (block_size) {
1108  case 2:
1109  copy_block4(dst, src, stride, stride, 2);
1110  break;
1111  case 4:
1112  copy_block8(dst, src, stride, stride, 4);
1113  break;
1114  case 8:
1115  copy_block16(dst, src, stride, stride, 8);
1116  break;
1117  }
1118 }
1119 
1120 static void fill_block(uint16_t *pdest, uint16_t color, int block_size, ptrdiff_t pitch)
1121 {
1122  int x, y;
1123 
1124  pitch -= block_size;
1125  for (y = 0; y < block_size; y++, pdest += pitch)
1126  for (x = 0; x < block_size; x++)
1127  *pdest++ = color;
1128 }
1129 
1130 static int draw_glyph(SANMVideoContext *ctx, uint16_t *dst, int index,
1131  uint16_t fg_color, uint16_t bg_color, int block_size,
1132  ptrdiff_t pitch)
1133 {
1134  int8_t *pglyph;
1135  uint16_t colors[2] = { fg_color, bg_color };
1136  int x, y;
1137 
1138  if (index >= NGLYPHS) {
1139  av_log(ctx->avctx, AV_LOG_ERROR, "Ignoring nonexistent glyph #%u.\n", index);
1140  return AVERROR_INVALIDDATA;
1141  }
1142 
1143  pglyph = block_size == 8 ? ctx->p8x8glyphs[index] : ctx->p4x4glyphs[index];
1144  pitch -= block_size;
1145 
1146  for (y = 0; y < block_size; y++, dst += pitch)
1147  for (x = 0; x < block_size; x++)
1148  *dst++ = colors[*pglyph++];
1149  return 0;
1150 }
1151 
1152 static int opcode_0xf7(SANMVideoContext *ctx, int cx, int cy, int block_size, ptrdiff_t pitch)
1153 {
1154  uint16_t *dst = ctx->frm0 + cx + cy * ctx->pitch;
1155 
1156  if (block_size == 2) {
1157  uint32_t indices;
1158 
1159  if (bytestream2_get_bytes_left(&ctx->gb) < 4)
1160  return AVERROR_INVALIDDATA;
1161 
1162  indices = bytestream2_get_le32u(&ctx->gb);
1163  dst[0] = ctx->codebook[indices & 0xFF];
1164  indices >>= 8;
1165  dst[1] = ctx->codebook[indices & 0xFF];
1166  indices >>= 8;
1167  dst[pitch] = ctx->codebook[indices & 0xFF];
1168  indices >>= 8;
1169  dst[pitch + 1] = ctx->codebook[indices & 0xFF];
1170  } else {
1171  uint16_t fgcolor, bgcolor;
1172  int glyph;
1173 
1174  if (bytestream2_get_bytes_left(&ctx->gb) < 3)
1175  return AVERROR_INVALIDDATA;
1176 
1177  glyph = bytestream2_get_byteu(&ctx->gb);
1178  bgcolor = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
1179  fgcolor = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
1180 
1181  draw_glyph(ctx, dst, glyph, fgcolor, bgcolor, block_size, pitch);
1182  }
1183  return 0;
1184 }
1185 
1186 static int opcode_0xf8(SANMVideoContext *ctx, int cx, int cy, int block_size, ptrdiff_t pitch)
1187 {
1188  uint16_t *dst = ctx->frm0 + cx + cy * ctx->pitch;
1189 
1190  if (block_size == 2) {
1191  if (bytestream2_get_bytes_left(&ctx->gb) < 8)
1192  return AVERROR_INVALIDDATA;
1193 
1194  dst[0] = bytestream2_get_le16u(&ctx->gb);
1195  dst[1] = bytestream2_get_le16u(&ctx->gb);
1196  dst[pitch] = bytestream2_get_le16u(&ctx->gb);
1197  dst[pitch + 1] = bytestream2_get_le16u(&ctx->gb);
1198  } else {
1199  uint16_t fgcolor, bgcolor;
1200  int glyph;
1201 
1202  if (bytestream2_get_bytes_left(&ctx->gb) < 5)
1203  return AVERROR_INVALIDDATA;
1204 
1205  glyph = bytestream2_get_byteu(&ctx->gb);
1206  bgcolor = bytestream2_get_le16u(&ctx->gb);
1207  fgcolor = bytestream2_get_le16u(&ctx->gb);
1208 
1209  draw_glyph(ctx, dst, glyph, fgcolor, bgcolor, block_size, pitch);
1210  }
1211  return 0;
1212 }
1213 
1214 static int good_mvec(SANMVideoContext *ctx, int cx, int cy, int mx, int my,
1215  int block_size)
1216 {
1217  int start_pos = cx + mx + (cy + my) * ctx->pitch;
1218  int end_pos = start_pos + (block_size - 1) * (ctx->pitch + 1);
1219 
1220  int good = start_pos >= 0 && end_pos < (ctx->buf_size >> 1);
1221 
1222  if (!good)
1223  av_log(ctx->avctx, AV_LOG_ERROR,
1224  "Ignoring invalid motion vector (%i, %i)->(%u, %u), block size = %u\n",
1225  cx + mx, cy + my, cx, cy, block_size);
1226 
1227  return good;
1228 }
1229 
1230 static int codec2subblock(SANMVideoContext *ctx, int cx, int cy, int blk_size)
1231 {
1232  int16_t mx, my, index;
1233  int opcode;
1234 
1235  if (bytestream2_get_bytes_left(&ctx->gb) < 1)
1236  return AVERROR_INVALIDDATA;
1237 
1238  opcode = bytestream2_get_byteu(&ctx->gb);
1239 
1240  switch (opcode) {
1241  default:
1242  mx = motion_vectors[opcode][0];
1243  my = motion_vectors[opcode][1];
1244 
1245  if (good_mvec(ctx, cx, cy, mx, my, blk_size)) {
1246  copy_block(ctx->frm0 + cx + ctx->pitch * cy,
1247  ctx->frm2 + cx + mx + ctx->pitch * (cy + my),
1248  blk_size, ctx->pitch);
1249  }
1250  break;
1251  case 0xF5:
1252  if (bytestream2_get_bytes_left(&ctx->gb) < 2)
1253  return AVERROR_INVALIDDATA;
1254  index = bytestream2_get_le16u(&ctx->gb);
1255 
1256  mx = index % ctx->width;
1257  my = index / ctx->width;
1258 
1259  if (good_mvec(ctx, cx, cy, mx, my, blk_size)) {
1260  copy_block(ctx->frm0 + cx + ctx->pitch * cy,
1261  ctx->frm2 + cx + mx + ctx->pitch * (cy + my),
1262  blk_size, ctx->pitch);
1263  }
1264  break;
1265  case 0xF6:
1266  copy_block(ctx->frm0 + cx + ctx->pitch * cy,
1267  ctx->frm1 + cx + ctx->pitch * cy,
1268  blk_size, ctx->pitch);
1269  break;
1270  case 0xF7:
1271  opcode_0xf7(ctx, cx, cy, blk_size, ctx->pitch);
1272  break;
1273 
1274  case 0xF8:
1275  opcode_0xf8(ctx, cx, cy, blk_size, ctx->pitch);
1276  break;
1277  case 0xF9:
1278  case 0xFA:
1279  case 0xFB:
1280  case 0xFC:
1281  fill_block(ctx->frm0 + cx + cy * ctx->pitch,
1282  ctx->small_codebook[opcode - 0xf9], blk_size, ctx->pitch);
1283  break;
1284  case 0xFD:
1285  if (bytestream2_get_bytes_left(&ctx->gb) < 1)
1286  return AVERROR_INVALIDDATA;
1287  fill_block(ctx->frm0 + cx + cy * ctx->pitch,
1288  ctx->codebook[bytestream2_get_byteu(&ctx->gb)], blk_size, ctx->pitch);
1289  break;
1290  case 0xFE:
1291  if (bytestream2_get_bytes_left(&ctx->gb) < 2)
1292  return AVERROR_INVALIDDATA;
1293  fill_block(ctx->frm0 + cx + cy * ctx->pitch,
1294  bytestream2_get_le16u(&ctx->gb), blk_size, ctx->pitch);
1295  break;
1296  case 0xFF:
1297  if (blk_size == 2) {
1298  opcode_0xf8(ctx, cx, cy, blk_size, ctx->pitch);
1299  } else {
1300  blk_size >>= 1;
1301  if (codec2subblock(ctx, cx, cy, blk_size))
1302  return AVERROR_INVALIDDATA;
1303  if (codec2subblock(ctx, cx + blk_size, cy, blk_size))
1304  return AVERROR_INVALIDDATA;
1305  if (codec2subblock(ctx, cx, cy + blk_size, blk_size))
1306  return AVERROR_INVALIDDATA;
1307  if (codec2subblock(ctx, cx + blk_size, cy + blk_size, blk_size))
1308  return AVERROR_INVALIDDATA;
1309  }
1310  break;
1311  }
1312  return 0;
1313 }
1314 
1316 {
1317  int cx, cy, ret;
1318 
1319  for (cy = 0; cy < ctx->aligned_height; cy += 8)
1320  for (cx = 0; cx < ctx->aligned_width; cx += 8)
1321  if (ret = codec2subblock(ctx, cx, cy, 8))
1322  return ret;
1323 
1324  return 0;
1325 }
1326 
1328 {
1329  memcpy(ctx->frm0, ctx->frm2, ctx->frm2_size);
1330  return 0;
1331 }
1332 
1334 {
1335  memcpy(ctx->frm0, ctx->frm1, ctx->frm1_size);
1336  return 0;
1337 }
1338 
1340 {
1341 #if HAVE_BIGENDIAN
1342  uint16_t *frm;
1343  int npixels;
1344 #endif
1345  uint8_t *dst = (uint8_t*)ctx->frm0;
1346 
1347  if (rle_decode(ctx, dst, ctx->buf_size))
1348  return AVERROR_INVALIDDATA;
1349 
1350 #if HAVE_BIGENDIAN
1351  npixels = ctx->npixels;
1352  frm = ctx->frm0;
1353  while (npixels--) {
1354  *frm = av_bswap16(*frm);
1355  frm++;
1356  }
1357 #endif
1358 
1359  return 0;
1360 }
1361 
1363 {
1364  int npixels = ctx->npixels;
1365  uint16_t *frm = ctx->frm0;
1366 
1367  if (bytestream2_get_bytes_left(&ctx->gb) < npixels) {
1368  av_log(ctx->avctx, AV_LOG_ERROR, "Insufficient data for frame.\n");
1369  return AVERROR_INVALIDDATA;
1370  }
1371  while (npixels--)
1372  *frm++ = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
1373 
1374  return 0;
1375 }
1376 
1378 {
1379  uint16_t *pdest = ctx->frm0;
1380  uint8_t *rsrc;
1381  long npixels = ctx->npixels;
1382 
1383  av_fast_malloc(&ctx->rle_buf, &ctx->rle_buf_size, npixels);
1384  if (!ctx->rle_buf) {
1385  av_log(ctx->avctx, AV_LOG_ERROR, "RLE buffer allocation failed.\n");
1386  return AVERROR(ENOMEM);
1387  }
1388  rsrc = ctx->rle_buf;
1389 
1390  if (rle_decode(ctx, rsrc, npixels))
1391  return AVERROR_INVALIDDATA;
1392 
1393  while (npixels--)
1394  *pdest++ = ctx->codebook[*rsrc++];
1395 
1396  return 0;
1397 }
1398 
1400 
1401 static const frm_decoder v1_decoders[] = {
1404 };
1405 
1407 {
1408  int i, ret;
1409 
1410  if ((ret = bytestream2_get_bytes_left(&ctx->gb)) < 560) {
1411  av_log(ctx->avctx, AV_LOG_ERROR, "Input frame too short (%d bytes).\n",
1412  ret);
1413  return AVERROR_INVALIDDATA;
1414  }
1415  bytestream2_skip(&ctx->gb, 8); // skip pad
1416 
1417  hdr->width = bytestream2_get_le32u(&ctx->gb);
1418  hdr->height = bytestream2_get_le32u(&ctx->gb);
1419 
1420  if (hdr->width != ctx->width || hdr->height != ctx->height) {
1421  avpriv_report_missing_feature(ctx->avctx, "Variable size frames");
1422  return AVERROR_PATCHWELCOME;
1423  }
1424 
1425  hdr->seq_num = bytestream2_get_le16u(&ctx->gb);
1426  hdr->codec = bytestream2_get_byteu(&ctx->gb);
1427  hdr->rotate_code = bytestream2_get_byteu(&ctx->gb);
1428 
1429  bytestream2_skip(&ctx->gb, 4); // skip pad
1430 
1431  for (i = 0; i < 4; i++)
1432  ctx->small_codebook[i] = bytestream2_get_le16u(&ctx->gb);
1433  hdr->bg_color = bytestream2_get_le16u(&ctx->gb);
1434 
1435  bytestream2_skip(&ctx->gb, 2); // skip pad
1436 
1437  hdr->rle_output_size = bytestream2_get_le32u(&ctx->gb);
1438  for (i = 0; i < 256; i++)
1439  ctx->codebook[i] = bytestream2_get_le16u(&ctx->gb);
1440 
1441  bytestream2_skip(&ctx->gb, 8); // skip pad
1442 
1443  return 0;
1444 }
1445 
1446 static void fill_frame(uint16_t *pbuf, int buf_size, uint16_t color)
1447 {
1448  if (buf_size--) {
1449  *pbuf++ = color;
1450  av_memcpy_backptr((uint8_t*)pbuf, 2, 2*buf_size);
1451  }
1452 }
1453 
1455 {
1456  uint8_t *dst;
1457  const uint8_t *src = (uint8_t*) ctx->frm0;
1458  int ret, height = ctx->height;
1459  ptrdiff_t dstpitch, srcpitch = ctx->pitch * (hdr ? sizeof(ctx->frm0[0]) : 1);
1460 
1461  if ((ret = ff_get_buffer(ctx->avctx, ctx->frame, 0)) < 0)
1462  return ret;
1463 
1464  dst = ctx->frame->data[0];
1465  dstpitch = ctx->frame->linesize[0];
1466 
1467  while (height--) {
1468  memcpy(dst, src, srcpitch);
1469  src += srcpitch;
1470  dst += dstpitch;
1471  }
1472 
1473  return 0;
1474 }
1475 
1477  int *got_frame_ptr, AVPacket *pkt)
1478 {
1479  SANMVideoContext *ctx = avctx->priv_data;
1480  int i, ret;
1481 
1482  ctx->frame = frame;
1483  bytestream2_init(&ctx->gb, pkt->data, pkt->size);
1484 
1485  if (!ctx->version) {
1486  int to_store = 0;
1487 
1488  while (bytestream2_get_bytes_left(&ctx->gb) >= 8) {
1489  uint32_t sig, size;
1490  int pos;
1491 
1492  sig = bytestream2_get_be32u(&ctx->gb);
1493  size = bytestream2_get_be32u(&ctx->gb);
1494  pos = bytestream2_tell(&ctx->gb);
1495 
1496  if (bytestream2_get_bytes_left(&ctx->gb) < size) {
1497  av_log(avctx, AV_LOG_ERROR, "Incorrect chunk size %"PRIu32".\n", size);
1498  break;
1499  }
1500  switch (sig) {
1501  case MKBETAG('N', 'P', 'A', 'L'):
1502  if (size != PALETTE_SIZE * 3) {
1503  av_log(avctx, AV_LOG_ERROR,
1504  "Incorrect palette block size %"PRIu32".\n", size);
1505  return AVERROR_INVALIDDATA;
1506  }
1507  for (i = 0; i < PALETTE_SIZE; i++)
1508  ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb);
1509  break;
1510  case MKBETAG('F', 'O', 'B', 'J'):
1511  if (size < 16)
1512  return AVERROR_INVALIDDATA;
1513  if (ret = process_frame_obj(ctx))
1514  return ret;
1515  break;
1516  case MKBETAG('X', 'P', 'A', 'L'):
1517  if (ret = process_xpal(ctx, size))
1518  return ret;
1519  break;
1520  case MKBETAG('S', 'T', 'O', 'R'):
1521  to_store = 1;
1522  break;
1523  case MKBETAG('F', 'T', 'C', 'H'):
1524  memcpy(ctx->frm0, ctx->stored_frame, ctx->buf_size);
1525  break;
1526  default:
1527  bytestream2_skip(&ctx->gb, size);
1528  av_log(avctx, AV_LOG_DEBUG,
1529  "Unknown/unsupported chunk %"PRIx32".\n", sig);
1530  break;
1531  }
1532 
1533  bytestream2_seek(&ctx->gb, pos + size, SEEK_SET);
1534  if (size & 1)
1535  bytestream2_skip(&ctx->gb, 1);
1536  }
1537  if (to_store)
1538  memcpy(ctx->stored_frame, ctx->frm0, ctx->buf_size);
1539  if ((ret = copy_output(ctx, NULL)))
1540  return ret;
1541  memcpy(ctx->frame->data[1], ctx->pal, 1024);
1542  } else {
1544 
1545  if ((ret = read_frame_header(ctx, &header)))
1546  return ret;
1547 
1548  ctx->rotate_code = header.rotate_code;
1549  if (!header.seq_num) {
1550  ctx->frame->flags |= AV_FRAME_FLAG_KEY;
1551  ctx->frame->pict_type = AV_PICTURE_TYPE_I;
1552  fill_frame(ctx->frm1, ctx->npixels, header.bg_color);
1553  fill_frame(ctx->frm2, ctx->npixels, header.bg_color);
1554  } else {
1555  ctx->frame->flags &= ~AV_FRAME_FLAG_KEY;
1556  ctx->frame->pict_type = AV_PICTURE_TYPE_P;
1557  }
1558 
1559  if (header.codec < FF_ARRAY_ELEMS(v1_decoders)) {
1560  if ((ret = v1_decoders[header.codec](ctx))) {
1561  av_log(avctx, AV_LOG_ERROR,
1562  "Subcodec %d: error decoding frame.\n", header.codec);
1563  return ret;
1564  }
1565  } else {
1566  avpriv_request_sample(avctx, "Subcodec %d", header.codec);
1567  return AVERROR_PATCHWELCOME;
1568  }
1569 
1570  if ((ret = copy_output(ctx, &header)))
1571  return ret;
1572  }
1573  if (ctx->rotate_code)
1574  rotate_bufs(ctx, ctx->rotate_code);
1575 
1576  *got_frame_ptr = 1;
1577 
1578  return pkt->size;
1579 }
1580 
1582  .p.name = "sanm",
1583  CODEC_LONG_NAME("LucasArts SANM/Smush video"),
1584  .p.type = AVMEDIA_TYPE_VIDEO,
1585  .p.id = AV_CODEC_ID_SANM,
1586  .priv_data_size = sizeof(SANMVideoContext),
1587  .init = decode_init,
1588  .close = decode_end,
1590  .p.capabilities = AV_CODEC_CAP_DR1,
1591 };
SANMVideoContext::width
int width
Definition: sanm.c:272
codec47_read_interptable
static void codec47_read_interptable(SANMVideoContext *ctx)
Definition: sanm.c:860
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:215
AV_CODEC_ID_SANM
@ AV_CODEC_ID_SANM
Definition: codec_id.h:236
motion_vectors
static const int8_t motion_vectors[256][2]
Definition: sanm.c:53
decode_0
static int decode_0(SANMVideoContext *ctx)
Definition: sanm.c:1078
BOTTOM_EDGE
@ BOTTOM_EDGE
Definition: sanm.c:308
SANMVideoContext::rle_buf
uint8_t * rle_buf
Definition: sanm.c:282
decode_5
static int decode_5(SANMVideoContext *ctx)
Definition: sanm.c:1339
fill_block
static void fill_block(uint16_t *pdest, uint16_t color, int block_size, ptrdiff_t pitch)
Definition: sanm.c:1120
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:386
color
Definition: vf_paletteuse.c:513
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:770
GetByteContext
Definition: bytestream.h:33
SANMVideoContext::pal
uint32_t pal[PALETTE_SIZE]
Definition: sanm.c:268
SANMFrameHeader
Definition: sanm.c:297
SANMVideoContext::stored_frame
uint8_t * stored_frame
Definition: sanm.c:278
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:300
good_mvec
static int good_mvec(SANMVideoContext *ctx, int cx, int cy, int mx, int my, int block_size)
Definition: sanm.c:1214
out_size
int out_size
Definition: movenc.c:56
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:389
w
uint8_t w
Definition: llviddspenc.c:38
AVPacket::data
uint8_t * data
Definition: packet.h:539
decode_end
static av_cold int decode_end(AVCodecContext *avctx)
Definition: sanm.c:523
interp_point
static void interp_point(int8_t *points, int x0, int y0, int x1, int y1, int pos, int npoints)
Definition: sanm.c:366
FFCodec
Definition: codec_internal.h:127
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:1327
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:94
ff_sanm_decoder
const FFCodec ff_sanm_decoder
Definition: sanm.c:1581
old_codec37
static int old_codec37(SANMVideoContext *ctx, int top, int left, int width, int height)
Definition: sanm.c:624
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:298
mx
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t mx
Definition: dsp.h:53
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:131
LEFT_EDGE
@ LEFT_EDGE
Definition: sanm.c:305
old_codec47
static int old_codec47(SANMVideoContext *ctx, int top, int left, int width, int height)
Definition: sanm.c:909
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:298
SANMVideoContext::gb
GetByteContext gb
Definition: sanm.c:265
destroy_buffers
static void destroy_buffers(SANMVideoContext *ctx)
Definition: sanm.c:451
val
static double val(void *priv, double ch)
Definition: aeval.c:77
decode_2
static int decode_2(SANMVideoContext *ctx)
Definition: sanm.c:1315
SANMVideoContext::small_codebook
uint16_t small_codebook[4]
Definition: sanm.c:290
DIR_LEFT
@ DIR_LEFT
Definition: sanm.c:313
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:327
NO_EDGE
@ NO_EDGE
Definition: sanm.c:309
TOP_EDGE
@ TOP_EDGE
Definition: sanm.c:306
avassert.h
old_codec1
static int old_codec1(SANMVideoContext *ctx, int top, int left, int width, int height)
Definition: sanm.c:558
pkt
AVPacket * pkt
Definition: movenc.c:60
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:209
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:301
AV_FRAME_FLAG_KEY
#define AV_FRAME_FLAG_KEY
A flag to mark frames that are keyframes.
Definition: frame.h:640
av_memcpy_backptr
void av_memcpy_backptr(uint8_t *dst, int back, int cnt)
Overlapping memcpy() implementation.
Definition: mem.c:447
AVCodecContext::extradata_size
int extradata_size
Definition: avcodec.h:530
FF_CODEC_DECODE_CB
#define FF_CODEC_DECODE_CB(func)
Definition: codec_internal.h:311
SANMFrameHeader::rle_output_size
int rle_output_size
Definition: sanm.c:298
decode_6
static int decode_6(SANMVideoContext *ctx)
Definition: sanm.c:1362
AVFormatContext::flags
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1451
SANMVideoContext::npixels
long npixels
Definition: sanm.c:287
codec47_comp1
static void codec47_comp1(SANMVideoContext *ctx, uint8_t *dst_in, int width, int height, ptrdiff_t stride)
Definition: sanm.c:876
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:230
opcode_0xf8
static int opcode_0xf8(SANMVideoContext *ctx, int cx, int cy, int block_size, ptrdiff_t pitch)
Definition: sanm.c:1186
ctx
AVFormatContext * ctx
Definition: movenc.c:49
SANMVideoContext::stored_frame_size
uint32_t stored_frame_size
Definition: sanm.c:280
decode.h
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
CODEC_LONG_NAME
#define CODEC_LONG_NAME(str)
Definition: codec_internal.h:296
my
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t my
Definition: dsp.h:53
FFABS
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
Definition: common.h:74
if
if(ret)
Definition: filter_design.txt:179
GlyphEdge
GlyphEdge
Definition: sanm.c:304
init_sizes
static void init_sizes(SANMVideoContext *ctx, int width, int height)
Definition: sanm.c:438
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:301
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:1130
AV_PICTURE_TYPE_I
@ AV_PICTURE_TYPE_I
Intra.
Definition: avutil.h:279
decode_nop
static int decode_nop(SANMVideoContext *ctx)
Definition: sanm.c:1095
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:482
SANMVideoContext::c47itbl
uint8_t c47itbl[0x10000]
Definition: sanm.c:294
index
int index
Definition: gxfenc.c:90
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
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:1697
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts.c:368
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:540
SANMVideoContext
Definition: sanm.c:263
height
#define height
Definition: dsp.h:85
codec37_mv
static void codec37_mv(uint8_t *dst, const uint8_t *src, int height, int stride, int x, int y)
Definition: sanm.c:605
codec_internal.h
glyph8_y
static const int8_t glyph8_y[GLYPH_COORD_VECT_SIZE]
Definition: sanm.c:49
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:83
decode_4
static int decode_4(SANMVideoContext *ctx)
Definition: sanm.c:1333
size
int size
Definition: twinvq_data.h:10344
color
static const uint32_t color[16+AV_CLASS_CATEGORY_NB]
Definition: log.c:94
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:68
decode_init
static av_cold int decode_init(AVCodecContext *avctx)
Definition: sanm.c:489
rle_decode
static int rle_decode(SANMVideoContext *ctx, uint8_t *dst, const int out_size)
Definition: sanm.c:532
PALETTE_DELTA
#define PALETTE_DELTA
Definition: sanm.c:35
flag
#define flag(name)
Definition: cbs_av1.c:474
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:67
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
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:1446
copy_block.h
copy_block
static void copy_block(uint16_t *pdest, uint16_t *psrc, int block_size, ptrdiff_t pitch)
Definition: sanm.c:1101
AVCodecContext::extradata
uint8_t * extradata
some codecs need / can use extradata like Huffman tables.
Definition: avcodec.h:529
process_xpal
static int process_xpal(SANMVideoContext *ctx, int size)
Definition: sanm.c:1039
SANMFrameHeader::seq_num
int seq_num
Definition: sanm.c:298
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:194
len
int len
Definition: vorbis_enc_data.h:426
AVCodecContext::height
int height
Definition: avcodec.h:624
AVCodecContext::pix_fmt
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:663
AV_PIX_FMT_RGB565
#define AV_PIX_FMT_RGB565
Definition: pixfmt.h:489
avcodec.h
stride
#define stride
Definition: h264pred_template.c:537
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:1406
GlyphDir
GlyphDir
Definition: sanm.c:312
AV_PIX_FMT_PAL8
@ AV_PIX_FMT_PAL8
8 bits with AV_PIX_FMT_RGB32 palette
Definition: pixfmt.h:84
DIR_DOWN
@ DIR_DOWN
Definition: sanm.c:316
ret
ret
Definition: filter_design.txt:187
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
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:264
SANMVideoContext::frm2
uint16_t * frm2
Definition: sanm.c:277
DIR_RIGHT
@ DIR_RIGHT
Definition: sanm.c:315
pos
unsigned int pos
Definition: spdifenc.c:414
process_frame_obj
static int process_frame_obj(SANMVideoContext *ctx)
Definition: sanm.c:998
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:217
AV_RL32
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_RL32
Definition: bytestream.h:92
U
#define U(x)
Definition: vpx_arith.h:37
GLYPH_COORD_VECT_SIZE
#define GLYPH_COORD_VECT_SIZE
Definition: sanm.c:33
AVCodecContext
main external API structure.
Definition: avcodec.h:451
copy_output
static int copy_output(SANMVideoContext *ctx, SANMFrameHeader *hdr)
Definition: sanm.c:1454
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:65
which_direction
static enum GlyphDir which_direction(enum GlyphEdge edge0, enum GlyphEdge edge1)
Definition: sanm.c:343
av_clip_uint8
#define av_clip_uint8
Definition: common.h:106
RIGHT_EDGE
@ RIGHT_EDGE
Definition: sanm.c:307
AV_PICTURE_TYPE_P
@ AV_PICTURE_TYPE_P
Predicted.
Definition: avutil.h:280
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
SANMVideoContext::p8x8glyphs
int8_t p8x8glyphs[NGLYPHS][64]
Definition: sanm.c:293
mem.h
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:36
opcode_0xf7
static int opcode_0xf7(SANMVideoContext *ctx, int cx, int cy, int block_size, ptrdiff_t pitch)
Definition: sanm.c:1152
FFALIGN
#define FFALIGN(x, a)
Definition: macros.h:78
AVPacket
This structure stores compressed data.
Definition: packet.h:516
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:478
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
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:557
codec2subblock
static int codec2subblock(SANMVideoContext *ctx, int cx, int cy, int blk_size)
Definition: sanm.c:1230
frm_decoder
int(* frm_decoder)(SANMVideoContext *ctx)
Definition: sanm.c:1399
AVCodecContext::width
int width
picture width / height.
Definition: avcodec.h:624
bytestream.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:482
DIR_UP
@ DIR_UP
Definition: sanm.c:314
v1_decoders
static const frm_decoder v1_decoders[]
Definition: sanm.c:1401
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
h
h
Definition: vp9dsp_template.c:2070
SANMVideoContext::delta_pal
int16_t delta_pal[PALETTE_DELTA]
Definition: sanm.c:269
NO_DIR
@ NO_DIR
Definition: sanm.c:317
width
#define width
Definition: dsp.h:85
av_bswap16
#define av_bswap16
Definition: bswap.h:28
SANMVideoContext::rotate_code
int rotate_code
Definition: sanm.c:285
SANMVideoContext::pitch
ptrdiff_t pitch
Definition: sanm.c:271
skip
static void BS_FUNC() skip(BSCTX *bc, unsigned int n)
Skip n bits in the buffer.
Definition: bitstream_template.h:375
src
#define src
Definition: vp8dsp.c:248
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:1377
decode_frame
static int decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame_ptr, AVPacket *pkt)
Definition: sanm.c:1476
init_buffers
static av_cold int init_buffers(SANMVideoContext *ctx)
Definition: sanm.c:464