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 
998 // scale 4x4 input block to an 8x8 output block
999 static void c48_4to8(uint8_t *dst, const uint8_t *src, const uint16_t w)
1000 {
1001  uint16_t p;
1002  // dst is always at least 16bit aligned
1003  for (int i = 0; i < 4; i++) {
1004  for (int j = 0; j < 8; j += 2) {
1005  p = *src++;
1006  p = (p << 8) | p;
1007  *((uint16_t *)(dst + w * 0 + j)) = p;
1008  *((uint16_t *)(dst + w * 1 + j)) = p;
1009  }
1010  dst += w * 2;
1011  }
1012 }
1013 
1014 static int codec48_block(SANMVideoContext *ctx, uint8_t *dst, uint8_t *db,
1015  const uint16_t w)
1016 {
1017  uint8_t opc, sb[16];
1018  int i, j, k, l;
1019  int16_t mvofs;
1020  uint32_t ofs;
1021 
1022  if (bytestream2_get_bytes_left(&ctx->gb) < 1)
1023  return 1;
1024 
1025  opc = bytestream2_get_byteu(&ctx->gb);
1026  switch (opc) {
1027  case 0xFF: // 1x1 -> 8x8 block scale
1028  if (bytestream2_get_bytes_left(&ctx->gb) < 1)
1029  return 1;
1030 
1031  opc = bytestream2_get_byteu(&ctx->gb);
1032  for (i = 0; i < 16; i++)
1033  sb[i] = opc;
1034  c48_4to8(dst, sb, w);
1035  break;
1036  case 0xFE: // 1x 8x8 copy from deltabuf, 16bit mv from source
1037  if (bytestream2_get_bytes_left(&ctx->gb) < 2)
1038  return 1;
1039  mvofs = bytestream2_get_le16(&ctx->gb);
1040  for (i = 0; i < 8; i++) {
1041  ofs = w * i;
1042  for (k = 0; k < 8; k++)
1043  *(dst + ofs + k) = *(db + ofs + k + mvofs);
1044  }
1045  break;
1046  case 0xFD: // 2x2 -> 8x8 block scale
1047  if (bytestream2_get_bytes_left(&ctx->gb) < 4)
1048  return 1;
1049  sb[ 5] = bytestream2_get_byteu(&ctx->gb);
1050  sb[ 7] = bytestream2_get_byteu(&ctx->gb);
1051  sb[13] = bytestream2_get_byteu(&ctx->gb);
1052  sb[15] = bytestream2_get_byteu(&ctx->gb);
1053 
1054  sb[0] = sb[1] = sb[4] = sb[5];
1055  sb[2] = sb[3] = sb[6] = sb[7];
1056  sb[8] = sb[9] = sb[12] = sb[13];
1057  sb[10] = sb[11] = sb[14] = sb[15];
1058  c48_4to8(dst, sb, w);
1059  break;
1060  case 0xFC: // 4x copy 4x4 block, per-block c37_mv from source
1061  if (bytestream2_get_bytes_left(&ctx->gb) < 4)
1062  return 1;
1063  for (i = 0; i < 8; i += 4) {
1064  for (k = 0; k < 8; k += 4) {
1065  opc = bytestream2_get_byteu(&ctx->gb);
1066  mvofs = c37_mv[opc * 2] + (c37_mv[opc * 2 + 1] * w);
1067  for (j = 0; j < 4; j++) {
1068  ofs = (w * (j + i)) + k;
1069  for (l = 0; l < 4; l++)
1070  *(dst + ofs + l) = *(db + ofs + l + mvofs);
1071  }
1072  }
1073  }
1074  break;
1075  case 0xFB: // Copy 4x 4x4 blocks, per-block mv from source
1076  if (bytestream2_get_bytes_left(&ctx->gb) < 8)
1077  return 1;
1078  for (i = 0; i < 8; i += 4) {
1079  for (k = 0; k < 8; k += 4) {
1080  mvofs = bytestream2_get_le16(&ctx->gb);
1081  for (j = 0; j < 4; j++) {
1082  ofs = (w * (j + i)) + k;
1083  for (l = 0; l < 4; l++)
1084  *(dst + ofs + l) = *(db + ofs + l + mvofs);
1085  }
1086  }
1087  }
1088  break;
1089  case 0xFA: // scale 4x4 input block to 8x8 dest block
1090  if (bytestream2_get_bytes_left(&ctx->gb) < 16)
1091  return 1;
1092  bytestream2_get_bufferu(&ctx->gb, sb, 16);
1093  c48_4to8(dst, sb, w);
1094  break;
1095  case 0xF9: // 16x 2x2 copy from delta, per-block c37_mv from source
1096  if (bytestream2_get_bytes_left(&ctx->gb) < 16)
1097  return 1;
1098  for (i = 0; i < 8; i += 2) {
1099  for (j = 0; j < 8; j += 2) {
1100  ofs = (w * i) + j;
1101  opc = bytestream2_get_byteu(&ctx->gb);
1102  mvofs = c37_mv[opc * 2] + (c37_mv[opc * 2 + 1] * w);
1103  for (l = 0; l < 2; l++) {
1104  *(dst + ofs + l + 0) = *(db + ofs + l + 0 + mvofs);
1105  *(dst + ofs + l + w) = *(db + ofs + l + w + mvofs);
1106  }
1107  }
1108  }
1109  break;
1110  case 0xF8: // 16x 2x2 blocks copy, 16bit mv from source
1111  if (bytestream2_get_bytes_left(&ctx->gb) < 32)
1112  return 1;
1113  for (i = 0; i < 8; i += 2) {
1114  for (j = 0; j < 8; j += 2) {
1115  ofs = w * i + j;
1116  mvofs = bytestream2_get_le16(&ctx->gb);
1117  for (l = 0; l < 2; l++) {
1118  *(dst + ofs + l + 0) = *(db + ofs + l + 0 + mvofs);
1119  *(dst + ofs + l + w) = *(db + ofs + l + w + mvofs);
1120  }
1121  }
1122  }
1123  break;
1124  case 0xF7: // copy 8x8 block from src to dest
1125  if (bytestream2_get_bytes_left(&ctx->gb) < 64)
1126  return 1;
1127  for (i = 0; i < 8; i++) {
1128  ofs = i * w;
1129  for (l = 0; l < 8; l++)
1130  *(dst + ofs + l) = bytestream2_get_byteu(&ctx->gb);
1131  }
1132  break;
1133  default: // copy 8x8 block from prev, c37_mv from source
1134  mvofs = c37_mv[opc * 2] + (c37_mv[opc * 2 + 1] * w);
1135  for (i = 0; i < 8; i++) {
1136  ofs = i * w;
1137  for (l = 0; l < 8; l++)
1138  *(dst + ofs + l) = *(db + ofs + l + mvofs);
1139  }
1140  break;
1141  }
1142  return 0;
1143 }
1144 
1146 {
1147  uint8_t *dst, *prev;
1148  int compr = bytestream2_get_byte(&ctx->gb);
1149  int mvidx = bytestream2_get_byte(&ctx->gb);
1150  int seq = bytestream2_get_le16(&ctx->gb);
1151  uint32_t decoded_size = bytestream2_get_le32(&ctx->gb);
1152  int i, j, flags;
1153 
1154  // all codec48 videos use 1, but just to be safe...
1155  if (mvidx != 1) {
1156  av_log(ctx->avctx, AV_LOG_ERROR, "Invalid motion base value %d.\n", mvidx);
1157  return AVERROR_INVALIDDATA;
1158  }
1159 
1160  bytestream2_skip(&ctx->gb, 4);
1161  flags = bytestream2_get_byte(&ctx->gb);
1162  bytestream2_skip(&ctx->gb, 3);
1163 
1164  if (flags & 8) {
1165  if (bytestream2_get_bytes_left(&ctx->gb) < 0x8080)
1166  return AVERROR_INVALIDDATA;
1168  }
1169 
1170  dst = (uint8_t*)ctx->frm0;
1171  prev = (uint8_t*)ctx->frm2;
1172 
1173  if (!seq) {
1174  ctx->prev_seq = -1;
1175  memset(prev, 0, ctx->aligned_height * width);
1176  }
1177 
1178  switch (compr) {
1179  case 0:
1181  return AVERROR_INVALIDDATA;
1182  for (j = 0; j < height; j++) {
1184  dst += width;
1185  }
1186  break;
1187  case 2:
1188  if (rle_decode(ctx, dst, decoded_size))
1189  return AVERROR_INVALIDDATA;
1190  break;
1191  case 3:
1192  if (seq == ctx->prev_seq + 1) {
1193  for (j = 0; j < height; j += 8) {
1194  for (i = 0; i < width; i += 8) {
1195  if (codec48_block(ctx, dst + i, prev + i, width))
1196  return AVERROR_INVALIDDATA;
1197  }
1198  dst += width * 8;
1199  prev += width * 8;
1200  }
1201  }
1202  break;
1203  case 5:
1204  if (bytestream2_get_bytes_left(&ctx->gb) < ((width + 1) >> 1) * ((height + 1) >> 1))
1205  return AVERROR_INVALIDDATA;
1207  break;
1208 
1209  default:
1211  "Subcodec 48 compression %d", compr);
1212  return AVERROR_PATCHWELCOME;
1213  }
1214  ctx->rotate_code = 1; // swap frm[0] and frm[2]
1215  ctx->prev_seq = seq;
1216  return 0;
1217 }
1218 
1220 {
1221  uint16_t codec = bytestream2_get_le16u(&ctx->gb);
1222  uint16_t left = bytestream2_get_le16u(&ctx->gb);
1223  uint16_t top = bytestream2_get_le16u(&ctx->gb);
1224  uint16_t w = bytestream2_get_le16u(&ctx->gb);
1225  uint16_t h = bytestream2_get_le16u(&ctx->gb);
1226 
1227  if (!w || !h) {
1228  av_log(ctx->avctx, AV_LOG_ERROR, "Dimensions are invalid.\n");
1229  return AVERROR_INVALIDDATA;
1230  }
1231 
1232  if (ctx->width < left + w || ctx->height < top + h) {
1233  int ret = ff_set_dimensions(ctx->avctx, FFMAX(left + w, ctx->width),
1234  FFMAX(top + h, ctx->height));
1235  if (ret < 0)
1236  return ret;
1237  init_sizes(ctx, FFMAX(left + w, ctx->width),
1238  FFMAX(top + h, ctx->height));
1239  if (init_buffers(ctx)) {
1240  av_log(ctx->avctx, AV_LOG_ERROR, "Error resizing buffers.\n");
1241  return AVERROR(ENOMEM);
1242  }
1243  }
1244  bytestream2_skip(&ctx->gb, 4);
1245 
1246  switch (codec) {
1247  case 1:
1248  case 3:
1249  return old_codec1(ctx, top, left, w, h);
1250  case 37:
1251  return old_codec37(ctx, top, left, w, h);
1252  case 47:
1253  return old_codec47(ctx, top, left, w, h);
1254  case 48:
1255  return old_codec48(ctx, w, h);
1256  default:
1257  avpriv_request_sample(ctx->avctx, "Subcodec %d", codec);
1258  return AVERROR_PATCHWELCOME;
1259  }
1260 }
1261 
1263 {
1264  int16_t *dp = ctx->delta_pal;
1265  uint32_t *pal = ctx->pal;
1266  uint16_t cmd;
1267  uint8_t c[3];
1268  int i, j;
1269 
1270  bytestream2_skip(&ctx->gb, 2);
1271  cmd = bytestream2_get_be16(&ctx->gb);
1272 
1273  if (cmd == 1) {
1274  for (i = 0; i < PALETTE_DELTA; i += 3) {
1275  c[0] = (*pal >> 16) & 0xFF;
1276  c[1] = (*pal >> 8) & 0xFF;
1277  c[2] = (*pal >> 0) & 0xFF;
1278  for (j = 0; j < 3; j++) {
1279  int cl = (c[j] * 129) + *dp++;
1280  c[j] = av_clip_uint8(cl / 128) & 0xFF;
1281  }
1282  *pal++ = 0xFFU << 24 | c[0] << 16 | c[1] << 8 | c[2];
1283  }
1284  } else if (cmd == 2) {
1285  if (size < PALETTE_DELTA * 2 + 4) {
1286  av_log(ctx->avctx, AV_LOG_ERROR,
1287  "Incorrect palette change block size %"PRIu32".\n", size);
1288  return AVERROR_INVALIDDATA;
1289  }
1290  for (i = 0; i < PALETTE_DELTA; i++)
1291  dp[i] = bytestream2_get_le16u(&ctx->gb);
1292 
1293  if (size >= PALETTE_DELTA * 2 + 4 + PALETTE_SIZE * 3) {
1294  for (i = 0; i < PALETTE_SIZE; i++)
1295  ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb);
1296  }
1297  }
1298  return 0;
1299 }
1300 
1302 {
1303  uint16_t *frm = ctx->frm0;
1304  int x, y;
1305 
1306  if (bytestream2_get_bytes_left(&ctx->gb) < ctx->width * ctx->height * 2) {
1307  av_log(ctx->avctx, AV_LOG_ERROR, "Insufficient data for raw frame.\n");
1308  return AVERROR_INVALIDDATA;
1309  }
1310  for (y = 0; y < ctx->height; y++) {
1311  for (x = 0; x < ctx->width; x++)
1312  frm[x] = bytestream2_get_le16u(&ctx->gb);
1313  frm += ctx->pitch;
1314  }
1315  return 0;
1316 }
1317 
1319 {
1320  avpriv_request_sample(ctx->avctx, "Unknown/unsupported compression type");
1321  return AVERROR_PATCHWELCOME;
1322 }
1323 
1324 static void copy_block(uint16_t *pdest, uint16_t *psrc, int block_size, ptrdiff_t pitch)
1325 {
1326  uint8_t *dst = (uint8_t *)pdest;
1327  uint8_t *src = (uint8_t *)psrc;
1328  ptrdiff_t stride = pitch * 2;
1329 
1330  switch (block_size) {
1331  case 2:
1332  copy_block4(dst, src, stride, stride, 2);
1333  break;
1334  case 4:
1335  copy_block8(dst, src, stride, stride, 4);
1336  break;
1337  case 8:
1338  copy_block16(dst, src, stride, stride, 8);
1339  break;
1340  }
1341 }
1342 
1343 static void fill_block(uint16_t *pdest, uint16_t color, int block_size, ptrdiff_t pitch)
1344 {
1345  int x, y;
1346 
1347  pitch -= block_size;
1348  for (y = 0; y < block_size; y++, pdest += pitch)
1349  for (x = 0; x < block_size; x++)
1350  *pdest++ = color;
1351 }
1352 
1353 static int draw_glyph(SANMVideoContext *ctx, uint16_t *dst, int index,
1354  uint16_t fg_color, uint16_t bg_color, int block_size,
1355  ptrdiff_t pitch)
1356 {
1357  int8_t *pglyph;
1358  uint16_t colors[2] = { fg_color, bg_color };
1359  int x, y;
1360 
1361  if (index >= NGLYPHS) {
1362  av_log(ctx->avctx, AV_LOG_ERROR, "Ignoring nonexistent glyph #%u.\n", index);
1363  return AVERROR_INVALIDDATA;
1364  }
1365 
1366  pglyph = block_size == 8 ? ctx->p8x8glyphs[index] : ctx->p4x4glyphs[index];
1367  pitch -= block_size;
1368 
1369  for (y = 0; y < block_size; y++, dst += pitch)
1370  for (x = 0; x < block_size; x++)
1371  *dst++ = colors[*pglyph++];
1372  return 0;
1373 }
1374 
1375 static int opcode_0xf7(SANMVideoContext *ctx, int cx, int cy, int block_size, ptrdiff_t pitch)
1376 {
1377  uint16_t *dst = ctx->frm0 + cx + cy * ctx->pitch;
1378 
1379  if (block_size == 2) {
1380  uint32_t indices;
1381 
1382  if (bytestream2_get_bytes_left(&ctx->gb) < 4)
1383  return AVERROR_INVALIDDATA;
1384 
1385  indices = bytestream2_get_le32u(&ctx->gb);
1386  dst[0] = ctx->codebook[indices & 0xFF];
1387  indices >>= 8;
1388  dst[1] = ctx->codebook[indices & 0xFF];
1389  indices >>= 8;
1390  dst[pitch] = ctx->codebook[indices & 0xFF];
1391  indices >>= 8;
1392  dst[pitch + 1] = ctx->codebook[indices & 0xFF];
1393  } else {
1394  uint16_t fgcolor, bgcolor;
1395  int glyph;
1396 
1397  if (bytestream2_get_bytes_left(&ctx->gb) < 3)
1398  return AVERROR_INVALIDDATA;
1399 
1400  glyph = bytestream2_get_byteu(&ctx->gb);
1401  bgcolor = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
1402  fgcolor = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
1403 
1404  draw_glyph(ctx, dst, glyph, fgcolor, bgcolor, block_size, pitch);
1405  }
1406  return 0;
1407 }
1408 
1409 static int opcode_0xf8(SANMVideoContext *ctx, int cx, int cy, int block_size, ptrdiff_t pitch)
1410 {
1411  uint16_t *dst = ctx->frm0 + cx + cy * ctx->pitch;
1412 
1413  if (block_size == 2) {
1414  if (bytestream2_get_bytes_left(&ctx->gb) < 8)
1415  return AVERROR_INVALIDDATA;
1416 
1417  dst[0] = bytestream2_get_le16u(&ctx->gb);
1418  dst[1] = bytestream2_get_le16u(&ctx->gb);
1419  dst[pitch] = bytestream2_get_le16u(&ctx->gb);
1420  dst[pitch + 1] = bytestream2_get_le16u(&ctx->gb);
1421  } else {
1422  uint16_t fgcolor, bgcolor;
1423  int glyph;
1424 
1425  if (bytestream2_get_bytes_left(&ctx->gb) < 5)
1426  return AVERROR_INVALIDDATA;
1427 
1428  glyph = bytestream2_get_byteu(&ctx->gb);
1429  bgcolor = bytestream2_get_le16u(&ctx->gb);
1430  fgcolor = bytestream2_get_le16u(&ctx->gb);
1431 
1432  draw_glyph(ctx, dst, glyph, fgcolor, bgcolor, block_size, pitch);
1433  }
1434  return 0;
1435 }
1436 
1437 static int good_mvec(SANMVideoContext *ctx, int cx, int cy, int mx, int my,
1438  int block_size)
1439 {
1440  int start_pos = cx + mx + (cy + my) * ctx->pitch;
1441  int end_pos = start_pos + (block_size - 1) * (ctx->pitch + 1);
1442 
1443  int good = start_pos >= 0 && end_pos < (ctx->buf_size >> 1);
1444 
1445  if (!good)
1446  av_log(ctx->avctx, AV_LOG_ERROR,
1447  "Ignoring invalid motion vector (%i, %i)->(%u, %u), block size = %u\n",
1448  cx + mx, cy + my, cx, cy, block_size);
1449 
1450  return good;
1451 }
1452 
1453 static int codec2subblock(SANMVideoContext *ctx, int cx, int cy, int blk_size)
1454 {
1455  int16_t mx, my, index;
1456  int opcode;
1457 
1458  if (bytestream2_get_bytes_left(&ctx->gb) < 1)
1459  return AVERROR_INVALIDDATA;
1460 
1461  opcode = bytestream2_get_byteu(&ctx->gb);
1462 
1463  switch (opcode) {
1464  default:
1465  mx = motion_vectors[opcode][0];
1466  my = motion_vectors[opcode][1];
1467 
1468  if (good_mvec(ctx, cx, cy, mx, my, blk_size)) {
1469  copy_block(ctx->frm0 + cx + ctx->pitch * cy,
1470  ctx->frm2 + cx + mx + ctx->pitch * (cy + my),
1471  blk_size, ctx->pitch);
1472  }
1473  break;
1474  case 0xF5:
1475  if (bytestream2_get_bytes_left(&ctx->gb) < 2)
1476  return AVERROR_INVALIDDATA;
1477  index = bytestream2_get_le16u(&ctx->gb);
1478 
1479  mx = index % ctx->width;
1480  my = index / ctx->width;
1481 
1482  if (good_mvec(ctx, cx, cy, mx, my, blk_size)) {
1483  copy_block(ctx->frm0 + cx + ctx->pitch * cy,
1484  ctx->frm2 + cx + mx + ctx->pitch * (cy + my),
1485  blk_size, ctx->pitch);
1486  }
1487  break;
1488  case 0xF6:
1489  copy_block(ctx->frm0 + cx + ctx->pitch * cy,
1490  ctx->frm1 + cx + ctx->pitch * cy,
1491  blk_size, ctx->pitch);
1492  break;
1493  case 0xF7:
1494  opcode_0xf7(ctx, cx, cy, blk_size, ctx->pitch);
1495  break;
1496 
1497  case 0xF8:
1498  opcode_0xf8(ctx, cx, cy, blk_size, ctx->pitch);
1499  break;
1500  case 0xF9:
1501  case 0xFA:
1502  case 0xFB:
1503  case 0xFC:
1504  fill_block(ctx->frm0 + cx + cy * ctx->pitch,
1505  ctx->small_codebook[opcode - 0xf9], blk_size, ctx->pitch);
1506  break;
1507  case 0xFD:
1508  if (bytestream2_get_bytes_left(&ctx->gb) < 1)
1509  return AVERROR_INVALIDDATA;
1510  fill_block(ctx->frm0 + cx + cy * ctx->pitch,
1511  ctx->codebook[bytestream2_get_byteu(&ctx->gb)], blk_size, ctx->pitch);
1512  break;
1513  case 0xFE:
1514  if (bytestream2_get_bytes_left(&ctx->gb) < 2)
1515  return AVERROR_INVALIDDATA;
1516  fill_block(ctx->frm0 + cx + cy * ctx->pitch,
1517  bytestream2_get_le16u(&ctx->gb), blk_size, ctx->pitch);
1518  break;
1519  case 0xFF:
1520  if (blk_size == 2) {
1521  opcode_0xf8(ctx, cx, cy, blk_size, ctx->pitch);
1522  } else {
1523  blk_size >>= 1;
1524  if (codec2subblock(ctx, cx, cy, blk_size))
1525  return AVERROR_INVALIDDATA;
1526  if (codec2subblock(ctx, cx + blk_size, cy, blk_size))
1527  return AVERROR_INVALIDDATA;
1528  if (codec2subblock(ctx, cx, cy + blk_size, blk_size))
1529  return AVERROR_INVALIDDATA;
1530  if (codec2subblock(ctx, cx + blk_size, cy + blk_size, blk_size))
1531  return AVERROR_INVALIDDATA;
1532  }
1533  break;
1534  }
1535  return 0;
1536 }
1537 
1539 {
1540  int cx, cy, ret;
1541 
1542  for (cy = 0; cy < ctx->aligned_height; cy += 8)
1543  for (cx = 0; cx < ctx->aligned_width; cx += 8)
1544  if (ret = codec2subblock(ctx, cx, cy, 8))
1545  return ret;
1546 
1547  return 0;
1548 }
1549 
1551 {
1552  memcpy(ctx->frm0, ctx->frm2, ctx->frm2_size);
1553  return 0;
1554 }
1555 
1557 {
1558  memcpy(ctx->frm0, ctx->frm1, ctx->frm1_size);
1559  return 0;
1560 }
1561 
1563 {
1564 #if HAVE_BIGENDIAN
1565  uint16_t *frm;
1566  int npixels;
1567 #endif
1568  uint8_t *dst = (uint8_t*)ctx->frm0;
1569 
1570  if (rle_decode(ctx, dst, ctx->buf_size))
1571  return AVERROR_INVALIDDATA;
1572 
1573 #if HAVE_BIGENDIAN
1574  npixels = ctx->npixels;
1575  frm = ctx->frm0;
1576  while (npixels--) {
1577  *frm = av_bswap16(*frm);
1578  frm++;
1579  }
1580 #endif
1581 
1582  return 0;
1583 }
1584 
1586 {
1587  int npixels = ctx->npixels;
1588  uint16_t *frm = ctx->frm0;
1589 
1590  if (bytestream2_get_bytes_left(&ctx->gb) < npixels) {
1591  av_log(ctx->avctx, AV_LOG_ERROR, "Insufficient data for frame.\n");
1592  return AVERROR_INVALIDDATA;
1593  }
1594  while (npixels--)
1595  *frm++ = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
1596 
1597  return 0;
1598 }
1599 
1601 {
1602  uint16_t *pdest = ctx->frm0;
1603  uint8_t *rsrc;
1604  long npixels = ctx->npixels;
1605 
1606  av_fast_malloc(&ctx->rle_buf, &ctx->rle_buf_size, npixels);
1607  if (!ctx->rle_buf) {
1608  av_log(ctx->avctx, AV_LOG_ERROR, "RLE buffer allocation failed.\n");
1609  return AVERROR(ENOMEM);
1610  }
1611  rsrc = ctx->rle_buf;
1612 
1613  if (rle_decode(ctx, rsrc, npixels))
1614  return AVERROR_INVALIDDATA;
1615 
1616  while (npixels--)
1617  *pdest++ = ctx->codebook[*rsrc++];
1618 
1619  return 0;
1620 }
1621 
1623 
1624 static const frm_decoder v1_decoders[] = {
1627 };
1628 
1630 {
1631  int i, ret;
1632 
1633  if ((ret = bytestream2_get_bytes_left(&ctx->gb)) < 560) {
1634  av_log(ctx->avctx, AV_LOG_ERROR, "Input frame too short (%d bytes).\n",
1635  ret);
1636  return AVERROR_INVALIDDATA;
1637  }
1638  bytestream2_skip(&ctx->gb, 8); // skip pad
1639 
1640  hdr->width = bytestream2_get_le32u(&ctx->gb);
1641  hdr->height = bytestream2_get_le32u(&ctx->gb);
1642 
1643  if (hdr->width != ctx->width || hdr->height != ctx->height) {
1644  avpriv_report_missing_feature(ctx->avctx, "Variable size frames");
1645  return AVERROR_PATCHWELCOME;
1646  }
1647 
1648  hdr->seq_num = bytestream2_get_le16u(&ctx->gb);
1649  hdr->codec = bytestream2_get_byteu(&ctx->gb);
1650  hdr->rotate_code = bytestream2_get_byteu(&ctx->gb);
1651 
1652  bytestream2_skip(&ctx->gb, 4); // skip pad
1653 
1654  for (i = 0; i < 4; i++)
1655  ctx->small_codebook[i] = bytestream2_get_le16u(&ctx->gb);
1656  hdr->bg_color = bytestream2_get_le16u(&ctx->gb);
1657 
1658  bytestream2_skip(&ctx->gb, 2); // skip pad
1659 
1660  hdr->rle_output_size = bytestream2_get_le32u(&ctx->gb);
1661  for (i = 0; i < 256; i++)
1662  ctx->codebook[i] = bytestream2_get_le16u(&ctx->gb);
1663 
1664  bytestream2_skip(&ctx->gb, 8); // skip pad
1665 
1666  return 0;
1667 }
1668 
1669 static void fill_frame(uint16_t *pbuf, int buf_size, uint16_t color)
1670 {
1671  if (buf_size--) {
1672  *pbuf++ = color;
1673  av_memcpy_backptr((uint8_t*)pbuf, 2, 2*buf_size);
1674  }
1675 }
1676 
1678 {
1679  uint8_t *dst;
1680  const uint8_t *src = (uint8_t*) ctx->frm0;
1681  int ret, height = ctx->height;
1682  ptrdiff_t dstpitch, srcpitch = ctx->pitch * (hdr ? sizeof(ctx->frm0[0]) : 1);
1683 
1684  if ((ret = ff_get_buffer(ctx->avctx, ctx->frame, 0)) < 0)
1685  return ret;
1686 
1687  dst = ctx->frame->data[0];
1688  dstpitch = ctx->frame->linesize[0];
1689 
1690  while (height--) {
1691  memcpy(dst, src, srcpitch);
1692  src += srcpitch;
1693  dst += dstpitch;
1694  }
1695 
1696  return 0;
1697 }
1698 
1700  int *got_frame_ptr, AVPacket *pkt)
1701 {
1702  SANMVideoContext *ctx = avctx->priv_data;
1703  int i, ret;
1704 
1705  ctx->frame = frame;
1706  bytestream2_init(&ctx->gb, pkt->data, pkt->size);
1707 
1708  if (!ctx->version) {
1709  int to_store = 0;
1710 
1711  while (bytestream2_get_bytes_left(&ctx->gb) >= 8) {
1712  uint32_t sig, size;
1713  int pos;
1714 
1715  sig = bytestream2_get_be32u(&ctx->gb);
1716  size = bytestream2_get_be32u(&ctx->gb);
1717  pos = bytestream2_tell(&ctx->gb);
1718 
1719  if (bytestream2_get_bytes_left(&ctx->gb) < size) {
1720  av_log(avctx, AV_LOG_ERROR, "Incorrect chunk size %"PRIu32".\n", size);
1721  break;
1722  }
1723  switch (sig) {
1724  case MKBETAG('N', 'P', 'A', 'L'):
1725  if (size != PALETTE_SIZE * 3) {
1726  av_log(avctx, AV_LOG_ERROR,
1727  "Incorrect palette block size %"PRIu32".\n", size);
1728  return AVERROR_INVALIDDATA;
1729  }
1730  for (i = 0; i < PALETTE_SIZE; i++)
1731  ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb);
1732  break;
1733  case MKBETAG('F', 'O', 'B', 'J'):
1734  if (size < 16)
1735  return AVERROR_INVALIDDATA;
1736  if (ret = process_frame_obj(ctx))
1737  return ret;
1738  break;
1739  case MKBETAG('X', 'P', 'A', 'L'):
1740  if (ret = process_xpal(ctx, size))
1741  return ret;
1742  break;
1743  case MKBETAG('S', 'T', 'O', 'R'):
1744  to_store = 1;
1745  break;
1746  case MKBETAG('F', 'T', 'C', 'H'):
1747  memcpy(ctx->frm0, ctx->stored_frame, ctx->buf_size);
1748  break;
1749  default:
1750  bytestream2_skip(&ctx->gb, size);
1751  av_log(avctx, AV_LOG_DEBUG,
1752  "Unknown/unsupported chunk %"PRIx32".\n", sig);
1753  break;
1754  }
1755 
1756  bytestream2_seek(&ctx->gb, pos + size, SEEK_SET);
1757  if (size & 1)
1758  bytestream2_skip(&ctx->gb, 1);
1759  }
1760  if (to_store)
1761  memcpy(ctx->stored_frame, ctx->frm0, ctx->buf_size);
1762  if ((ret = copy_output(ctx, NULL)))
1763  return ret;
1764  memcpy(ctx->frame->data[1], ctx->pal, 1024);
1765  } else {
1767 
1768  if ((ret = read_frame_header(ctx, &header)))
1769  return ret;
1770 
1771  ctx->rotate_code = header.rotate_code;
1772  if (!header.seq_num) {
1773  ctx->frame->flags |= AV_FRAME_FLAG_KEY;
1774  ctx->frame->pict_type = AV_PICTURE_TYPE_I;
1775  fill_frame(ctx->frm1, ctx->npixels, header.bg_color);
1776  fill_frame(ctx->frm2, ctx->npixels, header.bg_color);
1777  } else {
1778  ctx->frame->flags &= ~AV_FRAME_FLAG_KEY;
1779  ctx->frame->pict_type = AV_PICTURE_TYPE_P;
1780  }
1781 
1782  if (header.codec < FF_ARRAY_ELEMS(v1_decoders)) {
1783  if ((ret = v1_decoders[header.codec](ctx))) {
1784  av_log(avctx, AV_LOG_ERROR,
1785  "Subcodec %d: error decoding frame.\n", header.codec);
1786  return ret;
1787  }
1788  } else {
1789  avpriv_request_sample(avctx, "Subcodec %d", header.codec);
1790  return AVERROR_PATCHWELCOME;
1791  }
1792 
1793  if ((ret = copy_output(ctx, &header)))
1794  return ret;
1795  }
1796  if (ctx->rotate_code)
1797  rotate_bufs(ctx, ctx->rotate_code);
1798 
1799  *got_frame_ptr = 1;
1800 
1801  return pkt->size;
1802 }
1803 
1805  .p.name = "sanm",
1806  CODEC_LONG_NAME("LucasArts SANM/Smush video"),
1807  .p.type = AVMEDIA_TYPE_VIDEO,
1808  .p.id = AV_CODEC_ID_SANM,
1809  .priv_data_size = sizeof(SANMVideoContext),
1810  .init = decode_init,
1811  .close = decode_end,
1813  .p.capabilities = AV_CODEC_CAP_DR1,
1814 };
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:1301
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:1562
fill_block
static void fill_block(uint16_t *pdest, uint16_t color, int block_size, ptrdiff_t pitch)
Definition: sanm.c:1343
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:1437
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:403
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:1550
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:1804
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:1538
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:654
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:538
codec48_block
static int codec48_block(SANMVideoContext *ctx, uint8_t *dst, uint8_t *db, const uint16_t w)
Definition: sanm.c:1014
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:1585
AVFormatContext::flags
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1451
c48_4to8
static void c48_4to8(uint8_t *dst, const uint8_t *src, const uint16_t w)
Definition: sanm.c:999
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:1409
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:1353
AV_PICTURE_TYPE_I
@ AV_PICTURE_TYPE_I
Intra.
Definition: avutil.h:279
decode_nop
static int decode_nop(SANMVideoContext *ctx)
Definition: sanm.c:1318
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:1556
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:1669
copy_block.h
copy_block
static void copy_block(uint16_t *pdest, uint16_t *psrc, int block_size, ptrdiff_t pitch)
Definition: sanm.c:1324
AVCodecContext::extradata
uint8_t * extradata
Out-of-band global headers that may be used by some codecs.
Definition: avcodec.h:537
process_xpal
static int process_xpal(SANMVideoContext *ctx, int size)
Definition: sanm.c:1262
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:632
AVCodecContext::pix_fmt
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:671
AV_PIX_FMT_RGB565
#define AV_PIX_FMT_RGB565
Definition: pixfmt.h:489
avcodec.h
stride
#define stride
Definition: h264pred_template.c:536
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:1629
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:1219
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:1677
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
old_codec48
static int old_codec48(SANMVideoContext *ctx, int width, int height)
Definition: sanm.c:1145
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:1375
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:1453
frm_decoder
int(* frm_decoder)(SANMVideoContext *ctx)
Definition: sanm.c:1622
AVCodecContext::width
int width
picture width / height.
Definition: avcodec.h:632
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:1624
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:1600
decode_frame
static int decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame_ptr, AVPacket *pkt)
Definition: sanm.c:1699
init_buffers
static av_cold int init_buffers(SANMVideoContext *ctx)
Definition: sanm.c:464