FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/sanm.c
Date: 2025-10-10 03:51:19
Exec Total Coverage
Lines: 336 1673 20.1%
Functions: 24 57 42.1%
Branches: 175 1241 14.1%

Line Branch Exec Source
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 /* codec47/bl16 motion vectors */
54 static const int8_t c47_mv[256][2] = {
55 { 0, 0 }, { -1, -43 }, { 6, -43 }, { -9, -42 }, { 13, -41 },
56 { -16, -40 }, { 19, -39 }, { -23, -36 }, { 26, -34 }, { -2, -33 },
57 { 4, -33 }, { -29, -32 }, { -9, -32 }, { 11, -31 }, { -16, -29 },
58 { 32, -29 }, { 18, -28 }, { -34, -26 }, { -22, -25 }, { -1, -25 },
59 { 3, -25 }, { -7, -24 }, { 8, -24 }, { 24, -23 }, { 36, -23 },
60 { -12, -22 }, { 13, -21 }, { -38, -20 }, { 0, -20 }, { -27, -19 },
61 { -4, -19 }, { 4, -19 }, { -17, -18 }, { -8, -17 }, { 8, -17 },
62 { 18, -17 }, { 28, -17 }, { 39, -17 }, { -12, -15 }, { 12, -15 },
63 { -21, -14 }, { -1, -14 }, { 1, -14 }, { -41, -13 }, { -5, -13 },
64 { 5, -13 }, { 21, -13 }, { -31, -12 }, { -15, -11 }, { -8, -11 },
65 { 8, -11 }, { 15, -11 }, { -2, -10 }, { 1, -10 }, { 31, -10 },
66 { -23, -9 }, { -11, -9 }, { -5, -9 }, { 4, -9 }, { 11, -9 },
67 { 42, -9 }, { 6, -8 }, { 24, -8 }, { -18, -7 }, { -7, -7 },
68 { -3, -7 }, { -1, -7 }, { 2, -7 }, { 18, -7 }, { -43, -6 },
69 { -13, -6 }, { -4, -6 }, { 4, -6 }, { 8, -6 }, { -33, -5 },
70 { -9, -5 }, { -2, -5 }, { 0, -5 }, { 2, -5 }, { 5, -5 },
71 { 13, -5 }, { -25, -4 }, { -6, -4 }, { -3, -4 }, { 3, -4 },
72 { 9, -4 }, { -19, -3 }, { -7, -3 }, { -4, -3 }, { -2, -3 },
73 { -1, -3 }, { 0, -3 }, { 1, -3 }, { 2, -3 }, { 4, -3 },
74 { 6, -3 }, { 33, -3 }, { -14, -2 }, { -10, -2 }, { -5, -2 },
75 { -3, -2 }, { -2, -2 }, { -1, -2 }, { 0, -2 }, { 1, -2 },
76 { 2, -2 }, { 3, -2 }, { 5, -2 }, { 7, -2 }, { 14, -2 },
77 { 19, -2 }, { 25, -2 }, { 43, -2 }, { -7, -1 }, { -3, -1 },
78 { -2, -1 }, { -1, -1 }, { 0, -1 }, { 1, -1 }, { 2, -1 },
79 { 3, -1 }, { 10, -1 }, { -5, 0 }, { -3, 0 }, { -2, 0 },
80 { -1, 0 }, { 1, 0 }, { 2, 0 }, { 3, 0 }, { 5, 0 },
81 { 7, 0 }, { -10, 1 }, { -7, 1 }, { -3, 1 }, { -2, 1 },
82 { -1, 1 }, { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 },
83 { -43, 2 }, { -25, 2 }, { -19, 2 }, { -14, 2 }, { -5, 2 },
84 { -3, 2 }, { -2, 2 }, { -1, 2 }, { 0, 2 }, { 1, 2 },
85 { 2, 2 }, { 3, 2 }, { 5, 2 }, { 7, 2 }, { 10, 2 },
86 { 14, 2 }, { -33, 3 }, { -6, 3 }, { -4, 3 }, { -2, 3 },
87 { -1, 3 }, { 0, 3 }, { 1, 3 }, { 2, 3 }, { 4, 3 },
88 { 19, 3 }, { -9, 4 }, { -3, 4 }, { 3, 4 }, { 7, 4 },
89 { 25, 4 }, { -13, 5 }, { -5, 5 }, { -2, 5 }, { 0, 5 },
90 { 2, 5 }, { 5, 5 }, { 9, 5 }, { 33, 5 }, { -8, 6 },
91 { -4, 6 }, { 4, 6 }, { 13, 6 }, { 43, 6 }, { -18, 7 },
92 { -2, 7 }, { 0, 7 }, { 2, 7 }, { 7, 7 }, { 18, 7 },
93 { -24, 8 }, { -6, 8 }, { -42, 9 }, { -11, 9 }, { -4, 9 },
94 { 5, 9 }, { 11, 9 }, { 23, 9 }, { -31, 10 }, { -1, 10 },
95 { 2, 10 }, { -15, 11 }, { -8, 11 }, { 8, 11 }, { 15, 11 },
96 { 31, 12 }, { -21, 13 }, { -5, 13 }, { 5, 13 }, { 41, 13 },
97 { -1, 14 }, { 1, 14 }, { 21, 14 }, { -12, 15 }, { 12, 15 },
98 { -39, 17 }, { -28, 17 }, { -18, 17 }, { -8, 17 }, { 8, 17 },
99 { 17, 18 }, { -4, 19 }, { 0, 19 }, { 4, 19 }, { 27, 19 },
100 { 38, 20 }, { -13, 21 }, { 12, 22 }, { -36, 23 }, { -24, 23 },
101 { -8, 24 }, { 7, 24 }, { -3, 25 }, { 1, 25 }, { 22, 25 },
102 { 34, 26 }, { -18, 28 }, { -32, 29 }, { 16, 29 }, { -11, 31 },
103 { 9, 32 }, { 29, 32 }, { -4, 33 }, { 2, 33 }, { -26, 34 },
104 { 23, 36 }, { -19, 39 }, { 16, 40 }, { -13, 41 }, { 9, 42 },
105 { -6, 43 }, { 1, 43 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
106 };
107
108 /* codec37/48 motion vector tables: 3x 510 bytes/255 x-y pairs */
109 static const int8_t c37_mv[] = {
110 0, 0, 1, 0, 2, 0, 3, 0, 5, 0,
111 8, 0, 13, 0, 21, 0, -1, 0, -2, 0,
112 -3, 0, -5, 0, -8, 0, -13, 0, -17, 0,
113 -21, 0, 0, 1, 1, 1, 2, 1, 3, 1,
114 5, 1, 8, 1, 13, 1, 21, 1, -1, 1,
115 -2, 1, -3, 1, -5, 1, -8, 1, -13, 1,
116 -17, 1, -21, 1, 0, 2, 1, 2, 2, 2,
117 3, 2, 5, 2, 8, 2, 13, 2, 21, 2,
118 -1, 2, -2, 2, -3, 2, -5, 2, -8, 2,
119 -13, 2, -17, 2, -21, 2, 0, 3, 1, 3,
120 2, 3, 3, 3, 5, 3, 8, 3, 13, 3,
121 21, 3, -1, 3, -2, 3, -3, 3, -5, 3,
122 -8, 3, -13, 3, -17, 3, -21, 3, 0, 5,
123 1, 5, 2, 5, 3, 5, 5, 5, 8, 5,
124 13, 5, 21, 5, -1, 5, -2, 5, -3, 5,
125 -5, 5, -8, 5, -13, 5, -17, 5, -21, 5,
126 0, 8, 1, 8, 2, 8, 3, 8, 5, 8,
127 8, 8, 13, 8, 21, 8, -1, 8, -2, 8,
128 -3, 8, -5, 8, -8, 8, -13, 8, -17, 8,
129 -21, 8, 0, 13, 1, 13, 2, 13, 3, 13,
130 5, 13, 8, 13, 13, 13, 21, 13, -1, 13,
131 -2, 13, -3, 13, -5, 13, -8, 13, -13, 13,
132 -17, 13, -21, 13, 0, 21, 1, 21, 2, 21,
133 3, 21, 5, 21, 8, 21, 13, 21, 21, 21,
134 -1, 21, -2, 21, -3, 21, -5, 21, -8, 21,
135 -13, 21, -17, 21, -21, 21, 0, -1, 1, -1,
136 2, -1, 3, -1, 5, -1, 8, -1, 13, -1,
137 21, -1, -1, -1, -2, -1, -3, -1, -5, -1,
138 -8, -1, -13, -1, -17, -1, -21, -1, 0, -2,
139 1, -2, 2, -2, 3, -2, 5, -2, 8, -2,
140 13, -2, 21, -2, -1, -2, -2, -2, -3, -2,
141 -5, -2, -8, -2, -13, -2, -17, -2, -21, -2,
142 0, -3, 1, -3, 2, -3, 3, -3, 5, -3,
143 8, -3, 13, -3, 21, -3, -1, -3, -2, -3,
144 -3, -3, -5, -3, -8, -3, -13, -3, -17, -3,
145 -21, -3, 0, -5, 1, -5, 2, -5, 3, -5,
146 5, -5, 8, -5, 13, -5, 21, -5, -1, -5,
147 -2, -5, -3, -5, -5, -5, -8, -5, -13, -5,
148 -17, -5, -21, -5, 0, -8, 1, -8, 2, -8,
149 3, -8, 5, -8, 8, -8, 13, -8, 21, -8,
150 -1, -8, -2, -8, -3, -8, -5, -8, -8, -8,
151 -13, -8, -17, -8, -21, -8, 0, -13, 1, -13,
152 2, -13, 3, -13, 5, -13, 8, -13, 13, -13,
153 21, -13, -1, -13, -2, -13, -3, -13, -5, -13,
154 -8, -13, -13, -13, -17, -13, -21, -13, 0, -17,
155 1, -17, 2, -17, 3, -17, 5, -17, 8, -17,
156 13, -17, 21, -17, -1, -17, -2, -17, -3, -17,
157 -5, -17, -8, -17, -13, -17, -17, -17, -21, -17,
158 0, -21, 1, -21, 2, -21, 3, -21, 5, -21,
159 8, -21, 13, -21, 21, -21, -1, -21, -2, -21,
160 -3, -21, -5, -21, -8, -21, -13, -21, -17, -21,
161 0, 0, -8, -29, 8, -29, -18, -25, 17, -25,
162 0, -23, -6, -22, 6, -22, -13, -19, 12, -19,
163 0, -18, 25, -18, -25, -17, -5, -17, 5, -17,
164 -10, -15, 10, -15, 0, -14, -4, -13, 4, -13,
165 19, -13, -19, -12, -8, -11, -2, -11, 0, -11,
166 2, -11, 8, -11, -15, -10, -4, -10, 4, -10,
167 15, -10, -6, -9, -1, -9, 1, -9, 6, -9,
168 -29, -8, -11, -8, -8, -8, -3, -8, 3, -8,
169 8, -8, 11, -8, 29, -8, -5, -7, -2, -7,
170 0, -7, 2, -7, 5, -7, -22, -6, -9, -6,
171 -6, -6, -3, -6, -1, -6, 1, -6, 3, -6,
172 6, -6, 9, -6, 22, -6, -17, -5, -7, -5,
173 -4, -5, -2, -5, 0, -5, 2, -5, 4, -5,
174 7, -5, 17, -5, -13, -4, -10, -4, -5, -4,
175 -3, -4, -1, -4, 0, -4, 1, -4, 3, -4,
176 5, -4, 10, -4, 13, -4, -8, -3, -6, -3,
177 -4, -3, -3, -3, -2, -3, -1, -3, 0, -3,
178 1, -3, 2, -3, 4, -3, 6, -3, 8, -3,
179 -11, -2, -7, -2, -5, -2, -3, -2, -2, -2,
180 -1, -2, 0, -2, 1, -2, 2, -2, 3, -2,
181 5, -2, 7, -2, 11, -2, -9, -1, -6, -1,
182 -4, -1, -3, -1, -2, -1, -1, -1, 0, -1,
183 1, -1, 2, -1, 3, -1, 4, -1, 6, -1,
184 9, -1, -31, 0, -23, 0, -18, 0, -14, 0,
185 -11, 0, -7, 0, -5, 0, -4, 0, -3, 0,
186 -2, 0, -1, 0, 0, -31, 1, 0, 2, 0,
187 3, 0, 4, 0, 5, 0, 7, 0, 11, 0,
188 14, 0, 18, 0, 23, 0, 31, 0, -9, 1,
189 -6, 1, -4, 1, -3, 1, -2, 1, -1, 1,
190 0, 1, 1, 1, 2, 1, 3, 1, 4, 1,
191 6, 1, 9, 1, -11, 2, -7, 2, -5, 2,
192 -3, 2, -2, 2, -1, 2, 0, 2, 1, 2,
193 2, 2, 3, 2, 5, 2, 7, 2, 11, 2,
194 -8, 3, -6, 3, -4, 3, -2, 3, -1, 3,
195 0, 3, 1, 3, 2, 3, 3, 3, 4, 3,
196 6, 3, 8, 3, -13, 4, -10, 4, -5, 4,
197 -3, 4, -1, 4, 0, 4, 1, 4, 3, 4,
198 5, 4, 10, 4, 13, 4, -17, 5, -7, 5,
199 -4, 5, -2, 5, 0, 5, 2, 5, 4, 5,
200 7, 5, 17, 5, -22, 6, -9, 6, -6, 6,
201 -3, 6, -1, 6, 1, 6, 3, 6, 6, 6,
202 9, 6, 22, 6, -5, 7, -2, 7, 0, 7,
203 2, 7, 5, 7, -29, 8, -11, 8, -8, 8,
204 -3, 8, 3, 8, 8, 8, 11, 8, 29, 8,
205 -6, 9, -1, 9, 1, 9, 6, 9, -15, 10,
206 -4, 10, 4, 10, 15, 10, -8, 11, -2, 11,
207 0, 11, 2, 11, 8, 11, 19, 12, -19, 13,
208 -4, 13, 4, 13, 0, 14, -10, 15, 10, 15,
209 -5, 17, 5, 17, 25, 17, -25, 18, 0, 18,
210 -12, 19, 13, 19, -6, 22, 6, 22, 0, 23,
211 -17, 25, 18, 25, -8, 29, 8, 29, 0, 31,
212 0, 0, -6, -22, 6, -22, -13, -19, 12, -19,
213 0, -18, -5, -17, 5, -17, -10, -15, 10, -15,
214 0, -14, -4, -13, 4, -13, 19, -13, -19, -12,
215 -8, -11, -2, -11, 0, -11, 2, -11, 8, -11,
216 -15, -10, -4, -10, 4, -10, 15, -10, -6, -9,
217 -1, -9, 1, -9, 6, -9, -11, -8, -8, -8,
218 -3, -8, 0, -8, 3, -8, 8, -8, 11, -8,
219 -5, -7, -2, -7, 0, -7, 2, -7, 5, -7,
220 -22, -6, -9, -6, -6, -6, -3, -6, -1, -6,
221 1, -6, 3, -6, 6, -6, 9, -6, 22, -6,
222 -17, -5, -7, -5, -4, -5, -2, -5, -1, -5,
223 0, -5, 1, -5, 2, -5, 4, -5, 7, -5,
224 17, -5, -13, -4, -10, -4, -5, -4, -3, -4,
225 -2, -4, -1, -4, 0, -4, 1, -4, 2, -4,
226 3, -4, 5, -4, 10, -4, 13, -4, -8, -3,
227 -6, -3, -4, -3, -3, -3, -2, -3, -1, -3,
228 0, -3, 1, -3, 2, -3, 3, -3, 4, -3,
229 6, -3, 8, -3, -11, -2, -7, -2, -5, -2,
230 -4, -2, -3, -2, -2, -2, -1, -2, 0, -2,
231 1, -2, 2, -2, 3, -2, 4, -2, 5, -2,
232 7, -2, 11, -2, -9, -1, -6, -1, -5, -1,
233 -4, -1, -3, -1, -2, -1, -1, -1, 0, -1,
234 1, -1, 2, -1, 3, -1, 4, -1, 5, -1,
235 6, -1, 9, -1, -23, 0, -18, 0, -14, 0,
236 -11, 0, -7, 0, -5, 0, -4, 0, -3, 0,
237 -2, 0, -1, 0, 0, -23, 1, 0, 2, 0,
238 3, 0, 4, 0, 5, 0, 7, 0, 11, 0,
239 14, 0, 18, 0, 23, 0, -9, 1, -6, 1,
240 -5, 1, -4, 1, -3, 1, -2, 1, -1, 1,
241 0, 1, 1, 1, 2, 1, 3, 1, 4, 1,
242 5, 1, 6, 1, 9, 1, -11, 2, -7, 2,
243 -5, 2, -4, 2, -3, 2, -2, 2, -1, 2,
244 0, 2, 1, 2, 2, 2, 3, 2, 4, 2,
245 5, 2, 7, 2, 11, 2, -8, 3, -6, 3,
246 -4, 3, -3, 3, -2, 3, -1, 3, 0, 3,
247 1, 3, 2, 3, 3, 3, 4, 3, 6, 3,
248 8, 3, -13, 4, -10, 4, -5, 4, -3, 4,
249 -2, 4, -1, 4, 0, 4, 1, 4, 2, 4,
250 3, 4, 5, 4, 10, 4, 13, 4, -17, 5,
251 -7, 5, -4, 5, -2, 5, -1, 5, 0, 5,
252 1, 5, 2, 5, 4, 5, 7, 5, 17, 5,
253 -22, 6, -9, 6, -6, 6, -3, 6, -1, 6,
254 1, 6, 3, 6, 6, 6, 9, 6, 22, 6,
255 -5, 7, -2, 7, 0, 7, 2, 7, 5, 7,
256 -11, 8, -8, 8, -3, 8, 0, 8, 3, 8,
257 8, 8, 11, 8, -6, 9, -1, 9, 1, 9,
258 6, 9, -15, 10, -4, 10, 4, 10, 15, 10,
259 -8, 11, -2, 11, 0, 11, 2, 11, 8, 11,
260 19, 12, -19, 13, -4, 13, 4, 13, 0, 14,
261 -10, 15, 10, 15, -5, 17, 5, 17, 0, 18,
262 -12, 19, 13, 19, -6, 22, 6, 22, 0, 23,
263 };
264
265 typedef struct SANMVideoContext {
266 AVCodecContext *avctx;
267 GetByteContext gb;
268
269 int version, subversion, have_dimensions, first_fob;
270 uint32_t pal[PALETTE_SIZE];
271 int16_t delta_pal[PALETTE_DELTA], shift_pal[PALETTE_DELTA];
272
273 ptrdiff_t pitch;
274 int width, height;
275 int aligned_width, aligned_height;
276 int prev_seq;
277
278 AVFrame *frame;
279 uint16_t *fbuf, *frm0, *frm1, *frm2;
280 uint8_t *stored_frame;
281 uint32_t fbuf_size, frm0_size, frm1_size, frm2_size;
282 uint32_t stor_size;
283 uint32_t stored_frame_size;
284
285 uint8_t *rle_buf;
286 unsigned int rle_buf_size;
287
288 long npixels, buf_size;
289
290 uint16_t codebook[256];
291 uint16_t small_codebook[4];
292
293 int8_t p4x4glyphs[NGLYPHS][16];
294 int8_t p8x8glyphs[NGLYPHS][64];
295 uint8_t c47itbl[0x10000];
296 uint8_t c23lut[256];
297 uint8_t c4tbl[2][256][16];
298 uint16_t c4param;
299 uint8_t c47cb[4];
300 } SANMVideoContext;
301
302 enum GlyphEdge {
303 LEFT_EDGE,
304 TOP_EDGE,
305 RIGHT_EDGE,
306 BOTTOM_EDGE,
307 NO_EDGE
308 };
309
310 enum GlyphDir {
311 DIR_LEFT,
312 DIR_UP,
313 DIR_RIGHT,
314 DIR_DOWN,
315 NO_DIR
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 1632 static enum GlyphEdge which_edge(int x, int y, int edge_size)
326 {
327 1632 const int edge_max = edge_size - 1;
328
329
2/2
✓ Branch 0 taken 408 times.
✓ Branch 1 taken 1224 times.
1632 if (!y)
330 408 return BOTTOM_EDGE;
331
2/2
✓ Branch 0 taken 408 times.
✓ Branch 1 taken 816 times.
1224 else if (y == edge_max)
332 408 return TOP_EDGE;
333
2/2
✓ Branch 0 taken 306 times.
✓ Branch 1 taken 510 times.
816 else if (!x)
334 306 return LEFT_EDGE;
335
2/2
✓ Branch 0 taken 306 times.
✓ Branch 1 taken 204 times.
510 else if (x == edge_max)
336 306 return RIGHT_EDGE;
337 else
338 204 return NO_EDGE;
339 }
340
341 1536 static enum GlyphDir which_direction(enum GlyphEdge edge0, enum GlyphEdge edge1)
342 {
343
6/6
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 1248 times.
✓ Branch 2 taken 228 times.
✓ Branch 3 taken 60 times.
✓ Branch 4 taken 288 times.
✓ Branch 5 taken 1188 times.
1536 if ((edge0 == LEFT_EDGE && edge1 == RIGHT_EDGE) ||
344
4/4
✓ Branch 0 taken 228 times.
✓ Branch 1 taken 60 times.
✓ Branch 2 taken 384 times.
✓ Branch 3 taken 1032 times.
1476 (edge1 == LEFT_EDGE && edge0 == RIGHT_EDGE) ||
345
4/4
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 288 times.
✓ Branch 2 taken 288 times.
✓ Branch 3 taken 840 times.
1416 (edge0 == BOTTOM_EDGE && edge1 != TOP_EDGE) ||
346
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 96 times.
288 (edge1 == BOTTOM_EDGE && edge0 != TOP_EDGE))
347 600 return DIR_UP;
348
6/6
✓ Branch 0 taken 384 times.
✓ Branch 1 taken 552 times.
✓ Branch 2 taken 96 times.
✓ Branch 3 taken 288 times.
✓ Branch 4 taken 288 times.
✓ Branch 5 taken 360 times.
936 else if ((edge0 == TOP_EDGE && edge1 != BOTTOM_EDGE) ||
349
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 96 times.
288 (edge1 == TOP_EDGE && edge0 != BOTTOM_EDGE))
350 480 return DIR_DOWN;
351
5/6
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 372 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 84 times.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 348 times.
456 else if ((edge0 == LEFT_EDGE && edge1 != RIGHT_EDGE) ||
352
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 (edge1 == LEFT_EDGE && edge0 != RIGHT_EDGE))
353 108 return DIR_LEFT;
354
5/6
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 252 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 96 times.
✓ Branch 4 taken 96 times.
✓ Branch 5 taken 156 times.
348 else if ((edge0 == TOP_EDGE && edge1 == BOTTOM_EDGE) ||
355
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 96 times.
✓ Branch 2 taken 84 times.
✓ Branch 3 taken 72 times.
252 (edge1 == TOP_EDGE && edge0 == BOTTOM_EDGE) ||
356
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 48 times.
156 (edge0 == RIGHT_EDGE && edge1 != LEFT_EDGE) ||
357
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 (edge1 == RIGHT_EDGE && edge0 != LEFT_EDGE))
358 300 return DIR_RIGHT;
359
360 48 return NO_DIR;
361 }
362
363 /* Interpolate two points. */
364 6600 static void interp_point(int8_t *points, int x0, int y0, int x1, int y1,
365 int pos, int npoints)
366 {
367
2/2
✓ Branch 0 taken 6504 times.
✓ Branch 1 taken 96 times.
6600 if (npoints) {
368 6504 points[0] = (x0 * pos + x1 * (npoints - pos) + (npoints >> 1)) / npoints;
369 6504 points[1] = (y0 * pos + y1 * (npoints - pos) + (npoints >> 1)) / npoints;
370 } else {
371 96 points[0] = x0;
372 96 points[1] = y0;
373 }
374 6600 }
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 6 static void make_glyphs(int8_t *pglyphs, const int8_t *xvec, const int8_t *yvec,
385 const int side_length)
386 {
387 6 const int glyph_size = side_length * side_length;
388 6 int8_t *pglyph = pglyphs;
389
390 int i, j;
391
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 6 times.
102 for (i = 0; i < GLYPH_COORD_VECT_SIZE; i++) {
392 96 int x0 = xvec[i];
393 96 int y0 = yvec[i];
394 96 enum GlyphEdge edge0 = which_edge(x0, y0, side_length);
395
396
2/2
✓ Branch 0 taken 1536 times.
✓ Branch 1 taken 96 times.
1632 for (j = 0; j < GLYPH_COORD_VECT_SIZE; j++, pglyph += glyph_size) {
397 1536 int x1 = xvec[j];
398 1536 int y1 = yvec[j];
399 1536 enum GlyphEdge edge1 = which_edge(x1, y1, side_length);
400 1536 enum GlyphDir dir = which_direction(edge0, edge1);
401 1536 int npoints = FFMAX(FFABS(x1 - x0), FFABS(y1 - y0));
402 int ipoint;
403
404
2/2
✓ Branch 0 taken 6600 times.
✓ Branch 1 taken 1536 times.
8136 for (ipoint = 0; ipoint <= npoints; ipoint++) {
405 int8_t point[2];
406 int irow, icol;
407
408 6600 interp_point(point, x0, y0, x1, y1, ipoint, npoints);
409
410
5/5
✓ Branch 0 taken 2832 times.
✓ Branch 1 taken 1968 times.
✓ Branch 2 taken 282 times.
✓ Branch 3 taken 1434 times.
✓ Branch 4 taken 84 times.
6600 switch (dir) {
411 2832 case DIR_UP:
412
2/2
✓ Branch 0 taken 8232 times.
✓ Branch 1 taken 2832 times.
11064 for (irow = point[1]; irow >= 0; irow--)
413 8232 pglyph[point[0] + irow * side_length] = 1;
414 2832 break;
415
416 1968 case DIR_DOWN:
417
2/2
✓ Branch 0 taken 4500 times.
✓ Branch 1 taken 1968 times.
6468 for (irow = point[1]; irow < side_length; irow++)
418 4500 pglyph[point[0] + irow * side_length] = 1;
419 1968 break;
420
421 282 case DIR_LEFT:
422
2/2
✓ Branch 0 taken 378 times.
✓ Branch 1 taken 282 times.
660 for (icol = point[0]; icol >= 0; icol--)
423 378 pglyph[icol + point[1] * side_length] = 1;
424 282 break;
425
426 1434 case DIR_RIGHT:
427
2/2
✓ Branch 0 taken 4794 times.
✓ Branch 1 taken 1434 times.
6228 for (icol = point[0]; icol < side_length; icol++)
428 4794 pglyph[icol + point[1] * side_length] = 1;
429 1434 break;
430 }
431 }
432 }
433 }
434 6 }
435
436 6 static void init_sizes(SANMVideoContext *ctx, int width, int height)
437 {
438 6 ctx->width = width;
439 6 ctx->height = height;
440 6 ctx->npixels = width * height;
441
442 6 ctx->aligned_width = FFALIGN(width, 8);
443 6 ctx->aligned_height = FFALIGN(height, 8);
444
445 6 ctx->buf_size = ctx->aligned_width * ctx->aligned_height * sizeof(ctx->frm0[0]);
446 6 ctx->pitch = width;
447 6 }
448
449 3 static void destroy_buffers(SANMVideoContext *ctx)
450 {
451 3 av_freep(&ctx->fbuf);
452 3 av_freep(&ctx->frm0);
453 3 av_freep(&ctx->frm1);
454 3 av_freep(&ctx->frm2);
455 3 av_freep(&ctx->stored_frame);
456 3 av_freep(&ctx->rle_buf);
457 3 ctx->frm0_size =
458 3 ctx->frm1_size =
459 3 ctx->frm2_size = 0;
460 3 init_sizes(ctx, 0, 0);
461 3 }
462
463 3 static av_cold int init_buffers(SANMVideoContext *ctx)
464 {
465 3 av_fast_padded_mallocz(&ctx->fbuf, &ctx->fbuf_size, ctx->buf_size);
466 3 av_fast_padded_mallocz(&ctx->frm0, &ctx->frm0_size, ctx->buf_size);
467 3 av_fast_padded_mallocz(&ctx->frm1, &ctx->frm1_size, ctx->buf_size);
468 3 av_fast_padded_mallocz(&ctx->frm2, &ctx->frm2_size, ctx->buf_size);
469
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!ctx->version) {
470 av_fast_padded_mallocz(&ctx->stored_frame,
471 &ctx->stored_frame_size, ctx->buf_size);
472 ctx->stor_size = 0;
473 }
474
475
3/6
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
3 if (!ctx->frm0 || !ctx->frm1 || !ctx->frm2 ||
476
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 (!ctx->stored_frame && !ctx->version)) {
477 destroy_buffers(ctx);
478 return AVERROR(ENOMEM);
479 }
480
481 3 return 0;
482 }
483
484 static void codec33_gen_tiles(SANMVideoContext *ctx, int8_t param1)
485 {
486 uint8_t *dst = &(ctx->c4tbl[0][0][0]);
487 int i, j, k, l, m, n, o, p;
488
489 for (i = 0; i < 8; i++) {
490 for (k = 0; k < 8; k++) {
491 j = i + param1;
492 l = k + param1;
493 p = (j + l) >> 1;
494 n = (j + p) >> 1;
495 m = (p + l) >> 1;
496
497 *dst++ = p; *dst++ = p; *dst++ = n; *dst++ = j;
498 *dst++ = p; *dst++ = p; *dst++ = n; *dst++ = j;
499 *dst++ = m; *dst++ = m; *dst++ = p; *dst++ = j;
500 *dst++ = l; *dst++ = l; *dst++ = m; *dst++ = p;
501 }
502 }
503
504 for (i = 0; i < 8; i++) {
505 for (k = 0; k < 8; k++) {
506 j = i + param1;
507 l = k + param1;
508 n = (j + l) >> 1;
509 m = (l + n) >> 1;
510
511 *dst++ = j; *dst++ = j; *dst++ = j; *dst++ = j;
512 *dst++ = n; *dst++ = n; *dst++ = n; *dst++ = n;
513 *dst++ = m; *dst++ = m; *dst++ = m; *dst++ = m;
514 *dst++ = l; *dst++ = l; *dst++ = l; *dst++ = l;
515 }
516 }
517
518 for (i = 0; i < 8; i++) {
519 for (k = 0; k < 8; k++) {
520 j = i + param1;
521 l = k + param1;
522 m = (j + l) >> 1;
523 n = (j + m) >> 1;
524 o = (l + m) >> 1;
525
526 *dst++ = j; *dst++ = j; *dst++ = n; *dst++ = m;
527 *dst++ = j; *dst++ = j; *dst++ = n; *dst++ = m;
528 *dst++ = n; *dst++ = n; *dst++ = m; *dst++ = o;
529 *dst++ = m; *dst++ = m; *dst++ = o; *dst++ = l;
530 }
531 }
532
533 for (i = 0; i < 8; i++) {
534 for (k = 0; k < 8; k++) {
535 j = i + param1;
536 l = k + param1;
537 m = (j + l) >> 1;
538 n = (l + m) >> 1;
539
540 *dst++ = j; *dst++ = m; *dst++ = n; *dst++ = l;
541 *dst++ = j; *dst++ = m; *dst++ = n; *dst++ = l;
542 *dst++ = j; *dst++ = m; *dst++ = n; *dst++ = l;
543 *dst++ = j; *dst++ = m; *dst++ = n; *dst++ = l;
544 }
545 }
546 }
547
548 static void codec4_gen_tiles(SANMVideoContext *ctx, uint16_t param1)
549 {
550 uint8_t *dst = &(ctx->c4tbl[0][0][0]);
551 int i, j, k, l, m, n, o;
552
553 for (i = 1; i < 16; i += 2) {
554 for (k = 0; k < 16; k++) {
555 j = i + param1;
556 l = k + param1;
557 m = (j + l) / 2;
558 n = (j + m) / 2;
559 o = (l + m) / 2;
560 if (j == m || l == m) {
561 *dst++ = l; *dst++ = j; *dst++ = l; *dst++ = j;
562 *dst++ = j; *dst++ = l; *dst++ = j; *dst++ = j;
563 *dst++ = l; *dst++ = j; *dst++ = l; *dst++ = j;
564 *dst++ = l; *dst++ = l; *dst++ = j; *dst++ = l;
565 } else {
566 *dst++ = m; *dst++ = m; *dst++ = n; *dst++ = j;
567 *dst++ = m; *dst++ = m; *dst++ = n; *dst++ = j;
568 *dst++ = o; *dst++ = o; *dst++ = m; *dst++ = n;
569 *dst++ = l; *dst++ = l; *dst++ = o; *dst++ = m;
570 }
571 }
572 }
573
574 for (i = 0; i < 16; i += 2) {
575 for (k = 0; k < 16; k++) {
576 j = i + param1;
577 l = k + param1;
578 m = (j + l) / 2;
579 n = (j + m) / 2;
580 o = (l + m) / 2;
581 if (m == j || m == l) {
582 *dst++ = j; *dst++ = j; *dst++ = l; *dst++ = j;
583 *dst++ = j; *dst++ = j; *dst++ = j; *dst++ = l;
584 *dst++ = l; *dst++ = j; *dst++ = l; *dst++ = l;
585 *dst++ = j; *dst++ = l; *dst++ = j; *dst++ = l;
586 } else {
587 *dst++ = j; *dst++ = j; *dst++ = n; *dst++ = m;
588 *dst++ = j; *dst++ = j; *dst++ = n; *dst++ = m;
589 *dst++ = n; *dst++ = n; *dst++ = m; *dst++ = o;
590 *dst++ = m; *dst++ = m; *dst++ = o; *dst++ = l;
591 }
592 }
593 }
594 }
595
596
597 static int codec4_load_tiles(SANMVideoContext *ctx, GetByteContext *gb,
598 uint16_t param2, uint8_t clr)
599 {
600 uint8_t c, *dst = (uint8_t *)&(ctx->c4tbl[1][0][0]);
601 uint32_t loop = param2 * 8;
602
603 if ((param2 > 256) || (bytestream2_get_bytes_left(gb) < loop))
604 return AVERROR_INVALIDDATA;
605
606 while (loop--) {
607 c = bytestream2_get_byteu(gb);
608 *dst++ = (c >> 4) + clr;
609 *dst++ = (c & 0xf) + clr;
610 }
611
612 return 0;
613 }
614
615 9 static void rotate_bufs(SANMVideoContext *ctx, int rotate_code)
616 {
617
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
9 if (rotate_code == 2)
618 1 FFSWAP(uint16_t*, ctx->frm1, ctx->frm2);
619 9 FFSWAP(uint16_t*, ctx->frm2, ctx->frm0);
620 9 }
621
622 3 static av_cold int decode_init(AVCodecContext *avctx)
623 {
624 3 SANMVideoContext *ctx = avctx->priv_data;
625
626 3 ctx->avctx = avctx;
627 3 ctx->version = !avctx->extradata_size;
628 // early sanity check before allocations to avoid need for deallocation code.
629
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3 if (!ctx->version && avctx->extradata_size < 1026) {
630 av_log(avctx, AV_LOG_ERROR, "Not enough extradata.\n");
631 return AVERROR_INVALIDDATA;
632 }
633
634
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 avctx->pix_fmt = ctx->version ? AV_PIX_FMT_RGB565 : AV_PIX_FMT_PAL8;
635
636
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!ctx->version) {
637 // ANIM has no dimensions in the header, distrust the incoming data.
638 avctx->width = avctx->height = 0;
639 ctx->have_dimensions = 0;
640
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 } else if (avctx->width > 800 || avctx->height > 600 ||
641
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 avctx->width < 8 || avctx->height < 8) {
642 // BL16 valid range is 8x8 - 800x600
643 return AVERROR_INVALIDDATA;
644 }
645 3 init_sizes(ctx, avctx->width, avctx->height);
646
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (init_buffers(ctx)) {
647 av_log(avctx, AV_LOG_ERROR, "Error allocating buffers.\n");
648 return AVERROR(ENOMEM);
649 }
650
651 3 make_glyphs(ctx->p4x4glyphs[0], glyph4_x, glyph4_y, 4);
652 3 make_glyphs(ctx->p8x8glyphs[0], glyph8_x, glyph8_y, 8);
653
654
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!ctx->version) {
655 int i;
656
657 ctx->subversion = AV_RL16(avctx->extradata);
658 for (i = 0; i < PALETTE_SIZE; i++)
659 ctx->pal[i] = 0xFFU << 24 | AV_RL32(avctx->extradata + 2 + i * 4);
660 if (ctx->subversion < 2)
661 ctx->pal[0] = 0xFFU << 24;
662 }
663 3 ctx->c4param = 0xffff;
664
665 3 return 0;
666 }
667
668 3 static av_cold int decode_end(AVCodecContext *avctx)
669 {
670 3 SANMVideoContext *ctx = avctx->priv_data;
671
672 3 destroy_buffers(ctx);
673
674 3 return 0;
675 }
676
677 static int old_codec4(SANMVideoContext *ctx, GetByteContext *gb, int top, int left,
678 int w, int h, uint8_t param, uint16_t param2, int codec)
679 {
680 const uint16_t mx = ctx->width, my = ctx->height, p = ctx->pitch;
681 uint8_t mask, bits, idx, *gs, *dst = (uint8_t *)ctx->fbuf;
682 int i, j, k, l, bit, ret, x, y;
683
684 if (ctx->c4param != param) {
685 if (codec > 32)
686 codec33_gen_tiles(ctx, param);
687 else
688 codec4_gen_tiles(ctx, param);
689 ctx->c4param = param;
690 }
691 if (param2 > 0) {
692 ret = codec4_load_tiles(ctx, gb, param2, param);
693 if (ret)
694 return ret;
695 }
696
697 if (codec > 32)
698 codec -= 29;
699
700 for (j = 0; j < w; j += 4) {
701 mask = bits = 0;
702 x = left + j;
703 for (i = 0; i < h; i += 4) {
704 y = top + i;
705 if (param2 > 0) {
706 if (bits == 0) {
707 if (bytestream2_get_bytes_left(gb) < 1)
708 return AVERROR_INVALIDDATA;
709 mask = bytestream2_get_byteu(gb);
710 bits = 8;
711 }
712 bit = !!(mask & 0x80);
713 mask <<= 1;
714 bits--;
715 } else {
716 bit = 0;
717 }
718
719 if (bytestream2_get_bytes_left(gb) < 1)
720 return AVERROR_INVALIDDATA;
721 idx = bytestream2_get_byteu(gb);
722 if ((bit == 0) && (idx == 0x80) && (codec != 5))
723 continue;
724 if ((y >= my) || ((y + 4) < 0) || ((x + 4) < 0) || (x >= mx))
725 continue;
726 gs = &(ctx->c4tbl[bit][idx][0]);
727 if ((y >= 0) && (x >= 0) && ((y + 4) < my) && ((x + 4) < mx)) {
728 for (k = 0; k < 4; k++, gs += 4)
729 memcpy(dst + x + (y + k) * p, gs, 4);
730 } else {
731 for (k = 0; k < 4; k++) {
732 for (l = 0; l < 4; l++, gs++) {
733 const int yo = y + k, xo = x + l;
734 if ((yo >= 0) && (yo < my) && (xo >= 0) && (xo < mx))
735 *(dst + yo * p + xo) = *gs;
736 }
737 }
738 }
739 }
740 }
741 return 0;
742 }
743
744 1 static int rle_decode(SANMVideoContext *ctx, GetByteContext *gb, uint8_t *dst, const int out_size)
745 {
746 1 int opcode, color, run_len, left = out_size;
747
748
2/2
✓ Branch 0 taken 4800 times.
✓ Branch 1 taken 1 times.
4801 while (left > 0) {
749 4800 opcode = bytestream2_get_byte(gb);
750 4800 run_len = (opcode >> 1) + 1;
751
2/4
✓ Branch 0 taken 4800 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4800 times.
4800 if (run_len > left || bytestream2_get_bytes_left(gb) <= 0)
752 return AVERROR_INVALIDDATA;
753
754
1/2
✓ Branch 0 taken 4800 times.
✗ Branch 1 not taken.
4800 if (opcode & 1) {
755 4800 color = bytestream2_get_byte(gb);
756 4800 memset(dst, color, run_len);
757 } else {
758 if (bytestream2_get_bytes_left(gb) < run_len)
759 return AVERROR_INVALIDDATA;
760 bytestream2_get_bufferu(gb, dst, run_len);
761 }
762
763 4800 dst += run_len;
764 4800 left -= run_len;
765 }
766
767 1 return 0;
768 }
769
770 static int old_codec23(SANMVideoContext *ctx, GetByteContext *gb, int top, int left,
771 int width, int height, uint8_t param, uint16_t param2)
772 {
773 const uint16_t mx = ctx->width, my = ctx->height, p = ctx->pitch;
774 uint8_t c, lut[256], *dst = (uint8_t *)ctx->fbuf;
775 int sk, i, j, ls, pc, y;
776
777 if (ctx->subversion < 2) {
778 /* Rebel Assault 1: constant offset + 0xd0 */
779 for (i = 0; i < 256; i++)
780 lut[i] = (i + param + 0xd0) & 0xff;
781 } else if (param2 == 256) {
782 if (bytestream2_get_bytes_left(gb) < 256)
783 return AVERROR_INVALIDDATA;
784 bytestream2_get_bufferu(gb, ctx->c23lut, 256);
785 } else if (param2 < 256) {
786 for (i = 0; i < 256; i++)
787 lut[i] = (i + param2) & 0xff;
788 } else {
789 memcpy(lut, ctx->c23lut, 256);
790 }
791 if (bytestream2_get_bytes_left(gb) < 1)
792 return 0; /* some c23 frames just set up the LUT */
793
794 if (((top + height) < 0) || (top >= my) || (left + width < 0) || (left >= mx))
795 return 0;
796
797 if (top < 0) {
798 y = -top;
799 while (y-- && bytestream2_get_bytes_left(gb) > 1) {
800 ls = bytestream2_get_le16u(gb);
801 if (bytestream2_get_bytes_left(gb) < ls)
802 return AVERROR_INVALIDDATA;
803 bytestream2_skip(gb, ls);
804 }
805 height += top;
806 top = 0;
807 }
808
809 y = top;
810 for (; (bytestream2_get_bytes_left(gb) > 1) && (height > 0) && (y < my); height--, y++) {
811 ls = bytestream2_get_le16u(gb);
812 sk = 1;
813 pc = left;
814 while ((bytestream2_get_bytes_left(gb) > 0) && (ls > 0) && (pc <= (width + left))) {
815 j = bytestream2_get_byteu(gb);
816 ls--;
817 if (!sk) {
818 while (j--) {
819 if ((pc >= 0) && (pc < mx)) {
820 c = *(dst + (y * p) + pc);
821 *(dst + (y * p) + pc) = lut[c];
822 }
823 if (pc < mx)
824 pc++;
825 }
826 } else {
827 if (pc < mx)
828 pc += j;
829 }
830 sk ^= 1;
831 }
832 }
833 return 0;
834 }
835
836 static int old_codec21(SANMVideoContext *ctx, GetByteContext *gb, int top, int left,
837 int width, int height)
838 {
839 const uint16_t mx = ctx->width, my = ctx->height, p = ctx->pitch;
840 uint8_t *dst = (uint8_t *)ctx->fbuf, c;
841 int j, y, pc, sk, ls;
842
843 if (((top + height) < 0) || (top >= my) || (left + width < 0) || (left >= mx))
844 return 0;
845
846 y = top;
847 for (; (bytestream2_get_bytes_left(gb) > 2) && (height > 0) && (y < my); height--, y++) {
848 ls = bytestream2_get_le16u(gb);
849 if (y < 0) {
850 if (ls >= bytestream2_get_bytes_left(gb))
851 return 0;
852 bytestream2_skip(gb, ls);
853 continue;
854 }
855 sk = 1;
856 pc = left;
857 while ((bytestream2_get_bytes_left(gb) > 1) && (ls > 1) && (pc <= (width + left))) {
858 j = bytestream2_get_le16u(gb);
859 ls -= 2;
860 if (sk) {
861 if (pc < mx)
862 pc += j;
863 } else {
864 while ((bytestream2_get_bytes_left(gb) > 0) && (ls > 0) && (j >= 0)) {
865 c = bytestream2_get_byteu(gb);
866 if ((pc >= 0) && (pc < mx)) {
867 *(dst + (y * p) + pc) = c;
868 }
869 ls--;
870 j--;
871 if (pc < mx)
872 pc++;
873 }
874 }
875 sk ^= 1;
876 }
877 }
878 return 0;
879 }
880
881 static int old_codec1(SANMVideoContext *ctx, GetByteContext *gb, int top,
882 int left, int width, int height, int opaque)
883 {
884 const uint16_t mx = ctx->width, my = ctx->height, p = ctx->pitch;
885 uint8_t *dst = (uint8_t *)ctx->fbuf, code, c;
886 int j, x, y, flag, dlen;
887
888 if (((top + height) < 0) || (top >= my) || (left + width < 0) || (left >= mx))
889 return 0;
890
891 if (top < 0) {
892 y = -top;
893 while (y-- && bytestream2_get_bytes_left(gb) > 1) {
894 dlen = bytestream2_get_le16u(gb);
895 if (bytestream2_get_bytes_left(gb) <= dlen)
896 return AVERROR_INVALIDDATA;
897 bytestream2_skip(gb, dlen);
898 }
899 height += top;
900 top = 0;
901 }
902
903 y = top;
904 for (; (bytestream2_get_bytes_left(gb) > 1) && (height > 0) && (y < my); height--, y++) {
905 dlen = bytestream2_get_le16u(gb);
906 x = left;
907 while (bytestream2_get_bytes_left(gb) > 1 && dlen) {
908 code = bytestream2_get_byteu(gb);
909 dlen--;
910 flag = code & 1;
911 code = (code >> 1) + 1;
912 if (flag) {
913 c = bytestream2_get_byteu(gb);
914 dlen--;
915 if (x >= mx)
916 continue;
917 if (x < 0) {
918 int dff = FFMIN(-x, code);
919 code -= dff;
920 x += dff;
921 }
922 if (x + code >= mx)
923 code = mx - x;
924 if (code < 1)
925 continue;
926 for (j = 0; (j < code) && (c || opaque); j++) {
927 *(dst + (y * p) + x + j) = c;
928 }
929 x += code;
930 } else {
931 if (bytestream2_get_bytes_left(gb) < code)
932 return AVERROR_INVALIDDATA;
933 for (j = 0; j < code; j++) {
934 c = bytestream2_get_byteu(gb);
935 if ((x >= 0) && (x < mx) && (c || opaque))
936 *(dst + (y * p) + x) = c;
937 if (x < mx)
938 x++;
939 }
940 dlen -= code;
941 }
942 }
943 }
944
945 return 0;
946 }
947
948 static int old_codec31(SANMVideoContext *ctx, GetByteContext *gb, int top,
949 int left, int width, int height, int p1, int opaque)
950 {
951 const uint16_t mx = ctx->width, my = ctx->height, p = ctx->pitch;
952 uint8_t *dst = (uint8_t *)ctx->fbuf, c;
953 int j, x, y, flag, dlen, code;
954
955 if (((top + height) < 0) || (top >= my) || (left + width < 0) || (left >= mx))
956 return 0;
957
958 if (top < 0) {
959 y = -top;
960 while (y-- && bytestream2_get_bytes_left(gb) > 1) {
961 dlen = bytestream2_get_le16u(gb);
962 if (bytestream2_get_bytes_left(gb) <= dlen)
963 return AVERROR_INVALIDDATA;
964 bytestream2_skip(gb, dlen);
965 }
966 height += top;
967 top = 0;
968 }
969
970 y = top;
971 for (; (bytestream2_get_bytes_left(gb) > 1) && (height > 0) && (y < my); height--, y++) {
972 dlen = bytestream2_get_le16u(gb);
973 x = left;
974 while (bytestream2_get_bytes_left(gb) > 1 && dlen) {
975 code = bytestream2_get_byteu(gb);
976 dlen--;
977 flag = code & 1;
978 code = (code >> 1) + 1;
979 if (flag) {
980 c = bytestream2_get_byteu(gb);
981 dlen--;
982 for (j = 0; (j < code); j++) {
983 if ((opaque || (c & 0xf)) && (x >= 0) && (x < mx))
984 *(dst + (y * p) + x) = p1 + (c & 0xf);
985 if (x < mx)
986 x++;
987 if ((opaque || (c >> 4)) && (x >= 0) && (x < mx))
988 *(dst + (y * p) + x) = p1 + (c >> 4);
989 if (x < mx)
990 x++;
991 }
992 } else {
993 if (bytestream2_get_bytes_left(gb) < code)
994 return AVERROR_INVALIDDATA;
995 for (j = 0; j < code; j++) {
996 c = bytestream2_get_byteu(gb);
997 if ((opaque || (c & 0xf)) && (x >= 0) && (x < mx))
998 *(dst + (y * p) + x) = p1 + (c & 0xf);
999 if (x < mx)
1000 x++;
1001 if ((opaque || (c >> 4)) && (x >= 0) && (x < mx))
1002 *(dst + (y * p) + x) = p1 + (c >> 4);
1003 if (x < mx)
1004 x++;
1005 }
1006 dlen -= code;
1007 }
1008 }
1009 }
1010
1011 return 0;
1012 }
1013
1014 static int old_codec2(SANMVideoContext *ctx, GetByteContext *gb, int top,
1015 int left, int width, int height)
1016 {
1017 uint8_t *dst = (uint8_t *)ctx->fbuf, col;
1018 int16_t xpos = left, ypos = top;
1019
1020 while (bytestream2_get_bytes_left(gb) > 3) {
1021 xpos += bytestream2_get_le16u(gb);
1022 ypos += bytestream2_get_byteu(gb);
1023 col = bytestream2_get_byteu(gb);
1024 if (xpos >= 0 && ypos >= 0 &&
1025 xpos < ctx->width && ypos < ctx->height) {
1026 *(dst + xpos + ypos * ctx->pitch) = col;
1027 }
1028 }
1029 return 0;
1030 }
1031
1032 static void blt_solid(uint8_t *dst, const uint8_t *src, int16_t left, int16_t top,
1033 uint16_t srcxoff, uint16_t srcyoff, uint16_t srcwidth,
1034 uint16_t srcheight, const uint16_t srcpitch, const uint16_t dstpitch,
1035 const uint16_t dstheight, int32_t size)
1036 {
1037 if ((srcwidth < 1) || (srcheight < 1) || (size < 1))
1038 return;
1039
1040 if (top < 0) {
1041 if (-top >= srcheight)
1042 return;
1043 srcyoff -= top;
1044 srcheight += top;
1045 size += (srcpitch * top);
1046 top = 0;
1047 }
1048
1049 if ((top + srcheight) > dstheight) {
1050 int clip = (top + srcheight) - dstheight;
1051 if (clip >= srcheight)
1052 return;
1053 srcheight -= clip;
1054 }
1055
1056 if (left < 0) {
1057 if (-left >= srcwidth)
1058 return;
1059 srcxoff -= left;
1060 srcwidth += left;
1061 size += left;
1062 left = 0;
1063 }
1064
1065 if (left + srcwidth > dstpitch) {
1066 int clip = (left + srcwidth) - dstpitch;
1067 if (clip >= srcwidth)
1068 return;
1069 srcwidth -= clip;
1070 }
1071
1072 src += ((uintptr_t)srcyoff * srcpitch) + srcxoff;
1073 dst += ((uintptr_t)top * dstpitch) + left;
1074 while ((srcheight--) && (size >= srcwidth)) {
1075 memcpy(dst, src, srcwidth);
1076 src += srcpitch;
1077 dst += dstpitch;
1078 size -= srcpitch;
1079 }
1080 if ((size > 0) && (size < srcwidth) && (srcheight > 0))
1081 memcpy(dst, src, size);
1082 }
1083
1084 static void blt_mask(uint8_t *dst, const uint8_t *src, int16_t left, int16_t top,
1085 uint16_t srcxoff, uint16_t srcyoff, uint16_t srcwidth,
1086 uint16_t srcheight, const uint16_t srcpitch, const uint16_t dstpitch,
1087 const uint16_t dstheight, int32_t size, const uint8_t skipcolor)
1088 {
1089 if ((srcwidth < 1) || (srcheight < 1) || (size < 1))
1090 return;
1091
1092 if (top < 0) {
1093 if (-top >= srcheight)
1094 return;
1095 srcyoff -= top;
1096 srcheight += top;
1097 size += (srcpitch * top);
1098 top = 0;
1099 }
1100
1101 if ((top + srcheight) > dstheight) {
1102 int clip = (top + srcheight) - dstheight;
1103 if (clip >= srcheight)
1104 return;
1105 srcheight -= clip;
1106 }
1107
1108 if (left < 0) {
1109 if (-left >= srcwidth)
1110 return;
1111 srcxoff -= left;
1112 srcwidth += left;
1113 size += left;
1114 left = 0;
1115 }
1116
1117 if (left + srcwidth > dstpitch) {
1118 int clip = (left + srcwidth) - dstpitch;
1119 if (clip >= srcwidth)
1120 return;
1121 srcwidth -= clip;
1122 }
1123
1124 src += ((uintptr_t)srcyoff * srcpitch) + srcxoff;
1125 dst += ((uintptr_t)top * dstpitch) + left;
1126 for (int i = 0; (size > 0) && (i < srcheight); i++) {
1127 for (int j = 0; (size > 0) && (j < srcwidth); j++, size--) {
1128 if (src[j] != skipcolor)
1129 dst[j] = src[j];
1130 }
1131 src += srcpitch;
1132 dst += dstpitch;
1133 }
1134 }
1135
1136 static void blt_ipol(uint8_t *dst, const uint8_t *src1, const uint8_t *src2,
1137 int16_t left, int16_t top, uint16_t srcxoff, uint16_t srcyoff,
1138 uint16_t srcwidth, uint16_t srcheight, const uint16_t srcpitch,
1139 const uint16_t dstpitch, const uint16_t dstheight, int32_t size,
1140 const uint8_t *itbl)
1141 {
1142 if ((srcwidth < 1) || (srcheight < 1) || (size < 1))
1143 return;
1144
1145 if (top < 0) {
1146 if (-top >= srcheight)
1147 return;
1148 srcyoff -= top;
1149 srcheight += top;
1150 size += (srcpitch * top);
1151 top = 0;
1152 }
1153
1154 if ((top + srcheight) > dstheight) {
1155 int clip = (top + srcheight) - dstheight;
1156 if (clip >= srcheight)
1157 return;
1158 srcheight -= clip;
1159 }
1160
1161 if (left < 0) {
1162 if (-left >= srcwidth)
1163 return;
1164 srcxoff -= left;
1165 srcwidth += left;
1166 size += left;
1167 left = 0;
1168 }
1169
1170 if (left + srcwidth > dstpitch) {
1171 int clip = (left + srcwidth) - dstpitch;
1172 if (clip >= srcwidth)
1173 return;
1174 srcwidth -= clip;
1175 }
1176
1177 src1 += ((uintptr_t)srcyoff * srcpitch) + srcxoff;
1178 src2 += ((uintptr_t)srcyoff * srcpitch) + srcxoff;
1179 dst += ((uintptr_t)top * dstpitch) + left;
1180 for (int i = 0; (size > 0) && (i < srcheight); i++) {
1181 for (int j = 0; (size > 0) && (j < srcwidth); j++, size--) {
1182 dst[j] = itbl[(src1[j] << 8) | src2[j]];
1183 }
1184 src1 += srcpitch;
1185 src2 += srcpitch;
1186 dst += dstpitch;
1187 }
1188 }
1189
1190 static int old_codec20(SANMVideoContext *ctx, GetByteContext *gb, int top, int left,
1191 const int w, const int h)
1192 {
1193 blt_solid((uint8_t*)ctx->fbuf, gb->buffer, left, top, 0, 0, w, h, w, ctx->pitch,
1194 ctx->height, FFMIN(bytestream2_get_bytes_left(gb), w * h));
1195
1196 return 0;
1197 }
1198
1199 static inline void codec37_mv(uint8_t *dst, const uint8_t *src,
1200 int height, int stride, int x, int y)
1201 {
1202 int pos, i, j;
1203
1204 pos = x + y * stride;
1205 for (j = 0; j < 4; j++) {
1206 for (i = 0; i < 4; i++) {
1207 if ((pos + i) < 0 || (pos + i) >= height * stride)
1208 dst[i] = 0;
1209 else
1210 dst[i] = src[i];
1211 }
1212 dst += stride;
1213 src += stride;
1214 pos += stride;
1215 }
1216 }
1217
1218 static int old_codec37(SANMVideoContext *ctx, GetByteContext *gb, int top, int left,
1219 int width, int height)
1220 {
1221 int i, j, k, l, t, run, len, code, skip, mx, my;
1222 uint8_t *dst, *prev;
1223 int skip_run = 0;
1224
1225 width = FFALIGN(width, 4);
1226 if (width > ctx->aligned_width)
1227 return AVERROR_INVALIDDATA;
1228
1229 if (bytestream2_get_bytes_left(gb) < 16)
1230 return AVERROR_INVALIDDATA;
1231
1232 int compr = bytestream2_get_byteu(gb);
1233 int mvoff = bytestream2_get_byteu(gb);
1234 int seq = bytestream2_get_le16u(gb);
1235 uint32_t decoded_size = bytestream2_get_le32u(gb);
1236 int flags;
1237
1238 bytestream2_skip(gb, 4);
1239 flags = bytestream2_get_byteu(gb);
1240 bytestream2_skip(gb, 3);
1241
1242 if (decoded_size > height * width) {
1243 decoded_size = height * width;
1244 av_log(ctx->avctx, AV_LOG_WARNING, "Decoded size is too large.\n");
1245 }
1246
1247 if (((seq & 1) || !(flags & 1)) && (compr && compr != 2)) {
1248 FFSWAP(uint16_t*, ctx->frm0, ctx->frm2);
1249 }
1250
1251 dst = ((uint8_t*)ctx->frm0);
1252 prev = ((uint8_t*)ctx->frm2);
1253
1254 if (mvoff > 2) {
1255 av_log(ctx->avctx, AV_LOG_ERROR, "Invalid motion base value %d.\n", mvoff);
1256 return AVERROR_INVALIDDATA;
1257 }
1258
1259 switch (compr) {
1260 case 0:
1261 if (bytestream2_get_bytes_left(gb) < width * height)
1262 return AVERROR_INVALIDDATA;
1263 bytestream2_get_bufferu(gb, dst, width * height);
1264 memset(ctx->frm2, 0, ctx->frm2_size);
1265 break;
1266 case 1:
1267 run = 0;
1268 len = -1;
1269 code = 0;
1270
1271 for (j = 0; j < height; j += 4) {
1272 for (i = 0; i < width; i += 4) {
1273 if (len < 0) {
1274 if (bytestream2_get_bytes_left(gb) < 1)
1275 return AVERROR_INVALIDDATA;
1276 code = bytestream2_get_byte(gb);
1277 len = code >> 1;
1278 run = code & 1;
1279 skip = 0;
1280 } else {
1281 skip = run;
1282 }
1283
1284 if (!skip) {
1285 if (bytestream2_get_bytes_left(gb) < 1)
1286 return AVERROR_INVALIDDATA;
1287 code = bytestream2_get_byte(gb);
1288 if (code == 0xff) {
1289 len--;
1290 for (k = 0; k < 4; k++) {
1291 for (l = 0; l < 4; l++) {
1292 if (len < 0) {
1293 if (bytestream2_get_bytes_left(gb) < 1)
1294 return AVERROR_INVALIDDATA;
1295 code = bytestream2_get_byte(gb);
1296 len = code >> 1;
1297 run = code & 1;
1298 if (run) {
1299 if (bytestream2_get_bytes_left(gb) < 1)
1300 return AVERROR_INVALIDDATA;
1301 code = bytestream2_get_byte(gb);
1302 }
1303 }
1304 if (!run) {
1305 if (bytestream2_get_bytes_left(gb) < 1)
1306 return AVERROR_INVALIDDATA;
1307 code = bytestream2_get_byte(gb);
1308 }
1309 *(dst + i + (k * width) + l) = code;
1310 len--;
1311 }
1312 }
1313 continue;
1314 }
1315 }
1316 /* 4x4 block copy from prev with MV */
1317 code = (code == 0xff) ? 0 : code;
1318 mx = c37_mv[(mvoff * 255 + code) * 2];
1319 my = c37_mv[(mvoff * 255 + code) * 2 + 1];
1320 codec37_mv(dst + i, prev + i + mx + my * width,
1321 height, width, i + mx, j + my);
1322 len--;
1323 }
1324 dst += width * 4;
1325 prev += width * 4;
1326 }
1327 break;
1328 case 2:
1329 if (rle_decode(ctx, gb, dst, decoded_size))
1330 return AVERROR_INVALIDDATA;
1331 memset(ctx->frm2, 0, ctx->frm2_size);
1332 break;
1333 case 3:
1334 case 4:
1335 for (j = 0; j < height; j += 4) {
1336 for (i = 0; i < width; i += 4) {
1337 int code;
1338 if (skip_run) {
1339 skip_run--;
1340 copy_block4(dst + i, prev + i, width, width, 4);
1341 continue;
1342 }
1343 if (bytestream2_get_bytes_left(gb) < 1)
1344 return AVERROR_INVALIDDATA;
1345 code = bytestream2_get_byteu(gb);
1346 if (code == 0xFF) {
1347 if (bytestream2_get_bytes_left(gb) < 16)
1348 return AVERROR_INVALIDDATA;
1349 for (k = 0; k < 4; k++)
1350 bytestream2_get_bufferu(gb, dst + i + k * width, 4);
1351 } else if ((flags & 4) && (code == 0xFE)) {
1352 if (bytestream2_get_bytes_left(gb) < 4)
1353 return AVERROR_INVALIDDATA;
1354 for (k = 0; k < 4; k += 2) {
1355 uint8_t c1 = bytestream2_get_byteu(gb);
1356 uint8_t c2 = bytestream2_get_byteu(gb);
1357 for (l = 0; l < 2; l++) {
1358 *(dst + i + ((k + l) * width) + 0) = c1;
1359 *(dst + i + ((k + l) * width) + 1) = c1;
1360 *(dst + i + ((k + l) * width) + 2) = c2;
1361 *(dst + i + ((k + l) * width) + 3) = c2;
1362 }
1363 }
1364 } else if ((flags & 4) && (code == 0xFD)) {
1365 if (bytestream2_get_bytes_left(gb) < 1)
1366 return AVERROR_INVALIDDATA;
1367 t = bytestream2_get_byteu(gb);
1368 for (k = 0; k < 4; k++)
1369 memset(dst + i + k * width, t, 4);
1370 } else {
1371 mx = c37_mv[(mvoff * 255 + code) * 2];
1372 my = c37_mv[(mvoff * 255 + code) * 2 + 1];
1373 codec37_mv(dst + i, prev + i + mx + my * width,
1374 height, width, i + mx, j + my);
1375
1376 if ((compr == 4) && (code == 0)) {
1377 if (bytestream2_get_bytes_left(gb) < 1)
1378 return AVERROR_INVALIDDATA;
1379 skip_run = bytestream2_get_byteu(gb);
1380 }
1381 }
1382 }
1383 dst += width * 4;
1384 prev += width * 4;
1385 }
1386 break;
1387 default:
1388 avpriv_report_missing_feature(ctx->avctx,
1389 "Subcodec 37 compression %d", compr);
1390 return AVERROR_PATCHWELCOME;
1391 }
1392
1393 if ((flags & 2) == 0) {
1394 blt_solid((uint8_t*)ctx->fbuf, (uint8_t*)ctx->frm0, left, top, 0, 0, width,
1395 height, width, ctx->pitch, ctx->height, width * height);
1396 } else {
1397 blt_mask((uint8_t*)ctx->fbuf, (uint8_t*)ctx->frm0, left, top, 0, 0, width,
1398 height, width, ctx->pitch, ctx->height, width * height, 0);
1399 }
1400 return 0;
1401 }
1402
1403 static int codec47_block(SANMVideoContext *ctx, GetByteContext *gb,uint8_t *dst,
1404 uint8_t *prev1, uint8_t *prev2, int stride, int size)
1405 {
1406 int code, k, t;
1407 uint8_t colors[2];
1408 int8_t *pglyph;
1409
1410 if (bytestream2_get_bytes_left(gb) < 1)
1411 return AVERROR_INVALIDDATA;
1412
1413 code = bytestream2_get_byteu(gb);
1414 if (code >= 0xF8) {
1415 switch (code) {
1416 case 0xFF:
1417 if (size == 2) {
1418 if (bytestream2_get_bytes_left(gb) < 4)
1419 return AVERROR_INVALIDDATA;
1420 dst[0] = bytestream2_get_byteu(gb);
1421 dst[1] = bytestream2_get_byteu(gb);
1422 dst[0 + stride] = bytestream2_get_byteu(gb);
1423 dst[1 + stride] = bytestream2_get_byteu(gb);
1424 } else {
1425 size >>= 1;
1426 if (codec47_block(ctx, gb, dst, prev1, prev2, stride, size))
1427 return AVERROR_INVALIDDATA;
1428 if (codec47_block(ctx, gb, dst + size, prev1 + size, prev2 + size,
1429 stride, size))
1430 return AVERROR_INVALIDDATA;
1431 dst += size * stride;
1432 prev1 += size * stride;
1433 prev2 += size * stride;
1434 if (codec47_block(ctx, gb, dst, prev1, prev2, stride, size))
1435 return AVERROR_INVALIDDATA;
1436 if (codec47_block(ctx, gb, dst + size, prev1 + size, prev2 + size,
1437 stride, size))
1438 return AVERROR_INVALIDDATA;
1439 }
1440 break;
1441 case 0xFE:
1442 if (bytestream2_get_bytes_left(gb) < 1)
1443 return AVERROR_INVALIDDATA;
1444
1445 t = bytestream2_get_byteu(gb);
1446 for (k = 0; k < size; k++)
1447 memset(dst + k * stride, t, size);
1448 break;
1449 case 0xFD:
1450 if (bytestream2_get_bytes_left(gb) < 3)
1451 return AVERROR_INVALIDDATA;
1452
1453 code = bytestream2_get_byteu(gb);
1454 pglyph = (size == 8) ? ctx->p8x8glyphs[code] : ctx->p4x4glyphs[code];
1455 bytestream2_get_bufferu(gb, colors, 2);
1456
1457 for (k = 0; k < size; k++)
1458 for (t = 0; t < size; t++)
1459 dst[t + k * stride] = colors[!*pglyph++];
1460 break;
1461 case 0xFC:
1462 for (k = 0; k < size; k++)
1463 memcpy(dst + k * stride, prev1 + k * stride, size);
1464 break;
1465 default:
1466 for (k = 0; k < size; k++)
1467 memset(dst + k * stride, ctx->c47cb[code & 3], size);
1468 }
1469 } else {
1470 int mx = c47_mv[code][0];
1471 int my = c47_mv[code][1];
1472 int index = prev2 - (const uint8_t *)ctx->frm2;
1473
1474 av_assert2(index >= 0 && index < (ctx->buf_size >> 1));
1475
1476 if (index < -mx - my * stride ||
1477 (ctx->buf_size >> 1) - index < mx + size + (my + size - 1) * stride) {
1478 av_log(ctx->avctx, AV_LOG_ERROR, "MV is invalid.\n");
1479 return AVERROR_INVALIDDATA;
1480 }
1481
1482 for (k = 0; k < size; k++)
1483 memcpy(dst + k * stride, prev2 + mx + (my + k) * stride, size);
1484 }
1485
1486 return 0;
1487 }
1488
1489 static void codec47_read_interptable(GetByteContext *gb, uint8_t *itbl)
1490 {
1491 uint8_t *p1, *p2;
1492 int i, j;
1493
1494 for (i = 0; i < 256; i++) {
1495 p1 = p2 = itbl + i;
1496 for (j = 256 - i; j; j--) {
1497 *p1 = *p2 = bytestream2_get_byte(gb);
1498 p1 += 1;
1499 p2 += 256;
1500 }
1501 itbl += 256;
1502 }
1503 }
1504
1505 static void codec47_comp1(GetByteContext *gb, uint8_t *dst_in, int width,
1506 const int height, const ptrdiff_t stride, const uint8_t *itbl)
1507 {
1508 uint8_t p1, *dst;
1509 uint16_t px;
1510 int i, j;
1511
1512 dst = dst_in + stride;
1513 for (i = 0; i < height; i += 2) {
1514 p1 = bytestream2_get_byte(gb);
1515 *dst++ = p1;
1516 *dst++ = p1;
1517 px = p1;
1518 for (j = 2; j < width; j += 2) {
1519 p1 = bytestream2_get_byte(gb);
1520 px = (px << 8) | p1;
1521 *dst++ = itbl[px];
1522 *dst++ = p1;
1523 }
1524 dst += stride;
1525 }
1526
1527 memcpy(dst_in, dst_in + stride, width);
1528 dst = dst_in + stride + stride;
1529 for (i = 2; i < height - 1; i += 2) {
1530 for (j = 0; j < width; j++) {
1531 px = (*(dst - stride) << 8) | *(dst + stride);
1532 *dst++ = itbl[px];
1533 }
1534 dst += stride;
1535 }
1536 }
1537
1538 static int old_codec47(SANMVideoContext *ctx, GetByteContext *gb, int top, int left,
1539 int width, int height)
1540 {
1541 uint32_t decoded_size;
1542 int i, j;
1543 uint8_t *dst = (uint8_t *)ctx->frm0;
1544 uint8_t *prev1 = (uint8_t *)ctx->frm1;
1545 uint8_t *prev2 = (uint8_t *)ctx->frm2;
1546 uint8_t auxcol[2];
1547
1548 width = FFALIGN(width, 8);
1549 if (width > ctx->aligned_width)
1550 return AVERROR_INVALIDDATA;
1551
1552 if (bytestream2_get_bytes_left(gb) < 26)
1553 return AVERROR_INVALIDDATA;
1554
1555 int seq = bytestream2_get_le16u(gb);
1556 int compr = bytestream2_get_byteu(gb);
1557 int new_rot = bytestream2_get_byteu(gb);
1558 int skip = bytestream2_get_byteu(gb);
1559
1560 bytestream2_skip(gb, 3);
1561 bytestream2_get_bufferu(gb, ctx->c47cb, 4);
1562 auxcol[0] = bytestream2_get_byteu(gb);
1563 auxcol[1] = bytestream2_get_byteu(gb);
1564 decoded_size = bytestream2_get_le32u(gb);
1565 bytestream2_skip(gb, 8);
1566
1567 if (decoded_size > ctx->aligned_height * width) {
1568 decoded_size = height * width;
1569 av_log(ctx->avctx, AV_LOG_WARNING, "Decoded size is too large.\n");
1570 }
1571
1572 if (skip & 1) {
1573 if (bytestream2_get_bytes_left(gb) < 0x8080)
1574 return AVERROR_INVALIDDATA;
1575 codec47_read_interptable(gb, ctx->c47itbl);
1576 }
1577 if (!seq) {
1578 ctx->prev_seq = -1;
1579 memset(prev1, auxcol[0], ctx->frm0_size);
1580 memset(prev2, auxcol[1], ctx->frm0_size);
1581 }
1582
1583 switch (compr) {
1584 case 0:
1585 if (bytestream2_get_bytes_left(gb) < width * height)
1586 return AVERROR_INVALIDDATA;
1587 bytestream2_get_bufferu(gb, dst, width * height);
1588 break;
1589 case 1:
1590 if (bytestream2_get_bytes_left(gb) < ((width + 1) >> 1) * ((height + 1) >> 1))
1591 return AVERROR_INVALIDDATA;
1592 codec47_comp1(gb, dst, width, height, width, ctx->c47itbl);
1593 break;
1594 case 2:
1595 if (seq == ctx->prev_seq + 1) {
1596 for (j = 0; j < height; j += 8) {
1597 for (i = 0; i < width; i += 8)
1598 if (codec47_block(ctx, gb, dst + i, prev1 + i, prev2 + i, width, 8))
1599 return AVERROR_INVALIDDATA;
1600 dst += width * 8;
1601 prev1 += width * 8;
1602 prev2 += width * 8;
1603 }
1604 }
1605 break;
1606 case 3:
1607 memcpy(ctx->frm0, ctx->frm2, ctx->frm0_size);
1608 break;
1609 case 4:
1610 memcpy(ctx->frm0, ctx->frm1, ctx->frm0_size);
1611 break;
1612 case 5:
1613 if (rle_decode(ctx, gb, dst, decoded_size))
1614 return AVERROR_INVALIDDATA;
1615 break;
1616 default:
1617 avpriv_report_missing_feature(ctx->avctx,
1618 "Subcodec 47 compression %d", compr);
1619 return AVERROR_PATCHWELCOME;
1620 }
1621
1622 blt_solid((uint8_t*)ctx->fbuf, (uint8_t*)ctx->frm0, left, top, 0, 0, width,
1623 height, width, ctx->pitch, ctx->height, width * height);
1624
1625 if ((seq == ctx->prev_seq + 1) && new_rot)
1626 rotate_bufs(ctx, new_rot);
1627
1628 ctx->prev_seq = seq;
1629
1630 return 0;
1631 }
1632
1633 // scale 4x4 input block to an 8x8 output block
1634 static void c48_4to8(uint8_t *dst, const uint8_t *src, const uint16_t w)
1635 {
1636 uint16_t p;
1637 // dst is always at least 16bit aligned
1638 for (int i = 0; i < 4; i++) {
1639 for (int j = 0; j < 8; j += 2) {
1640 p = *src++;
1641 p = (p << 8) | p;
1642 *((uint16_t *)(dst + w * 0 + j)) = p;
1643 *((uint16_t *)(dst + w * 1 + j)) = p;
1644 }
1645 dst += w * 2;
1646 }
1647 }
1648
1649 static int c48_invalid_mv(int x, int y, const uint16_t w, int h, int blocksize, int mvofs) {
1650 if (mvofs < -x + -y*w)
1651 return AVERROR_INVALIDDATA;
1652
1653 if (mvofs > w-x-blocksize + w*(h-y-blocksize))
1654 return AVERROR_INVALIDDATA;
1655
1656 return 0;
1657 }
1658
1659 static int codec48_block(GetByteContext *gb, uint8_t *dst, uint8_t *db, int x, int y,
1660 const uint16_t w, const int aligned_height, const uint8_t *itbl)
1661 {
1662 uint8_t opc, sb[16];
1663 int i, j, k, l;
1664 int16_t mvofs;
1665 uint32_t ofs;
1666
1667 if (bytestream2_get_bytes_left(gb) < 1)
1668 return 1;
1669
1670 opc = bytestream2_get_byteu(gb);
1671 switch (opc) {
1672 case 0xFF: // 1x1 -> 8x8 block scale
1673 if (bytestream2_get_bytes_left(gb) < 1)
1674 return 1;
1675
1676 if (y > 0 && x > 0) {
1677 sb[15] = bytestream2_get_byteu(gb);
1678 sb[ 7] = itbl[(*(dst - 1*w + 7) << 8) | sb[15]];
1679 sb[ 3] = itbl[(*(dst - 1*w + 7) << 8) | sb[ 7]];
1680 sb[11] = itbl[(sb[15] << 8) | sb[ 7]];
1681 sb[ 1] = itbl[(*(dst + 0*w - 1) << 8) | sb[ 3]];
1682 sb[ 0] = itbl[(*(dst + 0*w - 1) << 8) | sb[ 1]];
1683 sb[ 2] = itbl[(sb[ 3] << 8) | sb[ 1]];
1684 sb[ 5] = itbl[(*(dst + 2*w - 1) << 8) | sb[ 7]];
1685 sb[ 4] = itbl[(*(dst + 2*w - 1) << 8) | sb[ 5]];
1686 sb[ 6] = itbl[(sb[ 7] << 8) | sb[ 5]];
1687 sb[ 9] = itbl[(*(dst + 3*w - 1) << 8) | sb[11]];
1688 sb[ 8] = itbl[(*(dst + 3*w - 1) << 8) | sb[ 9]];
1689 sb[10] = itbl[(sb[11] << 8) | sb[ 9]];
1690 sb[13] = itbl[(*(dst + 4*w - 1) << 8) | sb[15]];
1691 sb[12] = itbl[(*(dst + 4*w - 1) << 8) | sb[13]];
1692 sb[14] = itbl[(sb[15] << 8) | sb[13]];
1693 } else {
1694 opc = bytestream2_get_byteu(gb);
1695 for (i = 0; i < 16; i++)
1696 sb[i] = opc;
1697 }
1698 c48_4to8(dst, sb, w);
1699 break;
1700 case 0xFE: // 1x 8x8 copy from deltabuf, 16bit mv from source
1701 if (bytestream2_get_bytes_left(gb) < 2)
1702 return 1;
1703 mvofs = bytestream2_get_le16(gb);
1704 if (c48_invalid_mv(x, y, w, aligned_height, 8, mvofs))
1705 break;
1706 for (i = 0; i < 8; i++) {
1707 ofs = w * i;
1708 for (k = 0; k < 8; k++)
1709 *(dst + ofs + k) = *(db + ofs + k + mvofs);
1710 }
1711 break;
1712 case 0xFD: // 2x2 -> 8x8 block scale
1713 if (bytestream2_get_bytes_left(gb) < 4)
1714 return 1;
1715 sb[ 5] = bytestream2_get_byteu(gb);
1716 sb[ 7] = bytestream2_get_byteu(gb);
1717 sb[13] = bytestream2_get_byteu(gb);
1718 sb[15] = bytestream2_get_byteu(gb);
1719
1720 if (y > 0 && x >0) {
1721 sb[ 1] = itbl[(*(dst - 1*w + 3) << 8) | sb[ 5]];
1722 sb[ 3] = itbl[(*(dst - 1*w + 7) << 8) | sb[ 7]];
1723 sb[ 9] = itbl[(sb[13] << 8) | sb[ 5]];
1724 sb[11] = itbl[(sb[15] << 8) | sb[ 7]];
1725 sb[ 0] = itbl[(*(dst + 0*w - 1) << 8) | sb[ 1]];
1726 sb[ 2] = itbl[(sb[ 3] << 8) | sb[ 1]];
1727 sb[ 4] = itbl[(*(dst + 2*w - 1) << 8) | sb[ 5]];
1728 sb[ 6] = itbl[(sb[ 7] << 8) | sb[ 5]];
1729 sb[ 8] = itbl[(*(dst + 3*w - 1) << 8) | sb[ 9]];
1730 sb[10] = itbl[(sb[11] << 8) | sb[ 9]];
1731 sb[12] = itbl[(*(dst + 4*w - 1) << 8) | sb[13]];
1732 sb[14] = itbl[(sb[15] << 8) | sb[13]];
1733 } else {
1734 sb[ 0] = sb[ 1] = sb[ 4] = sb[ 5];
1735 sb[ 2] = sb[ 3] = sb[ 6] = sb[ 7];
1736 sb[ 8] = sb[ 9] = sb[12] = sb[13];
1737 sb[10] = sb[11] = sb[14] = sb[15];
1738 }
1739 c48_4to8(dst, sb, w);
1740 break;
1741 case 0xFC: // 4x copy 4x4 block, per-block c37_mv from source
1742 if (bytestream2_get_bytes_left(gb) < 4)
1743 return 1;
1744 for (i = 0; i < 8; i += 4) {
1745 for (k = 0; k < 8; k += 4) {
1746 opc = bytestream2_get_byteu(gb);
1747 opc = (opc == 255) ? 0 : opc;
1748 mvofs = c37_mv[opc * 2] + (c37_mv[opc * 2 + 1] * w);
1749 if (c48_invalid_mv(x+k, y+i, w, aligned_height, 4, mvofs))
1750 continue;
1751 for (j = 0; j < 4; j++) {
1752 ofs = (w * (j + i)) + k;
1753 for (l = 0; l < 4; l++)
1754 *(dst + ofs + l) = *(db + ofs + l + mvofs);
1755 }
1756 }
1757 }
1758 break;
1759 case 0xFB: // Copy 4x 4x4 blocks, per-block mv from source
1760 if (bytestream2_get_bytes_left(gb) < 8)
1761 return 1;
1762 for (i = 0; i < 8; i += 4) {
1763 for (k = 0; k < 8; k += 4) {
1764 mvofs = bytestream2_get_le16(gb);
1765 if (c48_invalid_mv(x+k, y+i, w, aligned_height, 4, mvofs))
1766 continue;
1767 for (j = 0; j < 4; j++) {
1768 ofs = (w * (j + i)) + k;
1769 for (l = 0; l < 4; l++)
1770 *(dst + ofs + l) = *(db + ofs + l + mvofs);
1771 }
1772 }
1773 }
1774 break;
1775 case 0xFA: // scale 4x4 input block to 8x8 dest block
1776 if (bytestream2_get_bytes_left(gb) < 16)
1777 return 1;
1778 bytestream2_get_bufferu(gb, sb, 16);
1779 c48_4to8(dst, sb, w);
1780 break;
1781 case 0xF9: // 16x 2x2 copy from delta, per-block c37_mv from source
1782 if (bytestream2_get_bytes_left(gb) < 16)
1783 return 1;
1784 for (i = 0; i < 8; i += 2) {
1785 for (j = 0; j < 8; j += 2) {
1786 ofs = (w * i) + j;
1787 opc = bytestream2_get_byteu(gb);
1788 opc = (opc == 255) ? 0 : opc;
1789 mvofs = c37_mv[opc * 2] + (c37_mv[opc * 2 + 1] * w);
1790 if (c48_invalid_mv(x+j, y+i, w, aligned_height, 2, mvofs))
1791 continue;
1792 for (l = 0; l < 2; l++) {
1793 *(dst + ofs + l + 0) = *(db + ofs + l + 0 + mvofs);
1794 *(dst + ofs + l + w) = *(db + ofs + l + w + mvofs);
1795 }
1796 }
1797 }
1798 break;
1799 case 0xF8: // 16x 2x2 blocks copy, 16bit mv from source
1800 if (bytestream2_get_bytes_left(gb) < 32)
1801 return 1;
1802 for (i = 0; i < 8; i += 2) {
1803 for (j = 0; j < 8; j += 2) {
1804 ofs = w * i + j;
1805 mvofs = bytestream2_get_le16(gb);
1806 if (c48_invalid_mv(x+j, y+i, w, aligned_height, 2, mvofs))
1807 continue;
1808 for (l = 0; l < 2; l++) {
1809 *(dst + ofs + l + 0) = *(db + ofs + l + 0 + mvofs);
1810 *(dst + ofs + l + w) = *(db + ofs + l + w + mvofs);
1811 }
1812 }
1813 }
1814 break;
1815 case 0xF7: // copy 8x8 block from src to dest
1816 if (bytestream2_get_bytes_left(gb) < 64)
1817 return 1;
1818 for (i = 0; i < 8; i++) {
1819 ofs = i * w;
1820 for (l = 0; l < 8; l++)
1821 *(dst + ofs + l) = bytestream2_get_byteu(gb);
1822 }
1823 break;
1824 default: // copy 8x8 block from prev, c37_mv from source
1825 mvofs = c37_mv[opc * 2] + (c37_mv[opc * 2 + 1] * w);
1826 if (c48_invalid_mv(x, y, w, aligned_height, 8, mvofs))
1827 break;
1828 for (i = 0; i < 8; i++) {
1829 ofs = i * w;
1830 for (l = 0; l < 8; l++)
1831 *(dst + ofs + l) = *(db + ofs + l + mvofs);
1832 }
1833 break;
1834 }
1835 return 0;
1836 }
1837
1838 static int old_codec48(SANMVideoContext *ctx, GetByteContext *gb, int top, int left,
1839 int width, int height)
1840 {
1841 uint8_t *dst, *prev;
1842 int i, j, flags, ah;
1843
1844 width = FFALIGN(width, 8);
1845 if (width > ctx->aligned_width)
1846 return AVERROR_INVALIDDATA;
1847
1848 ah = FFALIGN(height, 8);
1849 if (ah > ctx->aligned_height)
1850 return AVERROR_INVALIDDATA;
1851
1852 if (bytestream2_get_bytes_left(gb) < 16)
1853 return AVERROR_INVALIDDATA;
1854
1855 int compr = bytestream2_get_byteu(gb);
1856 int mvidx = bytestream2_get_byteu(gb);
1857 int seq = bytestream2_get_le16u(gb);
1858 uint32_t decoded_size = bytestream2_get_le32u(gb);
1859
1860 // all codec48 videos use 1, but just to be safe...
1861 if (mvidx != 1) {
1862 av_log(ctx->avctx, AV_LOG_ERROR, "Invalid motion base value %d.\n", mvidx);
1863 return AVERROR_INVALIDDATA;
1864 }
1865
1866 bytestream2_skip(gb, 4);
1867 flags = bytestream2_get_byteu(gb);
1868 bytestream2_skip(gb, 3);
1869
1870 if (flags & 8) {
1871 if (bytestream2_get_bytes_left(gb) < 0x8080)
1872 return AVERROR_INVALIDDATA;
1873 codec47_read_interptable(gb, ctx->c47itbl);
1874 }
1875
1876 dst = (uint8_t*)ctx->frm0;
1877 prev = (uint8_t*)ctx->frm2;
1878
1879 if (seq == 0)
1880 memset(ctx->frm2, 0, ctx->frm2_size);
1881
1882 switch (compr) {
1883 case 0:
1884 if (bytestream2_get_bytes_left(gb) < width * height)
1885 return AVERROR_INVALIDDATA;
1886 bytestream2_get_bufferu(gb, dst, width * height);
1887 break;
1888 case 2:
1889 if (decoded_size > width * height) {
1890 av_log(ctx->avctx, AV_LOG_ERROR, "Decoded size %u is too large.\n", decoded_size);
1891 decoded_size = width * height;
1892 }
1893
1894 if (rle_decode(ctx, gb, dst, decoded_size))
1895 return AVERROR_INVALIDDATA;
1896 break;
1897 case 3:
1898 if ((seq == 0) || (seq == ctx->prev_seq + 1)) {
1899 if ((seq & 1) || ((flags & 1) == 0) || (flags & 0x10)) {
1900 FFSWAP(uint16_t*, ctx->frm0, ctx->frm2);
1901 dst = (uint8_t*)ctx->frm0;
1902 prev = (uint8_t*)ctx->frm2;
1903 }
1904 for (j = 0; j < height; j += 8) {
1905 for (i = 0; i < width; i += 8) {
1906 if (codec48_block(gb, dst + i, prev + i, i, j, width,
1907 ah, ctx->c47itbl))
1908 return AVERROR_INVALIDDATA;
1909 }
1910 dst += width * 8;
1911 prev += width * 8;
1912 }
1913 }
1914 break;
1915 case 5:
1916 if (bytestream2_get_bytes_left(gb) < ((width + 1) >> 1) * ((height + 1) >> 1))
1917 return AVERROR_INVALIDDATA;
1918 codec47_comp1(gb, dst, width, height, width, ctx->c47itbl);
1919 break;
1920 case 6: /* this is a "stub" frame that follows a frame with flag 0x10 set. */
1921 break;
1922 default:
1923 avpriv_report_missing_feature(ctx->avctx,
1924 "Subcodec 48 compression %d", compr);
1925 return AVERROR_PATCHWELCOME;
1926 }
1927
1928 ctx->prev_seq = seq;
1929 if ((flags & 2) == 0) {
1930 if (flags & 0x10) {
1931 /* generate an artificial frame from the 2 buffers. This will be
1932 * followed up immediately with a codec48 compression 6 frame, which
1933 * will then blit the actual decoding result (frm0) to the main buffer.
1934 */
1935 blt_ipol((uint8_t*)ctx->fbuf, (uint8_t*)ctx->frm0, (uint8_t*)ctx->frm2,
1936 left, top, 0, 0, width, height, width, ctx->pitch, ctx->height,
1937 width * height, ctx->c47itbl);
1938 return 0;
1939 }
1940 blt_solid((uint8_t*)ctx->fbuf, (uint8_t*)ctx->frm0, left, top, 0, 0, width,
1941 height, width, ctx->pitch, ctx->height, width * height);
1942 } else {
1943 blt_mask((uint8_t*)ctx->fbuf, (uint8_t*)ctx->frm0, left, top, 0, 0, width,
1944 height, width, ctx->pitch, ctx->height, width * height, 0);
1945 }
1946 return 0;
1947 }
1948
1949 static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb,
1950 int xoff, int yoff)
1951 {
1952 uint16_t w, h, parm2;
1953 uint8_t codec, param;
1954 int16_t left, top;
1955 int fsc;
1956
1957 codec = bytestream2_get_byteu(gb);
1958 param = bytestream2_get_byteu(gb);
1959 left = bytestream2_get_le16u(gb) + xoff;
1960 top = bytestream2_get_le16u(gb) + yoff;
1961 w = bytestream2_get_le16u(gb);
1962 h = bytestream2_get_le16u(gb);
1963 bytestream2_skip(gb, 2);
1964 parm2 = bytestream2_get_le16u(gb);
1965
1966 if (w < 1 || h < 1 || w > 640 || h > 480 || left > 640 || top > 480 || left + w <= 0 || top + h <= 0) {
1967 av_log(ctx->avctx, AV_LOG_WARNING,
1968 "ignoring invalid fobj dimensions: c%d %d %d @ %d %d\n",
1969 codec, w, h, left, top);
1970 return 0;
1971 }
1972
1973 /* codecs with their own buffers */
1974 fsc = (codec == 37 || codec == 47 || codec == 48);
1975
1976 /* special case for "Shadows of the Empire" videos: they have top=60
1977 * at all frames to vertically center the video in the 640x480 game
1978 * window, but we don't need that.
1979 */
1980 if ((w == 640) && (h == 272) && (top == 60) && (codec == 47))
1981 left = top = 0;
1982
1983 if (!ctx->have_dimensions) {
1984 int xres, yres;
1985 if (ctx->subversion < 2) {
1986 /* Rebel Assault 1: 384x242 internal size */
1987 xres = 384;
1988 yres = 242;
1989 if (w > xres || h > yres)
1990 return AVERROR_INVALIDDATA;
1991 ctx->have_dimensions = 1;
1992 } else if (fsc) {
1993 /* these codecs work on full frames, trust their dimensions */
1994 xres = w;
1995 yres = h;
1996 ctx->have_dimensions = 1;
1997 } else {
1998 /* detect common sizes */
1999 xres = w + left;
2000 yres = h + top;
2001 if (((xres == 424) && (yres == 260)) || /* RA2 */
2002 ((xres == 320) && (yres == 200)) || /* FT/Dig */
2003 ((xres == 640) && (yres == 272)) || /* SotE */
2004 ((xres == 640) && (yres == 350)) || /* MotS */
2005 ((xres == 640) && (yres == 480))) {
2006 ctx->have_dimensions = 1;
2007 }
2008
2009 xres = FFMAX(xres, ctx->width);
2010 yres = FFMAX(yres, ctx->height);
2011 }
2012
2013 if ((xres < (fsc ? 8 : 1)) || (yres < (fsc ? 8 : 1)) || (xres > 640) || (yres > 480))
2014 return AVERROR_INVALIDDATA;
2015
2016 if (ctx->width < xres || ctx->height < yres) {
2017 int ret = ff_set_dimensions(ctx->avctx, xres, yres);
2018 if (ret < 0)
2019 return ret;
2020 init_sizes(ctx, xres, yres);
2021 if (init_buffers(ctx)) {
2022 av_log(ctx->avctx, AV_LOG_ERROR, "Error resizing buffers.\n");
2023 return AVERROR(ENOMEM);
2024 }
2025 }
2026 } else {
2027 if (((w > ctx->width) || (h > ctx->height) || (w * h > ctx->buf_size)) && fsc) {
2028 /* correct unexpected overly large frames: this happens
2029 * for instance with The Dig's sq1.san video: it has a few
2030 * (all black) 640x480 frames halfway in, while the rest is
2031 * 320x200.
2032 */
2033 av_log(ctx->avctx, AV_LOG_WARNING,
2034 "resizing too large fobj: c%d %d %d @ %d %d\n", codec, w, h, left, top);
2035 w = ctx->width;
2036 h = ctx->height;
2037 }
2038 }
2039
2040 /* users of codecs>=37 are subversion 2, enforce that for STOR/FTCH */
2041 if (fsc && ctx->subversion < 2) {
2042 ctx->subversion = 2;
2043 ctx->stor_size = 0; /* invalidate existing data */
2044 }
2045
2046 /* clear the main buffer on the first fob */
2047 if (ctx->first_fob) {
2048 ctx->first_fob = 0;
2049 if (!fsc)
2050 memset(ctx->fbuf, 0, ctx->frm0_size);
2051 }
2052
2053 switch (codec) {
2054 case 1:
2055 case 3:
2056 return old_codec1(ctx, gb, top, left, w, h, codec == 3);
2057 case 2:
2058 return old_codec2(ctx, gb, top, left, w, h);
2059 case 4:
2060 case 5:
2061 case 33:
2062 case 34:
2063 return old_codec4(ctx, gb, top, left, w, h, param, parm2, codec);
2064 case 20:
2065 return old_codec20(ctx, gb, top, left, w, h);
2066 case 21:
2067 return old_codec21(ctx, gb, top, left, w, h);
2068 case 23:
2069 return old_codec23(ctx, gb, top, left, w, h, param, parm2);
2070 case 31:
2071 case 32:
2072 return old_codec31(ctx, gb, top, left, w, h, param, (codec == 32));
2073 case 37:
2074 return old_codec37(ctx, gb, top, left, w, h); break;
2075 case 45:
2076 return 0;
2077 case 47:
2078 return old_codec47(ctx, gb, top, left, w, h); break;
2079 case 48:
2080 return old_codec48(ctx, gb, top, left, w, h); break;
2081 default:
2082 avpriv_request_sample(ctx->avctx, "Subcodec %d", codec);
2083 ctx->frame->flags |= AV_FRAME_FLAG_CORRUPT;
2084 break;
2085 }
2086 return 0;
2087 }
2088
2089 static int process_ftch(SANMVideoContext *ctx, int size)
2090 {
2091 int xoff, yoff, ret;
2092 GetByteContext gb;
2093
2094 /* FTCH defines additional x/y offsets */
2095 if (size == 6) {
2096 bytestream2_skip(&ctx->gb, 2);
2097 xoff = bytestream2_get_le16u(&ctx->gb);
2098 yoff = bytestream2_get_le16u(&ctx->gb);
2099 } else if (size == 12) {
2100 av_assert0(bytestream2_get_bytes_left(&ctx->gb) >= 12);
2101 bytestream2_skip(&ctx->gb, 4);
2102 xoff = bytestream2_get_be32u(&ctx->gb);
2103 yoff = bytestream2_get_be32u(&ctx->gb);
2104 } else
2105 return 1;
2106
2107 if (ctx->stor_size > 0) {
2108 /* decode the stored FOBJ */
2109 uint8_t *bitstream = av_malloc(ctx->stor_size + AV_INPUT_BUFFER_PADDING_SIZE);
2110 if (!bitstream)
2111 return AVERROR(ENOMEM);
2112 memcpy(bitstream, ctx->stored_frame, ctx->stor_size);
2113 bytestream2_init(&gb, bitstream, ctx->stor_size);
2114 ret = process_frame_obj(ctx, &gb, xoff, yoff);
2115 av_free(bitstream);
2116 } else {
2117 /* this happens a lot in RA1: The individual files are meant to
2118 * be played in sequence, with some referencing objects STORed
2119 * by previous files, e.g. the cockpit codec21 object in RA1 LVL8.
2120 * But spamming the log with errors is also not helpful, so
2121 * here we simply ignore this case. Return 1 to indicate that
2122 * there was no valid image fetched.
2123 */
2124 ret = 1;
2125 }
2126 return ret;
2127 }
2128
2129 static int process_xpal(SANMVideoContext *ctx, int size)
2130 {
2131 int16_t *dp = ctx->delta_pal;
2132 uint32_t *pal = ctx->pal;
2133 uint16_t cmd;
2134 uint8_t c[3];
2135 int i, j;
2136
2137 if (size < 4)
2138 return AVERROR_INVALIDDATA;
2139 bytestream2_skip(&ctx->gb, 2);
2140 cmd = bytestream2_get_be16(&ctx->gb);
2141 size -= 4;
2142
2143 if (cmd == 1) {
2144 for (i = 0; i < PALETTE_DELTA; i += 3) {
2145 for (j = 0; j < 3; j++) {
2146 ctx->shift_pal[i + j] += dp[i + j];
2147 c[j] = av_clip_uint8(ctx->shift_pal[i + j] >> 7) & 0xFFU;
2148 }
2149 *pal++ = 0xFFU << 24 | c[0] << 16 | c[1] << 8 | c[2];
2150 }
2151 } else if (cmd == 0 || cmd == 2) {
2152 if (size < PALETTE_DELTA * 2) {
2153 av_log(ctx->avctx, AV_LOG_ERROR,
2154 "Incorrect palette change block size %"PRIu32".\n", size);
2155 return AVERROR_INVALIDDATA;
2156 }
2157 for (i = 0; i < PALETTE_DELTA; i++)
2158 dp[i] = bytestream2_get_le16u(&ctx->gb);
2159 size -= PALETTE_DELTA * 2;
2160
2161 if (size >= PALETTE_SIZE * 3) {
2162 for (i = 0; i < PALETTE_SIZE; i++)
2163 ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb);
2164 if (ctx->subversion < 2)
2165 ctx->pal[0] = 0xFFU << 24;
2166 }
2167 for (i = 0, j = 0; i < PALETTE_DELTA; i += 3, j++) {
2168 ctx->shift_pal[i + 0] = (((ctx->pal[j]) >> 16) & 0xFFU) << 7;
2169 ctx->shift_pal[i + 1] = (((ctx->pal[j]) >> 8) & 0xFFU) << 7;
2170 ctx->shift_pal[i + 2] = (((ctx->pal[j]) >> 0) & 0xFFU) << 7;
2171 }
2172 }
2173 return 0;
2174 }
2175
2176 static int bl16_decode_0(SANMVideoContext *ctx)
2177 {
2178 uint16_t *frm = ctx->frm0;
2179 int x, y;
2180
2181 if (bytestream2_get_bytes_left(&ctx->gb) < ctx->width * ctx->height * 2) {
2182 av_log(ctx->avctx, AV_LOG_ERROR, "Insufficient data for raw frame.\n");
2183 return AVERROR_INVALIDDATA;
2184 }
2185 for (y = 0; y < ctx->height; y++) {
2186 for (x = 0; x < ctx->width; x++)
2187 frm[x] = bytestream2_get_le16u(&ctx->gb);
2188 frm += ctx->pitch;
2189 }
2190 return 0;
2191 }
2192
2193 /* BL16 pixel interpolation function, see tgsmush.dll c690 */
2194 static inline uint16_t bl16_c1_avg_col(uint16_t c1, uint16_t c2)
2195 {
2196 return (((c2 & 0x07e0) + (c1 & 0x07e0)) & 0x00fc0) |
2197 (((c2 & 0xf800) + (c1 & 0xf800)) & 0x1f000) |
2198 (((c2 & 0x001f) + (c1 & 0x001f))) >> 1;
2199 }
2200
2201 /* Quarter-sized keyframe encoded as stream of 16bit pixel values. Interpolate
2202 * missing pixels by averaging the colors of immediate neighbours.
2203 * Identical to codec47_comp1() but with 16bit-pixels. tgsmush.dll c6f0
2204 */
2205 static int bl16_decode_1(SANMVideoContext *ctx)
2206 {
2207 uint16_t hh, hw, c1, c2, *dst1, *dst2;
2208
2209 if (bytestream2_get_bytes_left(&ctx->gb) < ((ctx->width * ctx->height) / 2))
2210 return AVERROR_INVALIDDATA;
2211
2212 hh = (ctx->height + 1) >> 1;
2213 dst1 = (uint16_t *)ctx->frm0 + ctx->pitch; /* start with line 1 */
2214 while (hh--) {
2215 hw = (ctx->width - 1) >> 1;
2216 c1 = bytestream2_get_le16u(&ctx->gb);
2217 dst1[0] = c1;
2218 dst1[1] = c1;
2219 dst2 = dst1 + 2;
2220 while (--hw) {
2221 c2 = bytestream2_get_le16u(&ctx->gb);
2222 *dst2++ = bl16_c1_avg_col(c1, c2);
2223 *dst2++ = c2;
2224 c1 = c2;
2225 }
2226 dst1 += ctx->pitch * 2; /* skip to overnext line */
2227 }
2228 /* line 0 is a copy of line 1 */
2229 memcpy(ctx->frm0, ctx->frm0 + ctx->pitch, ctx->pitch);
2230
2231 /* complete the skipped lines by averaging from the pixels in the lines
2232 * above and below
2233 */
2234 dst1 = ctx->frm0 + (ctx->pitch * 2);
2235 hh = (ctx->height - 1) >> 1;
2236 while (hh--) {
2237 hw = ctx->width;
2238 dst2 = dst1;
2239 while (hw--) {
2240 c1 = *(dst2 - ctx->pitch); /* pixel from line above */
2241 c2 = *(dst2 + ctx->pitch); /* pixel from line below */
2242 *dst2++ = bl16_c1_avg_col(c1, c2);
2243 }
2244 dst1 += ctx->pitch * 2;
2245 }
2246 return 0;
2247 }
2248
2249 42964 static void copy_block(uint16_t *pdest, uint16_t *psrc, int block_size, ptrdiff_t pitch)
2250 {
2251 42964 uint8_t *dst = (uint8_t *)pdest;
2252 42964 uint8_t *src = (uint8_t *)psrc;
2253 42964 ptrdiff_t stride = pitch * 2;
2254
2255
3/4
✓ Branch 0 taken 14526 times.
✓ Branch 1 taken 12400 times.
✓ Branch 2 taken 16038 times.
✗ Branch 3 not taken.
42964 switch (block_size) {
2256 14526 case 2:
2257 14526 copy_block4(dst, src, stride, stride, 2);
2258 14526 break;
2259 12400 case 4:
2260 12400 copy_block8(dst, src, stride, stride, 4);
2261 12400 break;
2262 16038 case 8:
2263 16038 copy_block16(dst, src, stride, stride, 8);
2264 16038 break;
2265 }
2266 42964 }
2267
2268 7913 static void fill_block(uint16_t *pdest, uint16_t color, int block_size, ptrdiff_t pitch)
2269 {
2270 int x, y;
2271
2272 7913 pitch -= block_size;
2273
2/2
✓ Branch 0 taken 30438 times.
✓ Branch 1 taken 7913 times.
38351 for (y = 0; y < block_size; y++, pdest += pitch)
2274
2/2
✓ Branch 0 taken 149540 times.
✓ Branch 1 taken 30438 times.
179978 for (x = 0; x < block_size; x++)
2275 149540 *pdest++ = color;
2276 7913 }
2277
2278 8368 static int draw_glyph(SANMVideoContext *ctx, uint16_t *dst, int index,
2279 uint16_t fg_color, uint16_t bg_color, int block_size,
2280 ptrdiff_t pitch)
2281 {
2282 int8_t *pglyph;
2283 8368 uint16_t colors[2] = { fg_color, bg_color };
2284 int x, y;
2285
2286
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8368 times.
8368 if (index >= NGLYPHS) {
2287 av_log(ctx->avctx, AV_LOG_ERROR, "Ignoring nonexistent glyph #%u.\n", index);
2288 return AVERROR_INVALIDDATA;
2289 }
2290
2291
2/2
✓ Branch 0 taken 1158 times.
✓ Branch 1 taken 7210 times.
8368 pglyph = block_size == 8 ? ctx->p8x8glyphs[index] : ctx->p4x4glyphs[index];
2292 8368 pitch -= block_size;
2293
2294
2/2
✓ Branch 0 taken 38104 times.
✓ Branch 1 taken 8368 times.
46472 for (y = 0; y < block_size; y++, dst += pitch)
2295
2/2
✓ Branch 0 taken 189472 times.
✓ Branch 1 taken 38104 times.
227576 for (x = 0; x < block_size; x++)
2296 189472 *dst++ = colors[*pglyph++];
2297 8368 return 0;
2298 }
2299
2300 8029 static int opcode_0xf7(SANMVideoContext *ctx, int cx, int cy, int block_size, ptrdiff_t pitch)
2301 {
2302 8029 uint16_t *dst = ctx->frm0 + cx + cy * ctx->pitch;
2303
2304
2/2
✓ Branch 0 taken 825 times.
✓ Branch 1 taken 7204 times.
8029 if (block_size == 2) {
2305 uint32_t indices;
2306
2307
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 825 times.
825 if (bytestream2_get_bytes_left(&ctx->gb) < 4)
2308 return AVERROR_INVALIDDATA;
2309
2310 825 indices = bytestream2_get_le32u(&ctx->gb);
2311 825 dst[0] = ctx->codebook[indices & 0xFF];
2312 825 indices >>= 8;
2313 825 dst[1] = ctx->codebook[indices & 0xFF];
2314 825 indices >>= 8;
2315 825 dst[pitch] = ctx->codebook[indices & 0xFF];
2316 825 indices >>= 8;
2317 825 dst[pitch + 1] = ctx->codebook[indices & 0xFF];
2318 } else {
2319 uint16_t fgcolor, bgcolor;
2320 int glyph;
2321
2322
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 7203 times.
7204 if (bytestream2_get_bytes_left(&ctx->gb) < 3)
2323 1 return AVERROR_INVALIDDATA;
2324
2325 7203 glyph = bytestream2_get_byteu(&ctx->gb);
2326 7203 bgcolor = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
2327 7203 fgcolor = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
2328
2329 7203 draw_glyph(ctx, dst, glyph, fgcolor, bgcolor, block_size, pitch);
2330 }
2331 8028 return 0;
2332 }
2333
2334 1169 static int opcode_0xf8(SANMVideoContext *ctx, int cx, int cy, int block_size, ptrdiff_t pitch)
2335 {
2336 1169 uint16_t *dst = ctx->frm0 + cx + cy * ctx->pitch;
2337
2338
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1165 times.
1169 if (block_size == 2) {
2339
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (bytestream2_get_bytes_left(&ctx->gb) < 8)
2340 return AVERROR_INVALIDDATA;
2341
2342 4 dst[0] = bytestream2_get_le16u(&ctx->gb);
2343 4 dst[1] = bytestream2_get_le16u(&ctx->gb);
2344 4 dst[pitch] = bytestream2_get_le16u(&ctx->gb);
2345 4 dst[pitch + 1] = bytestream2_get_le16u(&ctx->gb);
2346 } else {
2347 uint16_t fgcolor, bgcolor;
2348 int glyph;
2349
2350
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1165 times.
1165 if (bytestream2_get_bytes_left(&ctx->gb) < 5)
2351 return AVERROR_INVALIDDATA;
2352
2353 1165 glyph = bytestream2_get_byteu(&ctx->gb);
2354 1165 bgcolor = bytestream2_get_le16u(&ctx->gb);
2355 1165 fgcolor = bytestream2_get_le16u(&ctx->gb);
2356
2357 1165 draw_glyph(ctx, dst, glyph, fgcolor, bgcolor, block_size, pitch);
2358 }
2359 1169 return 0;
2360 }
2361
2362 30376 static int good_mvec(SANMVideoContext *ctx, int cx, int cy, int mx, int my,
2363 int block_size)
2364 {
2365 30376 int start_pos = cx + mx + (cy + my) * ctx->pitch;
2366 30376 int end_pos = start_pos + (block_size - 1) * (ctx->pitch + 1);
2367
2368
2/4
✓ Branch 0 taken 30376 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30376 times.
✗ Branch 3 not taken.
30376 int good = start_pos >= 0 && end_pos < (ctx->buf_size >> 1);
2369
2370
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30376 times.
30376 if (!good)
2371 av_log(ctx->avctx, AV_LOG_ERROR,
2372 "Ignoring invalid motion vector (%i, %i)->(%u, %u), block size = %u\n",
2373 cx + mx, cy + my, cx, cy, block_size);
2374
2375 30376 return good;
2376 }
2377
2378 71636 static int bl16_block(SANMVideoContext *ctx, int cx, int cy, int blk_size)
2379 {
2380 int16_t mx, my, index;
2381 int opcode;
2382
2383
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 71635 times.
71636 if (bytestream2_get_bytes_left(&ctx->gb) < 1)
2384 1 return AVERROR_INVALIDDATA;
2385
2386 71635 opcode = bytestream2_get_byteu(&ctx->gb);
2387
2388
9/9
✓ Branch 0 taken 28212 times.
✓ Branch 1 taken 2164 times.
✓ Branch 2 taken 12588 times.
✓ Branch 3 taken 8029 times.
✓ Branch 4 taken 1169 times.
✓ Branch 5 taken 315 times.
✓ Branch 6 taken 5496 times.
✓ Branch 7 taken 2102 times.
✓ Branch 8 taken 11560 times.
71635 switch (opcode) {
2389 28212 default:
2390 28212 mx = c47_mv[opcode][0];
2391 28212 my = c47_mv[opcode][1];
2392
2393 /* The original implementation of this codec precomputes a table
2394 * of int16_t of all motion vectors a for given image width.
2395 * For widths starting at 762 pixels, the calculation of
2396 * mv table indices 1+ and 255- overflow the int16_t, inverting the
2397 * sign of the offset. This is actively exploited in e.g. the
2398 * "jonesopn_8.snm" video of "Indiana Jones and the Infernal Machine".
2399 * Therefore let the overflow happen and extract x/y components from
2400 * the new value.
2401 */
2402
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28212 times.
28212 if (ctx->width > 761) {
2403 index = (int16_t)(my * ctx->width + mx);
2404 mx = index % ctx->width;
2405 my = index / ctx->width;
2406 }
2407
1/2
✓ Branch 1 taken 28212 times.
✗ Branch 2 not taken.
28212 if (good_mvec(ctx, cx, cy, mx, my, blk_size)) {
2408 28212 copy_block(ctx->frm0 + cx + ctx->pitch * cy,
2409 28212 ctx->frm2 + cx + mx + ctx->pitch * (cy + my),
2410 blk_size, ctx->pitch);
2411 }
2412 28212 break;
2413 2164 case 0xF5:
2414
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2164 times.
2164 if (bytestream2_get_bytes_left(&ctx->gb) < 2)
2415 return AVERROR_INVALIDDATA;
2416 2164 index = bytestream2_get_le16u(&ctx->gb);
2417
2418 2164 mx = index % ctx->width;
2419 2164 my = index / ctx->width;
2420
2421
1/2
✓ Branch 1 taken 2164 times.
✗ Branch 2 not taken.
2164 if (good_mvec(ctx, cx, cy, mx, my, blk_size)) {
2422 2164 copy_block(ctx->frm0 + cx + ctx->pitch * cy,
2423 2164 ctx->frm2 + cx + mx + ctx->pitch * (cy + my),
2424 blk_size, ctx->pitch);
2425 }
2426 2164 break;
2427 12588 case 0xF6:
2428 12588 copy_block(ctx->frm0 + cx + ctx->pitch * cy,
2429 12588 ctx->frm1 + cx + ctx->pitch * cy,
2430 blk_size, ctx->pitch);
2431 12588 break;
2432 8029 case 0xF7:
2433 8029 opcode_0xf7(ctx, cx, cy, blk_size, ctx->pitch);
2434 8029 break;
2435
2436 1169 case 0xF8:
2437 1169 opcode_0xf8(ctx, cx, cy, blk_size, ctx->pitch);
2438 1169 break;
2439 315 case 0xF9:
2440 case 0xFA:
2441 case 0xFB:
2442 case 0xFC:
2443 315 fill_block(ctx->frm0 + cx + cy * ctx->pitch,
2444 315 ctx->small_codebook[opcode - 0xf9], blk_size, ctx->pitch);
2445 315 break;
2446 5496 case 0xFD:
2447
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5496 times.
5496 if (bytestream2_get_bytes_left(&ctx->gb) < 1)
2448 return AVERROR_INVALIDDATA;
2449 10992 fill_block(ctx->frm0 + cx + cy * ctx->pitch,
2450 5496 ctx->codebook[bytestream2_get_byteu(&ctx->gb)], blk_size, ctx->pitch);
2451 5496 break;
2452 2102 case 0xFE:
2453
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2102 times.
2102 if (bytestream2_get_bytes_left(&ctx->gb) < 2)
2454 return AVERROR_INVALIDDATA;
2455 2102 fill_block(ctx->frm0 + cx + cy * ctx->pitch,
2456 2102 bytestream2_get_le16u(&ctx->gb), blk_size, ctx->pitch);
2457 2102 break;
2458 11560 case 0xFF:
2459
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11560 times.
11560 if (blk_size == 2) {
2460 opcode_0xf8(ctx, cx, cy, blk_size, ctx->pitch);
2461 } else {
2462 11560 blk_size >>= 1;
2463
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 11560 times.
11560 if (bl16_block(ctx, cx, cy, blk_size))
2464 return AVERROR_INVALIDDATA;
2465
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 11560 times.
11560 if (bl16_block(ctx, cx + blk_size, cy, blk_size))
2466 return AVERROR_INVALIDDATA;
2467
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 11560 times.
11560 if (bl16_block(ctx, cx, cy + blk_size, blk_size))
2468 return AVERROR_INVALIDDATA;
2469
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 11560 times.
11560 if (bl16_block(ctx, cx + blk_size, cy + blk_size, blk_size))
2470 return AVERROR_INVALIDDATA;
2471 }
2472 11560 break;
2473 }
2474 71635 return 0;
2475 }
2476
2477 6 static int bl16_decode_2(SANMVideoContext *ctx)
2478 {
2479 int cx, cy, ret;
2480
2481
2/2
✓ Branch 0 taken 318 times.
✓ Branch 1 taken 5 times.
323 for (cy = 0; cy < ctx->aligned_height; cy += 8)
2482
2/2
✓ Branch 0 taken 25396 times.
✓ Branch 1 taken 317 times.
25713 for (cx = 0; cx < ctx->aligned_width; cx += 8)
2483
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 25395 times.
25396 if (ret = bl16_block(ctx, cx, cy, 8))
2484 1 return ret;
2485
2486 5 return 0;
2487 }
2488
2489 1 static int bl16_decode_5(SANMVideoContext *ctx, int rle_size)
2490 {
2491 #if HAVE_BIGENDIAN
2492 uint16_t *frm;
2493 int npixels;
2494 #endif
2495 1 uint8_t *dst = (uint8_t*)ctx->frm0;
2496
2497
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (rle_decode(ctx, &ctx->gb, dst, rle_size))
2498 return AVERROR_INVALIDDATA;
2499
2500 #if HAVE_BIGENDIAN
2501 npixels = ctx->npixels;
2502 frm = ctx->frm0;
2503 while (npixels--) {
2504 *frm = av_bswap16(*frm);
2505 frm++;
2506 }
2507 #endif
2508
2509 1 return 0;
2510 }
2511
2512 static int bl16_decode_6(SANMVideoContext *ctx)
2513 {
2514 int npixels = ctx->npixels;
2515 uint16_t *frm = ctx->frm0;
2516
2517 if (bytestream2_get_bytes_left(&ctx->gb) < npixels) {
2518 av_log(ctx->avctx, AV_LOG_ERROR, "Insufficient data for frame.\n");
2519 return AVERROR_INVALIDDATA;
2520 }
2521 while (npixels--)
2522 *frm++ = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
2523
2524 return 0;
2525 }
2526
2527 /* Quarter-sized keyframe encoded as stream of codebook indices. Interpolate
2528 * missing pixels by averaging the colors of immediate neighbours.
2529 * Identical to codec47_comp1(), but without the interpolation table.
2530 * tgsmush.dll c6f0
2531 */
2532 static int bl16_decode_7(SANMVideoContext *ctx)
2533 {
2534 uint16_t hh, hw, c1, c2, *dst1, *dst2;
2535
2536 if (bytestream2_get_bytes_left(&ctx->gb) < ((ctx->width * ctx->height) / 4))
2537 return AVERROR_INVALIDDATA;
2538
2539 hh = (ctx->height + 1) >> 1;
2540 dst1 = (uint16_t *)ctx->frm0 + ctx->pitch; /* start with line 1 */
2541 while (hh--) {
2542 hw = (ctx->width - 1) >> 1;
2543 c1 = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
2544 dst1[0] = c1; /* leftmost 2 pixels of a row are identical */
2545 dst1[1] = c1;
2546 dst2 = dst1 + 2;
2547 while (--hw) {
2548 c2 = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
2549 *dst2++ = bl16_c1_avg_col(c1, c2);
2550 *dst2++ = c2;
2551 c1 = c2;
2552 }
2553 dst1 += ctx->pitch * 2; /* skip to overnext line */
2554 }
2555 /* line 0 is a copy of line 1 */
2556 memcpy(ctx->frm0, ctx->frm0 + ctx->pitch, ctx->pitch);
2557
2558 /* complete the skipped lines by averaging from the pixels in the lines
2559 * above and below.
2560 */
2561 dst1 = ctx->frm0 + (ctx->pitch * 2);
2562 hh = (ctx->height - 1) >> 1;
2563 while (hh--) {
2564 hw = ctx->width;
2565 dst2 = dst1;
2566 while (hw--) {
2567 c1 = *(dst2 - ctx->pitch); /* pixel from line above */
2568 c2 = *(dst2 + ctx->pitch); /* pixel from line below */
2569 *dst2++ = bl16_c1_avg_col(c1, c2);
2570 }
2571 dst1 += ctx->pitch * 2;
2572 }
2573 return 0;
2574 }
2575
2576 static int bl16_decode_8(SANMVideoContext *ctx)
2577 {
2578 uint16_t *pdest = ctx->frm0;
2579 uint8_t *rsrc;
2580 long npixels = ctx->npixels;
2581
2582 av_fast_malloc(&ctx->rle_buf, &ctx->rle_buf_size, npixels);
2583 if (!ctx->rle_buf) {
2584 av_log(ctx->avctx, AV_LOG_ERROR, "RLE buffer allocation failed.\n");
2585 return AVERROR(ENOMEM);
2586 }
2587 rsrc = ctx->rle_buf;
2588
2589 if (rle_decode(ctx, &ctx->gb, rsrc, npixels))
2590 return AVERROR_INVALIDDATA;
2591
2592 while (npixels--)
2593 *pdest++ = ctx->codebook[*rsrc++];
2594
2595 return 0;
2596 }
2597
2598 2 static void fill_frame(uint16_t *pbuf, int buf_size, uint16_t color)
2599 {
2600
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (buf_size--) {
2601 2 *pbuf++ = color;
2602 2 av_memcpy_backptr((uint8_t*)pbuf, 2, 2*buf_size);
2603 }
2604 2 }
2605
2606 15 static int copy_output(SANMVideoContext *ctx, int sanm)
2607 {
2608 uint8_t *dst;
2609
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 const uint8_t *src = sanm ? (uint8_t *)ctx->frm0 : (uint8_t *)ctx->fbuf;
2610 15 int ret, height = ctx->height;
2611
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 ptrdiff_t dstpitch, srcpitch = ctx->pitch * (sanm ? sizeof(ctx->frm0[0]) : 1);
2612
2613
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
15 if ((ret = ff_get_buffer(ctx->avctx, ctx->frame, 0)) < 0)
2614 return ret;
2615
2616 15 dst = ctx->frame->data[0];
2617 15 dstpitch = ctx->frame->linesize[0];
2618
2619
2/2
✓ Branch 0 taken 7200 times.
✓ Branch 1 taken 15 times.
7215 while (height--) {
2620 7200 memcpy(dst, src, srcpitch);
2621 7200 src += srcpitch;
2622 7200 dst += dstpitch;
2623 }
2624
2625 15 return 0;
2626 }
2627
2628 16 static int decode_bl16(AVCodecContext *avctx,int *got_frame_ptr)
2629 {
2630 16 SANMVideoContext *ctx = avctx->priv_data;
2631 int i, ret, w, h, seq_num, codec, bg_color, rle_output_size, rcode;
2632
2633
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
16 if ((ret = bytestream2_get_bytes_left(&ctx->gb)) < 560) {
2634 av_log(ctx->avctx, AV_LOG_ERROR, "Input frame too short (%d bytes).\n",
2635 ret);
2636 return AVERROR_INVALIDDATA;
2637 }
2638 16 bytestream2_skip(&ctx->gb, 8); // skip pad
2639
2640 16 w = bytestream2_get_le32u(&ctx->gb);
2641 16 h = bytestream2_get_le32u(&ctx->gb);
2642
2643
2/4
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 16 times.
16 if (w != ctx->width || h != ctx->height) {
2644 avpriv_report_missing_feature(ctx->avctx, "Variable size frames");
2645 return AVERROR_PATCHWELCOME;
2646 }
2647
2648 16 seq_num = bytestream2_get_le16u(&ctx->gb);
2649 16 codec = bytestream2_get_byteu(&ctx->gb);
2650 16 rcode = bytestream2_get_byteu(&ctx->gb);
2651
2652 16 bytestream2_skip(&ctx->gb, 4); // skip pad
2653
2654
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 16 times.
80 for (i = 0; i < 4; i++)
2655 64 ctx->small_codebook[i] = bytestream2_get_le16u(&ctx->gb);
2656 16 bg_color = bytestream2_get_le16u(&ctx->gb);
2657
2658 16 bytestream2_skip(&ctx->gb, 2); // skip pad
2659
2660 16 rle_output_size = bytestream2_get_le32u(&ctx->gb);
2661
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (rle_output_size > w * ctx->aligned_height * 2) {
2662 av_log(avctx, AV_LOG_WARNING, "bl16 rle size too large, truncated: %d\n",
2663 rle_output_size);
2664 rle_output_size = w * ctx->aligned_height * 2;
2665 }
2666
2667
2/2
✓ Branch 0 taken 4096 times.
✓ Branch 1 taken 16 times.
4112 for (i = 0; i < 256; i++)
2668 4096 ctx->codebook[i] = bytestream2_get_le16u(&ctx->gb);
2669
2670 16 bytestream2_skip(&ctx->gb, 8); // skip pad
2671
2672
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 15 times.
16 if (seq_num == 0) {
2673 1 ctx->frame->flags |= AV_FRAME_FLAG_KEY;
2674 1 ctx->frame->pict_type = AV_PICTURE_TYPE_I;
2675 1 fill_frame(ctx->frm1, ctx->npixels, bg_color);
2676 1 fill_frame(ctx->frm2, ctx->npixels, bg_color);
2677 } else {
2678 15 ctx->frame->flags &= ~AV_FRAME_FLAG_KEY;
2679 15 ctx->frame->pict_type = AV_PICTURE_TYPE_P;
2680 }
2681
2682 16 ret = 0;
2683
3/10
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
16 switch (codec) {
2684 case 0: ret = bl16_decode_0(ctx); break;
2685 case 1: ret = bl16_decode_1(ctx); break;
2686 6 case 2: ret = bl16_decode_2(ctx); break;
2687 case 3: memcpy(ctx->frm0, ctx->frm2, ctx->frm2_size); break;
2688 9 case 4: memcpy(ctx->frm0, ctx->frm1, ctx->frm1_size); break;
2689 1 case 5: ret = bl16_decode_5(ctx, rle_output_size); break;
2690 case 6: ret = bl16_decode_6(ctx); break;
2691 case 7: ret = bl16_decode_7(ctx); break;
2692 case 8: ret = bl16_decode_8(ctx); break;
2693 default:
2694 avpriv_request_sample(ctx->avctx, "Unknown/unsupported compression type %d", codec);
2695 return AVERROR_PATCHWELCOME;
2696 }
2697
2698
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 15 times.
16 if (ret) {
2699 1 av_log(avctx, AV_LOG_ERROR,
2700 "Subcodec %d: error decoding frame.\n", codec);
2701 1 return ret;
2702 }
2703
2704 15 ret = copy_output(ctx, 1);
2705
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 6 times.
15 if (rcode)
2706 9 rotate_bufs(ctx, rcode);
2707
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (ret)
2708 return ret;
2709
2710 15 *got_frame_ptr = 1;
2711 15 return 0;
2712 }
2713
2714 static int decode_anim(AVCodecContext *avctx, int *got_frame_ptr)
2715 {
2716 SANMVideoContext *ctx = avctx->priv_data;
2717 int i, ret, to_store = 0, have_img = 0;
2718
2719 ctx->first_fob = 1;
2720 while (bytestream2_get_bytes_left(&ctx->gb) >= 8) {
2721 uint32_t sig, size;
2722 int pos;
2723
2724 sig = bytestream2_get_be32u(&ctx->gb);
2725 size = bytestream2_get_be32u(&ctx->gb);
2726 pos = bytestream2_tell(&ctx->gb);
2727
2728 if (bytestream2_get_bytes_left(&ctx->gb) < size) {
2729 av_log(avctx, AV_LOG_ERROR, "Incorrect chunk size %"PRIu32".\n", size);
2730 break;
2731 }
2732 switch (sig) {
2733 case MKBETAG('N', 'P', 'A', 'L'):
2734 if (size != PALETTE_SIZE * 3) {
2735 av_log(avctx, AV_LOG_ERROR,
2736 "Incorrect palette block size %"PRIu32".\n", size);
2737 return AVERROR_INVALIDDATA;
2738 }
2739 for (i = 0; i < PALETTE_SIZE; i++)
2740 ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb);
2741 if (ctx->subversion < 2)
2742 ctx->pal[0] = 0xFFU << 24;
2743 break;
2744 case MKBETAG('F', 'O', 'B', 'J'):
2745 if (size < 16)
2746 return AVERROR_INVALIDDATA;
2747 GetByteContext fc;
2748 bytestream2_init(&fc, ctx->gb.buffer, size);
2749 if (ret = process_frame_obj(ctx, &fc, 0, 0)) {
2750 return ret;
2751 }
2752 have_img = 1;
2753
2754 /* STOR: for ANIMv0/1 store the whole FOBJ datablock, as it
2755 * needs to be replayed on FTCH, since none of the codecs
2756 * it uses work on the full buffer.
2757 * For ANIMv2, it's enough to store the current framebuffer.
2758 */
2759 if (to_store) {
2760 to_store = 0;
2761 if (ctx->subversion < 2) {
2762 if (size <= ctx->stored_frame_size) {
2763 bytestream2_seek(&fc, 0, SEEK_SET);
2764 bytestream2_get_bufferu(&fc, ctx->stored_frame, size);
2765 ctx->stor_size = size;
2766 } else {
2767 av_log(avctx, AV_LOG_ERROR, "FOBJ too large for STOR\n");
2768 ret = AVERROR(ENOMEM);
2769 }
2770 } else {
2771 memcpy(ctx->stored_frame, ctx->fbuf, ctx->buf_size);
2772 ctx->stor_size = ctx->buf_size;
2773 }
2774 }
2775 bytestream2_skip(&ctx->gb, size);
2776 break;
2777 case MKBETAG('X', 'P', 'A', 'L'):
2778 if (ret = process_xpal(ctx, size))
2779 return ret;
2780 break;
2781 case MKBETAG('S', 'T', 'O', 'R'):
2782 to_store = 1;
2783 break;
2784 case MKBETAG('F', 'T', 'C', 'H'):
2785 if (ctx->subversion < 2) {
2786 if ((ret = process_ftch(ctx, size)) < 0)
2787 return ret;
2788 have_img = (ret == 0) ? 1 : 0;
2789 } else {
2790 if (ctx->stor_size > 0) {
2791 memcpy(ctx->fbuf, ctx->stored_frame, ctx->buf_size);
2792 have_img = 1;
2793 }
2794 }
2795 break;
2796 default:
2797 bytestream2_skip(&ctx->gb, size);
2798 av_log(avctx, AV_LOG_DEBUG,
2799 "Unknown/unsupported chunk %"PRIx32".\n", sig);
2800 break;
2801 }
2802
2803 /* the sizes of chunks are usually a multiple of 2. However
2804 * there are a few unaligned FOBJs in RA1 L2PLAY.ANM only (looks
2805 * like a game bug) and IACT audio chunks which have odd sizes
2806 * but are padded with a zero byte.
2807 */
2808 bytestream2_seek(&ctx->gb, pos + size, SEEK_SET);
2809 if ((pos + size) & 1) {
2810 if (bytestream2_peek_byte(&ctx->gb) == 0)
2811 bytestream2_skip(&ctx->gb, 1);
2812 }
2813 }
2814
2815 if (have_img) {
2816 if ((ret = copy_output(ctx, 0)))
2817 return ret;
2818 memcpy(ctx->frame->data[1], ctx->pal, 1024);
2819 *got_frame_ptr = 1;
2820 }
2821 return 0;
2822 }
2823
2824 16 static int decode_frame(AVCodecContext *avctx, AVFrame *frame,
2825 int *got_frame_ptr, AVPacket *pkt)
2826 {
2827 16 SANMVideoContext *ctx = avctx->priv_data;
2828 int ret;
2829
2830 16 ctx->frame = frame;
2831 16 bytestream2_init(&ctx->gb, pkt->data, pkt->size);
2832
2833
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (!ctx->version) {
2834 if ((ret = decode_anim(avctx, got_frame_ptr)))
2835 return ret;
2836 } else {
2837
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 15 times.
16 if ((ret = decode_bl16(avctx, got_frame_ptr)))
2838 1 return ret;
2839 }
2840 15 return pkt->size;
2841 }
2842
2843 const FFCodec ff_sanm_decoder = {
2844 .p.name = "sanm",
2845 CODEC_LONG_NAME("LucasArts SANM/Smush video"),
2846 .p.type = AVMEDIA_TYPE_VIDEO,
2847 .p.id = AV_CODEC_ID_SANM,
2848 .priv_data_size = sizeof(SANMVideoContext),
2849 .init = decode_init,
2850 .close = decode_end,
2851 FF_CODEC_DECODE_CB(decode_frame),
2852 .p.capabilities = AV_CODEC_CAP_DR1,
2853 };
2854