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