GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavcodec/sanm.c Lines: 325 767 42.4 %
Date: 2020-09-25 23:16:12 Branches: 164 466 35.2 %

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/bswap.h"
25
#include "libavutil/imgutils.h"
26
27
#include "avcodec.h"
28
#include "bytestream.h"
29
#include "copy_block.h"
30
#include "internal.h"
31
32
#define NGLYPHS 256
33
#define GLYPH_COORD_VECT_SIZE 16
34
#define PALETTE_SIZE 256
35
#define PALETTE_DELTA 768
36
37
static const int8_t glyph4_x[GLYPH_COORD_VECT_SIZE] = {
38
    0, 1, 2, 3, 3, 3, 3, 2, 1, 0, 0, 0, 1, 2, 2, 1
39
};
40
41
static const int8_t glyph4_y[GLYPH_COORD_VECT_SIZE] = {
42
    0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 2, 1, 1, 1, 2, 2
43
};
44
45
static const int8_t glyph8_x[GLYPH_COORD_VECT_SIZE] = {
46
    0, 2, 5, 7, 7, 7, 7, 7, 7, 5, 2, 0, 0, 0, 0, 0
47
};
48
49
static const int8_t glyph8_y[GLYPH_COORD_VECT_SIZE] = {
50
    0, 0, 0, 0, 1, 3, 4, 6, 7, 7, 7, 7, 6, 4, 3, 1
51
};
52
53
static const int8_t motion_vectors[256][2] = {
54
    {   0,   0 }, {  -1, -43 }, {   6, -43 }, {  -9, -42 }, {  13, -41 },
55
    { -16, -40 }, {  19, -39 }, { -23, -36 }, {  26, -34 }, {  -2, -33 },
56
    {   4, -33 }, { -29, -32 }, {  -9, -32 }, {  11, -31 }, { -16, -29 },
57
    {  32, -29 }, {  18, -28 }, { -34, -26 }, { -22, -25 }, {  -1, -25 },
58
    {   3, -25 }, {  -7, -24 }, {   8, -24 }, {  24, -23 }, {  36, -23 },
59
    { -12, -22 }, {  13, -21 }, { -38, -20 }, {   0, -20 }, { -27, -19 },
60
    {  -4, -19 }, {   4, -19 }, { -17, -18 }, {  -8, -17 }, {   8, -17 },
61
    {  18, -17 }, {  28, -17 }, {  39, -17 }, { -12, -15 }, {  12, -15 },
62
    { -21, -14 }, {  -1, -14 }, {   1, -14 }, { -41, -13 }, {  -5, -13 },
63
    {   5, -13 }, {  21, -13 }, { -31, -12 }, { -15, -11 }, {  -8, -11 },
64
    {   8, -11 }, {  15, -11 }, {  -2, -10 }, {   1, -10 }, {  31, -10 },
65
    { -23,  -9 }, { -11,  -9 }, {  -5,  -9 }, {   4,  -9 }, {  11,  -9 },
66
    {  42,  -9 }, {   6,  -8 }, {  24,  -8 }, { -18,  -7 }, {  -7,  -7 },
67
    {  -3,  -7 }, {  -1,  -7 }, {   2,  -7 }, {  18,  -7 }, { -43,  -6 },
68
    { -13,  -6 }, {  -4,  -6 }, {   4,  -6 }, {   8,  -6 }, { -33,  -5 },
69
    {  -9,  -5 }, {  -2,  -5 }, {   0,  -5 }, {   2,  -5 }, {   5,  -5 },
70
    {  13,  -5 }, { -25,  -4 }, {  -6,  -4 }, {  -3,  -4 }, {   3,  -4 },
71
    {   9,  -4 }, { -19,  -3 }, {  -7,  -3 }, {  -4,  -3 }, {  -2,  -3 },
72
    {  -1,  -3 }, {   0,  -3 }, {   1,  -3 }, {   2,  -3 }, {   4,  -3 },
73
    {   6,  -3 }, {  33,  -3 }, { -14,  -2 }, { -10,  -2 }, {  -5,  -2 },
74
    {  -3,  -2 }, {  -2,  -2 }, {  -1,  -2 }, {   0,  -2 }, {   1,  -2 },
75
    {   2,  -2 }, {   3,  -2 }, {   5,  -2 }, {   7,  -2 }, {  14,  -2 },
76
    {  19,  -2 }, {  25,  -2 }, {  43,  -2 }, {  -7,  -1 }, {  -3,  -1 },
77
    {  -2,  -1 }, {  -1,  -1 }, {   0,  -1 }, {   1,  -1 }, {   2,  -1 },
78
    {   3,  -1 }, {  10,  -1 }, {  -5,   0 }, {  -3,   0 }, {  -2,   0 },
79
    {  -1,   0 }, {   1,   0 }, {   2,   0 }, {   3,   0 }, {   5,   0 },
80
    {   7,   0 }, { -10,   1 }, {  -7,   1 }, {  -3,   1 }, {  -2,   1 },
81
    {  -1,   1 }, {   0,   1 }, {   1,   1 }, {   2,   1 }, {   3,   1 },
82
    { -43,   2 }, { -25,   2 }, { -19,   2 }, { -14,   2 }, {  -5,   2 },
83
    {  -3,   2 }, {  -2,   2 }, {  -1,   2 }, {   0,   2 }, {   1,   2 },
84
    {   2,   2 }, {   3,   2 }, {   5,   2 }, {   7,   2 }, {  10,   2 },
85
    {  14,   2 }, { -33,   3 }, {  -6,   3 }, {  -4,   3 }, {  -2,   3 },
86
    {  -1,   3 }, {   0,   3 }, {   1,   3 }, {   2,   3 }, {   4,   3 },
87
    {  19,   3 }, {  -9,   4 }, {  -3,   4 }, {   3,   4 }, {   7,   4 },
88
    {  25,   4 }, { -13,   5 }, {  -5,   5 }, {  -2,   5 }, {   0,   5 },
89
    {   2,   5 }, {   5,   5 }, {   9,   5 }, {  33,   5 }, {  -8,   6 },
90
    {  -4,   6 }, {   4,   6 }, {  13,   6 }, {  43,   6 }, { -18,   7 },
91
    {  -2,   7 }, {   0,   7 }, {   2,   7 }, {   7,   7 }, {  18,   7 },
92
    { -24,   8 }, {  -6,   8 }, { -42,   9 }, { -11,   9 }, {  -4,   9 },
93
    {   5,   9 }, {  11,   9 }, {  23,   9 }, { -31,  10 }, {  -1,  10 },
94
    {   2,  10 }, { -15,  11 }, {  -8,  11 }, {   8,  11 }, {  15,  11 },
95
    {  31,  12 }, { -21,  13 }, {  -5,  13 }, {   5,  13 }, {  41,  13 },
96
    {  -1,  14 }, {   1,  14 }, {  21,  14 }, { -12,  15 }, {  12,  15 },
97
    { -39,  17 }, { -28,  17 }, { -18,  17 }, {  -8,  17 }, {   8,  17 },
98
    {  17,  18 }, {  -4,  19 }, {   0,  19 }, {   4,  19 }, {  27,  19 },
99
    {  38,  20 }, { -13,  21 }, {  12,  22 }, { -36,  23 }, { -24,  23 },
100
    {  -8,  24 }, {   7,  24 }, {  -3,  25 }, {   1,  25 }, {  22,  25 },
101
    {  34,  26 }, { -18,  28 }, { -32,  29 }, {  16,  29 }, { -11,  31 },
102
    {   9,  32 }, {  29,  32 }, {  -4,  33 }, {   2,  33 }, { -26,  34 },
103
    {  23,  36 }, { -19,  39 }, {  16,  40 }, { -13,  41 }, {   9,  42 },
104
    {  -6,  43 }, {   1,  43 }, {   0,   0 }, {   0,   0 }, {   0,   0 },
105
};
106
107
static const int8_t c37_mv[] = {
108
    0,   0,   1,   0,   2,   0,   3,   0,   5,   0,
109
    8,   0,  13,   0,  21,   0,  -1,   0,  -2,   0,
110
   -3,   0,  -5,   0,  -8,   0, -13,   0, -17,   0,
111
  -21,   0,   0,   1,   1,   1,   2,   1,   3,   1,
112
    5,   1,   8,   1,  13,   1,  21,   1,  -1,   1,
113
   -2,   1,  -3,   1,  -5,   1,  -8,   1, -13,   1,
114
  -17,   1, -21,   1,   0,   2,   1,   2,   2,   2,
115
    3,   2,   5,   2,   8,   2,  13,   2,  21,   2,
116
   -1,   2,  -2,   2,  -3,   2,  -5,   2,  -8,   2,
117
  -13,   2, -17,   2, -21,   2,   0,   3,   1,   3,
118
    2,   3,   3,   3,   5,   3,   8,   3,  13,   3,
119
   21,   3,  -1,   3,  -2,   3,  -3,   3,  -5,   3,
120
   -8,   3, -13,   3, -17,   3, -21,   3,   0,   5,
121
    1,   5,   2,   5,   3,   5,   5,   5,   8,   5,
122
   13,   5,  21,   5,  -1,   5,  -2,   5,  -3,   5,
123
   -5,   5,  -8,   5, -13,   5, -17,   5, -21,   5,
124
    0,   8,   1,   8,   2,   8,   3,   8,   5,   8,
125
    8,   8,  13,   8,  21,   8,  -1,   8,  -2,   8,
126
   -3,   8,  -5,   8,  -8,   8, -13,   8, -17,   8,
127
  -21,   8,   0,  13,   1,  13,   2,  13,   3,  13,
128
    5,  13,   8,  13,  13,  13,  21,  13,  -1,  13,
129
   -2,  13,  -3,  13,  -5,  13,  -8,  13, -13,  13,
130
  -17,  13, -21,  13,   0,  21,   1,  21,   2,  21,
131
    3,  21,   5,  21,   8,  21,  13,  21,  21,  21,
132
   -1,  21,  -2,  21,  -3,  21,  -5,  21,  -8,  21,
133
  -13,  21, -17,  21, -21,  21,   0,  -1,   1,  -1,
134
    2,  -1,   3,  -1,   5,  -1,   8,  -1,  13,  -1,
135
   21,  -1,  -1,  -1,  -2,  -1,  -3,  -1,  -5,  -1,
136
   -8,  -1, -13,  -1, -17,  -1, -21,  -1,   0,  -2,
137
    1,  -2,   2,  -2,   3,  -2,   5,  -2,   8,  -2,
138
   13,  -2,  21,  -2,  -1,  -2,  -2,  -2,  -3,  -2,
139
   -5,  -2,  -8,  -2, -13,  -2, -17,  -2, -21,  -2,
140
    0,  -3,   1,  -3,   2,  -3,   3,  -3,   5,  -3,
141
    8,  -3,  13,  -3,  21,  -3,  -1,  -3,  -2,  -3,
142
   -3,  -3,  -5,  -3,  -8,  -3, -13,  -3, -17,  -3,
143
  -21,  -3,   0,  -5,   1,  -5,   2,  -5,   3,  -5,
144
    5,  -5,   8,  -5,  13,  -5,  21,  -5,  -1,  -5,
145
   -2,  -5,  -3,  -5,  -5,  -5,  -8,  -5, -13,  -5,
146
  -17,  -5, -21,  -5,   0,  -8,   1,  -8,   2,  -8,
147
    3,  -8,   5,  -8,   8,  -8,  13,  -8,  21,  -8,
148
   -1,  -8,  -2,  -8,  -3,  -8,  -5,  -8,  -8,  -8,
149
  -13,  -8, -17,  -8, -21,  -8,   0, -13,   1, -13,
150
    2, -13,   3, -13,   5, -13,   8, -13,  13, -13,
151
   21, -13,  -1, -13,  -2, -13,  -3, -13,  -5, -13,
152
   -8, -13, -13, -13, -17, -13, -21, -13,   0, -17,
153
    1, -17,   2, -17,   3, -17,   5, -17,   8, -17,
154
   13, -17,  21, -17,  -1, -17,  -2, -17,  -3, -17,
155
   -5, -17,  -8, -17, -13, -17, -17, -17, -21, -17,
156
    0, -21,   1, -21,   2, -21,   3, -21,   5, -21,
157
    8, -21,  13, -21,  21, -21,  -1, -21,  -2, -21,
158
   -3, -21,  -5, -21,  -8, -21, -13, -21, -17, -21,
159
    0,   0,  -8, -29,   8, -29, -18, -25,  17, -25,
160
    0, -23,  -6, -22,   6, -22, -13, -19,  12, -19,
161
    0, -18,  25, -18, -25, -17,  -5, -17,   5, -17,
162
  -10, -15,  10, -15,   0, -14,  -4, -13,   4, -13,
163
   19, -13, -19, -12,  -8, -11,  -2, -11,   0, -11,
164
    2, -11,   8, -11, -15, -10,  -4, -10,   4, -10,
165
   15, -10,  -6,  -9,  -1,  -9,   1,  -9,   6,  -9,
166
  -29,  -8, -11,  -8,  -8,  -8,  -3,  -8,   3,  -8,
167
    8,  -8,  11,  -8,  29,  -8,  -5,  -7,  -2,  -7,
168
    0,  -7,   2,  -7,   5,  -7, -22,  -6,  -9,  -6,
169
   -6,  -6,  -3,  -6,  -1,  -6,   1,  -6,   3,  -6,
170
    6,  -6,   9,  -6,  22,  -6, -17,  -5,  -7,  -5,
171
   -4,  -5,  -2,  -5,   0,  -5,   2,  -5,   4,  -5,
172
    7,  -5,  17,  -5, -13,  -4, -10,  -4,  -5,  -4,
173
   -3,  -4,  -1,  -4,   0,  -4,   1,  -4,   3,  -4,
174
    5,  -4,  10,  -4,  13,  -4,  -8,  -3,  -6,  -3,
175
   -4,  -3,  -3,  -3,  -2,  -3,  -1,  -3,   0,  -3,
176
    1,  -3,   2,  -3,   4,  -3,   6,  -3,   8,  -3,
177
  -11,  -2,  -7,  -2,  -5,  -2,  -3,  -2,  -2,  -2,
178
   -1,  -2,   0,  -2,   1,  -2,   2,  -2,   3,  -2,
179
    5,  -2,   7,  -2,  11,  -2,  -9,  -1,  -6,  -1,
180
   -4,  -1,  -3,  -1,  -2,  -1,  -1,  -1,   0,  -1,
181
    1,  -1,   2,  -1,   3,  -1,   4,  -1,   6,  -1,
182
    9,  -1, -31,   0, -23,   0, -18,   0, -14,   0,
183
  -11,   0,  -7,   0,  -5,   0,  -4,   0,  -3,   0,
184
   -2,   0,  -1,   0,   0, -31,   1,   0,   2,   0,
185
    3,   0,   4,   0,   5,   0,   7,   0,  11,   0,
186
   14,   0,  18,   0,  23,   0,  31,   0,  -9,   1,
187
   -6,   1,  -4,   1,  -3,   1,  -2,   1,  -1,   1,
188
    0,   1,   1,   1,   2,   1,   3,   1,   4,   1,
189
    6,   1,   9,   1, -11,   2,  -7,   2,  -5,   2,
190
   -3,   2,  -2,   2,  -1,   2,   0,   2,   1,   2,
191
    2,   2,   3,   2,   5,   2,   7,   2,  11,   2,
192
   -8,   3,  -6,   3,  -4,   3,  -2,   3,  -1,   3,
193
    0,   3,   1,   3,   2,   3,   3,   3,   4,   3,
194
    6,   3,   8,   3, -13,   4, -10,   4,  -5,   4,
195
   -3,   4,  -1,   4,   0,   4,   1,   4,   3,   4,
196
    5,   4,  10,   4,  13,   4, -17,   5,  -7,   5,
197
   -4,   5,  -2,   5,   0,   5,   2,   5,   4,   5,
198
    7,   5,  17,   5, -22,   6,  -9,   6,  -6,   6,
199
   -3,   6,  -1,   6,   1,   6,   3,   6,   6,   6,
200
    9,   6,  22,   6,  -5,   7,  -2,   7,   0,   7,
201
    2,   7,   5,   7, -29,   8, -11,   8,  -8,   8,
202
   -3,   8,   3,   8,   8,   8,  11,   8,  29,   8,
203
   -6,   9,  -1,   9,   1,   9,   6,   9, -15,  10,
204
   -4,  10,   4,  10,  15,  10,  -8,  11,  -2,  11,
205
    0,  11,   2,  11,   8,  11,  19,  12, -19,  13,
206
   -4,  13,   4,  13,   0,  14, -10,  15,  10,  15,
207
   -5,  17,   5,  17,  25,  17, -25,  18,   0,  18,
208
  -12,  19,  13,  19,  -6,  22,   6,  22,   0,  23,
209
  -17,  25,  18,  25,  -8,  29,   8,  29,   0,  31,
210
    0,   0,  -6, -22,   6, -22, -13, -19,  12, -19,
211
    0, -18,  -5, -17,   5, -17, -10, -15,  10, -15,
212
    0, -14,  -4, -13,   4, -13,  19, -13, -19, -12,
213
   -8, -11,  -2, -11,   0, -11,   2, -11,   8, -11,
214
  -15, -10,  -4, -10,   4, -10,  15, -10,  -6,  -9,
215
   -1,  -9,   1,  -9,   6,  -9, -11,  -8,  -8,  -8,
216
   -3,  -8,   0,  -8,   3,  -8,   8,  -8,  11,  -8,
217
   -5,  -7,  -2,  -7,   0,  -7,   2,  -7,   5,  -7,
218
  -22,  -6,  -9,  -6,  -6,  -6,  -3,  -6,  -1,  -6,
219
    1,  -6,   3,  -6,   6,  -6,   9,  -6,  22,  -6,
220
  -17,  -5,  -7,  -5,  -4,  -5,  -2,  -5,  -1,  -5,
221
    0,  -5,   1,  -5,   2,  -5,   4,  -5,   7,  -5,
222
   17,  -5, -13,  -4, -10,  -4,  -5,  -4,  -3,  -4,
223
   -2,  -4,  -1,  -4,   0,  -4,   1,  -4,   2,  -4,
224
    3,  -4,   5,  -4,  10,  -4,  13,  -4,  -8,  -3,
225
   -6,  -3,  -4,  -3,  -3,  -3,  -2,  -3,  -1,  -3,
226
    0,  -3,   1,  -3,   2,  -3,   3,  -3,   4,  -3,
227
    6,  -3,   8,  -3, -11,  -2,  -7,  -2,  -5,  -2,
228
   -4,  -2,  -3,  -2,  -2,  -2,  -1,  -2,   0,  -2,
229
    1,  -2,   2,  -2,   3,  -2,   4,  -2,   5,  -2,
230
    7,  -2,  11,  -2,  -9,  -1,  -6,  -1,  -5,  -1,
231
   -4,  -1,  -3,  -1,  -2,  -1,  -1,  -1,   0,  -1,
232
    1,  -1,   2,  -1,   3,  -1,   4,  -1,   5,  -1,
233
    6,  -1,   9,  -1, -23,   0, -18,   0, -14,   0,
234
  -11,   0,  -7,   0,  -5,   0,  -4,   0,  -3,   0,
235
   -2,   0,  -1,   0,   0, -23,   1,   0,   2,   0,
236
    3,   0,   4,   0,   5,   0,   7,   0,  11,   0,
237
   14,   0,  18,   0,  23,   0,  -9,   1,  -6,   1,
238
   -5,   1,  -4,   1,  -3,   1,  -2,   1,  -1,   1,
239
    0,   1,   1,   1,   2,   1,   3,   1,   4,   1,
240
    5,   1,   6,   1,   9,   1, -11,   2,  -7,   2,
241
   -5,   2,  -4,   2,  -3,   2,  -2,   2,  -1,   2,
242
    0,   2,   1,   2,   2,   2,   3,   2,   4,   2,
243
    5,   2,   7,   2,  11,   2,  -8,   3,  -6,   3,
244
   -4,   3,  -3,   3,  -2,   3,  -1,   3,   0,   3,
245
    1,   3,   2,   3,   3,   3,   4,   3,   6,   3,
246
    8,   3, -13,   4, -10,   4,  -5,   4,  -3,   4,
247
   -2,   4,  -1,   4,   0,   4,   1,   4,   2,   4,
248
    3,   4,   5,   4,  10,   4,  13,   4, -17,   5,
249
   -7,   5,  -4,   5,  -2,   5,  -1,   5,   0,   5,
250
    1,   5,   2,   5,   4,   5,   7,   5,  17,   5,
251
  -22,   6,  -9,   6,  -6,   6,  -3,   6,  -1,   6,
252
    1,   6,   3,   6,   6,   6,   9,   6,  22,   6,
253
   -5,   7,  -2,   7,   0,   7,   2,   7,   5,   7,
254
  -11,   8,  -8,   8,  -3,   8,   0,   8,   3,   8,
255
    8,   8,  11,   8,  -6,   9,  -1,   9,   1,   9,
256
    6,   9, -15,  10,  -4,  10,   4,  10,  15,  10,
257
   -8,  11,  -2,  11,   0,  11,   2,  11,   8,  11,
258
   19,  12, -19,  13,  -4,  13,   4,  13,   0,  14,
259
  -10,  15,  10,  15,  -5,  17,   5,  17,   0,  18,
260
  -12,  19,  13,  19,  -6,  22,   6,  22,   0,  23,
261
};
262
263
typedef struct SANMVideoContext {
264
    AVCodecContext *avctx;
265
    GetByteContext gb;
266
267
    int version, subversion;
268
    uint32_t pal[PALETTE_SIZE];
269
    int16_t delta_pal[PALETTE_DELTA];
270
271
    ptrdiff_t pitch;
272
    int width, height;
273
    int aligned_width, aligned_height;
274
    int prev_seq;
275
276
    AVFrame *frame;
277
    uint16_t *frm0, *frm1, *frm2;
278
    uint8_t *stored_frame;
279
    uint32_t frm0_size, frm1_size, frm2_size;
280
    uint32_t stored_frame_size;
281
282
    uint8_t *rle_buf;
283
    unsigned int rle_buf_size;
284
285
    int rotate_code;
286
287
    long npixels, buf_size;
288
289
    uint16_t codebook[256];
290
    uint16_t small_codebook[4];
291
292
    int8_t p4x4glyphs[NGLYPHS][16];
293
    int8_t p8x8glyphs[NGLYPHS][64];
294
} SANMVideoContext;
295
296
typedef struct SANMFrameHeader {
297
    int seq_num, codec, rotate_code, rle_output_size;
298
299
    uint16_t bg_color;
300
    uint32_t width, height;
301
} SANMFrameHeader;
302
303
enum GlyphEdge {
304
    LEFT_EDGE,
305
    TOP_EDGE,
306
    RIGHT_EDGE,
307
    BOTTOM_EDGE,
308
    NO_EDGE
309
};
310
311
enum GlyphDir {
312
    DIR_LEFT,
313
    DIR_UP,
314
    DIR_RIGHT,
315
    DIR_DOWN,
316
    NO_DIR
317
};
318
319
/**
320
 * Return enum GlyphEdge of box where point (x, y) lies.
321
 *
322
 * @param x x point coordinate
323
 * @param y y point coordinate
324
 * @param edge_size box width/height.
325
 */
326
1632
static enum GlyphEdge which_edge(int x, int y, int edge_size)
327
{
328
1632
    const int edge_max = edge_size - 1;
329
330
1632
    if (!y)
331
408
        return BOTTOM_EDGE;
332
1224
    else if (y == edge_max)
333
408
        return TOP_EDGE;
334
816
    else if (!x)
335
306
        return LEFT_EDGE;
336
510
    else if (x == edge_max)
337
306
        return RIGHT_EDGE;
338
    else
339
204
        return NO_EDGE;
340
}
341
342
1536
static enum GlyphDir which_direction(enum GlyphEdge edge0, enum GlyphEdge edge1)
343
{
344

1536
    if ((edge0 == LEFT_EDGE && edge1 == RIGHT_EDGE) ||
345

1476
        (edge1 == LEFT_EDGE && edge0 == RIGHT_EDGE) ||
346

1416
        (edge0 == BOTTOM_EDGE && edge1 != TOP_EDGE) ||
347
288
        (edge1 == BOTTOM_EDGE && edge0 != TOP_EDGE))
348
600
        return DIR_UP;
349

936
    else if ((edge0 == TOP_EDGE && edge1 != BOTTOM_EDGE) ||
350
288
             (edge1 == TOP_EDGE && edge0 != BOTTOM_EDGE))
351
480
        return DIR_DOWN;
352

456
    else if ((edge0 == LEFT_EDGE && edge1 != RIGHT_EDGE) ||
353
24
             (edge1 == LEFT_EDGE && edge0 != RIGHT_EDGE))
354
108
        return DIR_LEFT;
355

348
    else if ((edge0 == TOP_EDGE && edge1 == BOTTOM_EDGE) ||
356

252
             (edge1 == TOP_EDGE && edge0 == BOTTOM_EDGE) ||
357

156
             (edge0 == RIGHT_EDGE && edge1 != LEFT_EDGE) ||
358
24
             (edge1 == RIGHT_EDGE && edge0 != LEFT_EDGE))
359
300
        return DIR_RIGHT;
360
361
48
    return NO_DIR;
362
}
363
364
/* Interpolate two points. */
365
6600
static void interp_point(int8_t *points, int x0, int y0, int x1, int y1,
366
                         int pos, int npoints)
367
{
368
6600
    if (npoints) {
369
6504
        points[0] = (x0 * pos + x1 * (npoints - pos) + (npoints >> 1)) / npoints;
370
6504
        points[1] = (y0 * pos + y1 * (npoints - pos) + (npoints >> 1)) / npoints;
371
    } else {
372
96
        points[0] = x0;
373
96
        points[1] = y0;
374
    }
375
6600
}
376
377
/**
378
 * Construct glyphs by iterating through vector coordinates.
379
 *
380
 * @param pglyphs pointer to table where glyphs are stored
381
 * @param xvec pointer to x component of vector coordinates
382
 * @param yvec pointer to y component of vector coordinates
383
 * @param side_length glyph width/height.
384
 */
385
6
static void make_glyphs(int8_t *pglyphs, const int8_t *xvec, const int8_t *yvec,
386
                        const int side_length)
387
{
388
6
    const int glyph_size = side_length * side_length;
389
6
    int8_t *pglyph = pglyphs;
390
391
    int i, j;
392
102
    for (i = 0; i < GLYPH_COORD_VECT_SIZE; i++) {
393
96
        int x0 = xvec[i];
394
96
        int y0 = yvec[i];
395
96
        enum GlyphEdge edge0 = which_edge(x0, y0, side_length);
396
397
1632
        for (j = 0; j < GLYPH_COORD_VECT_SIZE; j++, pglyph += glyph_size) {
398
1536
            int x1 = xvec[j];
399
1536
            int y1 = yvec[j];
400
1536
            enum GlyphEdge edge1 = which_edge(x1, y1, side_length);
401
1536
            enum GlyphDir dir = which_direction(edge0, edge1);
402
1536
            int npoints = FFMAX(FFABS(x1 - x0), FFABS(y1 - y0));
403
            int ipoint;
404
405
8136
            for (ipoint = 0; ipoint <= npoints; ipoint++) {
406
                int8_t point[2];
407
                int irow, icol;
408
409
6600
                interp_point(point, x0, y0, x1, y1, ipoint, npoints);
410
411

6600
                switch (dir) {
412
2832
                case DIR_UP:
413
11064
                    for (irow = point[1]; irow >= 0; irow--)
414
8232
                        pglyph[point[0] + irow * side_length] = 1;
415
2832
                    break;
416
417
1968
                case DIR_DOWN:
418
6468
                    for (irow = point[1]; irow < side_length; irow++)
419
4500
                        pglyph[point[0] + irow * side_length] = 1;
420
1968
                    break;
421
422
282
                case DIR_LEFT:
423
660
                    for (icol = point[0]; icol >= 0; icol--)
424
378
                        pglyph[icol + point[1] * side_length] = 1;
425
282
                    break;
426
427
1434
                case DIR_RIGHT:
428
6228
                    for (icol = point[0]; icol < side_length; icol++)
429
4794
                        pglyph[icol + point[1] * side_length] = 1;
430
1434
                    break;
431
                }
432
6600
            }
433
        }
434
    }
435
6
}
436
437
6
static void init_sizes(SANMVideoContext *ctx, int width, int height)
438
{
439
6
    ctx->width   = width;
440
6
    ctx->height  = height;
441
6
    ctx->npixels = width * height;
442
443
6
    ctx->aligned_width  = FFALIGN(width, 8);
444
6
    ctx->aligned_height = FFALIGN(height, 8);
445
446
6
    ctx->buf_size = ctx->aligned_width * ctx->aligned_height * sizeof(ctx->frm0[0]);
447
6
    ctx->pitch    = width;
448
6
}
449
450
3
static void destroy_buffers(SANMVideoContext *ctx)
451
{
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->frm0, &ctx->frm0_size, ctx->buf_size);
466
3
    av_fast_padded_mallocz(&ctx->frm1, &ctx->frm1_size, ctx->buf_size);
467
3
    av_fast_padded_mallocz(&ctx->frm2, &ctx->frm2_size, ctx->buf_size);
468
3
    if (!ctx->version)
469
        av_fast_padded_mallocz(&ctx->stored_frame,
470
                              &ctx->stored_frame_size, ctx->buf_size);
471
472

3
    if (!ctx->frm0 || !ctx->frm1 || !ctx->frm2 ||
473

3
        (!ctx->stored_frame && !ctx->version)) {
474
        destroy_buffers(ctx);
475
        return AVERROR(ENOMEM);
476
    }
477
478
3
    return 0;
479
}
480
481
9
static void rotate_bufs(SANMVideoContext *ctx, int rotate_code)
482
{
483
9
    if (rotate_code == 2)
484
1
        FFSWAP(uint16_t*, ctx->frm1, ctx->frm2);
485
9
    FFSWAP(uint16_t*, ctx->frm2, ctx->frm0);
486
9
}
487
488
3
static av_cold int decode_init(AVCodecContext *avctx)
489
{
490
3
    SANMVideoContext *ctx = avctx->priv_data;
491
492
3
    ctx->avctx   = avctx;
493
3
    ctx->version = !avctx->extradata_size;
494
    // early sanity check before allocations to avoid need for deallocation code.
495

3
    if (!ctx->version && avctx->extradata_size < 1026) {
496
        av_log(avctx, AV_LOG_ERROR, "Not enough extradata.\n");
497
        return AVERROR_INVALIDDATA;
498
    }
499
500
3
    avctx->pix_fmt = ctx->version ? AV_PIX_FMT_RGB565 : AV_PIX_FMT_PAL8;
501
502
3
    init_sizes(ctx, avctx->width, avctx->height);
503
3
    if (init_buffers(ctx)) {
504
        av_log(avctx, AV_LOG_ERROR, "Error allocating buffers.\n");
505
        return AVERROR(ENOMEM);
506
    }
507
508
3
    make_glyphs(ctx->p4x4glyphs[0], glyph4_x, glyph4_y, 4);
509
3
    make_glyphs(ctx->p8x8glyphs[0], glyph8_x, glyph8_y, 8);
510
511
3
    if (!ctx->version) {
512
        int i;
513
514
        ctx->subversion = AV_RL16(avctx->extradata);
515
        for (i = 0; i < PALETTE_SIZE; i++)
516
            ctx->pal[i] = 0xFFU << 24 | AV_RL32(avctx->extradata + 2 + i * 4);
517
    }
518
519
3
    return 0;
520
}
521
522
3
static av_cold int decode_end(AVCodecContext *avctx)
523
{
524
3
    SANMVideoContext *ctx = avctx->priv_data;
525
526
3
    destroy_buffers(ctx);
527
528
3
    return 0;
529
}
530
531
1
static int rle_decode(SANMVideoContext *ctx, uint8_t *dst, const int out_size)
532
{
533
1
    int opcode, color, run_len, left = out_size;
534
535
4801
    while (left > 0) {
536
4800
        opcode = bytestream2_get_byte(&ctx->gb);
537
4800
        run_len = (opcode >> 1) + 1;
538

4800
        if (run_len > left || bytestream2_get_bytes_left(&ctx->gb) <= 0)
539
            return AVERROR_INVALIDDATA;
540
541
4800
        if (opcode & 1) {
542
4800
            color = bytestream2_get_byte(&ctx->gb);
543
4800
            memset(dst, color, run_len);
544
        } else {
545
            if (bytestream2_get_bytes_left(&ctx->gb) < run_len)
546
                return AVERROR_INVALIDDATA;
547
            bytestream2_get_bufferu(&ctx->gb, dst, run_len);
548
        }
549
550
4800
        dst  += run_len;
551
4800
        left -= run_len;
552
    }
553
554
1
    return 0;
555
}
556
557
static int old_codec1(SANMVideoContext *ctx, int top,
558
                      int left, int width, int height)
559
{
560
    uint8_t *dst = ((uint8_t *)ctx->frm0) + left + top * ctx->pitch;
561
    int i, j, len, flag, code, val, pos, end;
562
563
    for (i = 0; i < height; i++) {
564
        pos = 0;
565
566
        if (bytestream2_get_bytes_left(&ctx->gb) < 2)
567
            return AVERROR_INVALIDDATA;
568
569
        len = bytestream2_get_le16u(&ctx->gb);
570
        end = bytestream2_tell(&ctx->gb) + len;
571
572
        while (bytestream2_tell(&ctx->gb) < end) {
573
            if (bytestream2_get_bytes_left(&ctx->gb) < 2)
574
                return AVERROR_INVALIDDATA;
575
576
            code = bytestream2_get_byteu(&ctx->gb);
577
            flag = code & 1;
578
            code = (code >> 1) + 1;
579
            if (pos + code > width)
580
                return AVERROR_INVALIDDATA;
581
            if (flag) {
582
                val = bytestream2_get_byteu(&ctx->gb);
583
                if (val)
584
                    memset(dst + pos, val, code);
585
                pos += code;
586
            } else {
587
                if (bytestream2_get_bytes_left(&ctx->gb) < code)
588
                    return AVERROR_INVALIDDATA;
589
                for (j = 0; j < code; j++) {
590
                    val = bytestream2_get_byteu(&ctx->gb);
591
                    if (val)
592
                        dst[pos] = val;
593
                    pos++;
594
                }
595
            }
596
        }
597
        dst += ctx->pitch;
598
    }
599
    ctx->rotate_code = 0;
600
601
    return 0;
602
}
603
604
static inline void codec37_mv(uint8_t *dst, const uint8_t *src,
605
                              int height, int stride, int x, int y)
606
{
607
    int pos, i, j;
608
609
    pos = x + y * stride;
610
    for (j = 0; j < 4; j++) {
611
        for (i = 0; i < 4; i++) {
612
            if ((pos + i) < 0 || (pos + i) >= height * stride)
613
                dst[i] = 0;
614
            else
615
                dst[i] = src[i];
616
        }
617
        dst += stride;
618
        src += stride;
619
        pos += stride;
620
    }
621
}
622
623
static int old_codec37(SANMVideoContext *ctx, int top,
624
                       int left, int width, int height)
625
{
626
    ptrdiff_t stride = ctx->pitch;
627
    int i, j, k, t;
628
    uint8_t *dst, *prev;
629
    int skip_run = 0;
630
    int compr = bytestream2_get_byte(&ctx->gb);
631
    int mvoff = bytestream2_get_byte(&ctx->gb);
632
    int seq   = bytestream2_get_le16(&ctx->gb);
633
    uint32_t decoded_size = bytestream2_get_le32(&ctx->gb);
634
    int flags;
635
636
    bytestream2_skip(&ctx->gb, 4);
637
    flags = bytestream2_get_byte(&ctx->gb);
638
    bytestream2_skip(&ctx->gb, 3);
639
640
    if (decoded_size > ctx->height * stride - left - top * stride) {
641
        decoded_size = ctx->height * stride - left - top * stride;
642
        av_log(ctx->avctx, AV_LOG_WARNING, "Decoded size is too large.\n");
643
    }
644
645
    ctx->rotate_code = 0;
646
647
    if (((seq & 1) || !(flags & 1)) && (compr && compr != 2))
648
        rotate_bufs(ctx, 1);
649
650
    dst  = ((uint8_t*)ctx->frm0) + left + top * stride;
651
    prev = ((uint8_t*)ctx->frm2) + left + top * stride;
652
653
    if (mvoff > 2) {
654
        av_log(ctx->avctx, AV_LOG_ERROR, "Invalid motion base value %d.\n", mvoff);
655
        return AVERROR_INVALIDDATA;
656
    }
657
658
    switch (compr) {
659
    case 0:
660
        for (i = 0; i < height; i++) {
661
            bytestream2_get_buffer(&ctx->gb, dst, width);
662
            dst += stride;
663
        }
664
        memset(ctx->frm1, 0, ctx->height * stride);
665
        memset(ctx->frm2, 0, ctx->height * stride);
666
        break;
667
    case 2:
668
        if (rle_decode(ctx, dst, decoded_size))
669
            return AVERROR_INVALIDDATA;
670
        memset(ctx->frm1, 0, ctx->frm1_size);
671
        memset(ctx->frm2, 0, ctx->frm2_size);
672
        break;
673
    case 3:
674
    case 4:
675
        if (flags & 4) {
676
            for (j = 0; j < height; j += 4) {
677
                for (i = 0; i < width; i += 4) {
678
                    int code;
679
                    if (skip_run) {
680
                        skip_run--;
681
                        copy_block4(dst + i, prev + i, stride, stride, 4);
682
                        continue;
683
                    }
684
                    if (bytestream2_get_bytes_left(&ctx->gb) < 1)
685
                        return AVERROR_INVALIDDATA;
686
                    code = bytestream2_get_byteu(&ctx->gb);
687
                    switch (code) {
688
                    case 0xFF:
689
                        if (bytestream2_get_bytes_left(&ctx->gb) < 16)
690
                            return AVERROR_INVALIDDATA;
691
                        for (k = 0; k < 4; k++)
692
                            bytestream2_get_bufferu(&ctx->gb, dst + i + k * stride, 4);
693
                        break;
694
                    case 0xFE:
695
                        if (bytestream2_get_bytes_left(&ctx->gb) < 4)
696
                            return AVERROR_INVALIDDATA;
697
                        for (k = 0; k < 4; k++)
698
                            memset(dst + i + k * stride, bytestream2_get_byteu(&ctx->gb), 4);
699
                        break;
700
                    case 0xFD:
701
                        if (bytestream2_get_bytes_left(&ctx->gb) < 1)
702
                            return AVERROR_INVALIDDATA;
703
                        t = bytestream2_get_byteu(&ctx->gb);
704
                        for (k = 0; k < 4; k++)
705
                            memset(dst + i + k * stride, t, 4);
706
                        break;
707
                    default:
708
                        if (compr == 4 && !code) {
709
                            if (bytestream2_get_bytes_left(&ctx->gb) < 1)
710
                                return AVERROR_INVALIDDATA;
711
                            skip_run = bytestream2_get_byteu(&ctx->gb) + 1;
712
                            i -= 4;
713
                        } else {
714
                            int mx, my;
715
716
                            mx = c37_mv[(mvoff * 255 + code) * 2];
717
                            my = c37_mv[(mvoff * 255 + code) * 2 + 1];
718
                            codec37_mv(dst + i, prev + i + mx + my * stride,
719
                                       ctx->height, stride, i + mx, j + my);
720
                        }
721
                    }
722
                }
723
                dst  += stride * 4;
724
                prev += stride * 4;
725
            }
726
        } else {
727
            for (j = 0; j < height; j += 4) {
728
                for (i = 0; i < width; i += 4) {
729
                    int code;
730
                    if (skip_run) {
731
                        skip_run--;
732
                        copy_block4(dst + i, prev + i, stride, stride, 4);
733
                        continue;
734
                    }
735
                    code = bytestream2_get_byte(&ctx->gb);
736
                    if (code == 0xFF) {
737
                        if (bytestream2_get_bytes_left(&ctx->gb) < 16)
738
                            return AVERROR_INVALIDDATA;
739
                        for (k = 0; k < 4; k++)
740
                            bytestream2_get_bufferu(&ctx->gb, dst + i + k * stride, 4);
741
                    } else if (compr == 4 && !code) {
742
                        if (bytestream2_get_bytes_left(&ctx->gb) < 1)
743
                            return AVERROR_INVALIDDATA;
744
                        skip_run = bytestream2_get_byteu(&ctx->gb) + 1;
745
                        i -= 4;
746
                    } else {
747
                        int mx, my;
748
749
                        mx = c37_mv[(mvoff * 255 + code) * 2];
750
                        my = c37_mv[(mvoff * 255 + code) * 2 + 1];
751
                        codec37_mv(dst + i, prev + i + mx + my * stride,
752
                                   ctx->height, stride, i + mx, j + my);
753
                    }
754
                }
755
                dst  += stride * 4;
756
                prev += stride * 4;
757
            }
758
        }
759
        break;
760
    default:
761
        avpriv_report_missing_feature(ctx->avctx,
762
                                      "Subcodec 37 compression %d", compr);
763
        return AVERROR_PATCHWELCOME;
764
    }
765
766
    return 0;
767
}
768
769
static int process_block(SANMVideoContext *ctx, uint8_t *dst, uint8_t *prev1,
770
                         uint8_t *prev2, int stride, int tbl, int size)
771
{
772
    int code, k, t;
773
    uint8_t colors[2];
774
    int8_t *pglyph;
775
776
    if (bytestream2_get_bytes_left(&ctx->gb) < 1)
777
        return AVERROR_INVALIDDATA;
778
779
    code = bytestream2_get_byteu(&ctx->gb);
780
    if (code >= 0xF8) {
781
        switch (code) {
782
        case 0xFF:
783
            if (size == 2) {
784
                if (bytestream2_get_bytes_left(&ctx->gb) < 4)
785
                    return AVERROR_INVALIDDATA;
786
                dst[0]          = bytestream2_get_byteu(&ctx->gb);
787
                dst[1]          = bytestream2_get_byteu(&ctx->gb);
788
                dst[0 + stride] = bytestream2_get_byteu(&ctx->gb);
789
                dst[1 + stride] = bytestream2_get_byteu(&ctx->gb);
790
            } else {
791
                size >>= 1;
792
                if (process_block(ctx, dst, prev1, prev2, stride, tbl, size))
793
                    return AVERROR_INVALIDDATA;
794
                if (process_block(ctx, dst + size, prev1 + size, prev2 + size,
795
                                  stride, tbl, size))
796
                    return AVERROR_INVALIDDATA;
797
                dst   += size * stride;
798
                prev1 += size * stride;
799
                prev2 += size * stride;
800
                if (process_block(ctx, dst, prev1, prev2, stride, tbl, size))
801
                    return AVERROR_INVALIDDATA;
802
                if (process_block(ctx, dst + size, prev1 + size, prev2 + size,
803
                                  stride, tbl, size))
804
                    return AVERROR_INVALIDDATA;
805
            }
806
            break;
807
        case 0xFE:
808
            if (bytestream2_get_bytes_left(&ctx->gb) < 1)
809
                return AVERROR_INVALIDDATA;
810
811
            t = bytestream2_get_byteu(&ctx->gb);
812
            for (k = 0; k < size; k++)
813
                memset(dst + k * stride, t, size);
814
            break;
815
        case 0xFD:
816
            if (bytestream2_get_bytes_left(&ctx->gb) < 3)
817
                return AVERROR_INVALIDDATA;
818
819
            code = bytestream2_get_byteu(&ctx->gb);
820
            pglyph = (size == 8) ? ctx->p8x8glyphs[code] : ctx->p4x4glyphs[code];
821
            bytestream2_get_bufferu(&ctx->gb, colors, 2);
822
823
            for (k = 0; k < size; k++)
824
                for (t = 0; t < size; t++)
825
                    dst[t + k * stride] = colors[!*pglyph++];
826
            break;
827
        case 0xFC:
828
            for (k = 0; k < size; k++)
829
                memcpy(dst + k * stride, prev1 + k * stride, size);
830
            break;
831
        default:
832
            k = bytestream2_tell(&ctx->gb);
833
            bytestream2_seek(&ctx->gb, tbl + (code & 7), SEEK_SET);
834
            t = bytestream2_get_byte(&ctx->gb);
835
            bytestream2_seek(&ctx->gb, k, SEEK_SET);
836
            for (k = 0; k < size; k++)
837
                memset(dst + k * stride, t, size);
838
        }
839
    } else {
840
        int mx = motion_vectors[code][0];
841
        int my = motion_vectors[code][1];
842
        int index = prev2 - (const uint8_t *)ctx->frm2;
843
844
        av_assert2(index >= 0 && index < (ctx->buf_size >> 1));
845
846
        if (index < -mx - my * stride ||
847
            (ctx->buf_size >> 1) - index < mx + size + (my + size - 1) * stride) {
848
            av_log(ctx->avctx, AV_LOG_ERROR, "MV is invalid.\n");
849
            return AVERROR_INVALIDDATA;
850
        }
851
852
        for (k = 0; k < size; k++)
853
            memcpy(dst + k * stride, prev2 + mx + (my + k) * stride, size);
854
    }
855
856
    return 0;
857
}
858
859
static int old_codec47(SANMVideoContext *ctx, int top,
860
                       int left, int width, int height)
861
{
862
    uint32_t decoded_size;
863
    int i, j;
864
    ptrdiff_t stride = ctx->pitch;
865
    uint8_t *dst   = (uint8_t *)ctx->frm0 + left + top * stride;
866
    uint8_t *prev1 = (uint8_t *)ctx->frm1;
867
    uint8_t *prev2 = (uint8_t *)ctx->frm2;
868
    int tbl_pos = bytestream2_tell(&ctx->gb);
869
    int seq     = bytestream2_get_le16(&ctx->gb);
870
    int compr   = bytestream2_get_byte(&ctx->gb);
871
    int new_rot = bytestream2_get_byte(&ctx->gb);
872
    int skip    = bytestream2_get_byte(&ctx->gb);
873
874
    bytestream2_skip(&ctx->gb, 9);
875
    decoded_size = bytestream2_get_le32(&ctx->gb);
876
    bytestream2_skip(&ctx->gb, 8);
877
878
    if (decoded_size > ctx->height * stride - left - top * stride) {
879
        decoded_size = ctx->height * stride - left - top * stride;
880
        av_log(ctx->avctx, AV_LOG_WARNING, "Decoded size is too large.\n");
881
    }
882
883
    if (skip & 1)
884
        bytestream2_skip(&ctx->gb, 0x8080);
885
    if (!seq) {
886
        ctx->prev_seq = -1;
887
        memset(prev1, 0, ctx->height * stride);
888
        memset(prev2, 0, ctx->height * stride);
889
    }
890
891
    switch (compr) {
892
    case 0:
893
        if (bytestream2_get_bytes_left(&ctx->gb) < width * height)
894
            return AVERROR_INVALIDDATA;
895
        for (j = 0; j < height; j++) {
896
            bytestream2_get_bufferu(&ctx->gb, dst, width);
897
            dst += stride;
898
        }
899
        break;
900
    case 1:
901
        if (bytestream2_get_bytes_left(&ctx->gb) < ((width + 1) >> 1) * ((height + 1) >> 1))
902
            return AVERROR_INVALIDDATA;
903
        for (j = 0; j < height; j += 2) {
904
            for (i = 0; i < width; i += 2) {
905
                dst[i] =
906
                dst[i + 1] =
907
                dst[stride + i] =
908
                dst[stride + i + 1] = bytestream2_get_byteu(&ctx->gb);
909
            }
910
            dst += stride * 2;
911
        }
912
        break;
913
    case 2:
914
        if (seq == ctx->prev_seq + 1) {
915
            for (j = 0; j < height; j += 8) {
916
                for (i = 0; i < width; i += 8)
917
                    if (process_block(ctx, dst + i, prev1 + i, prev2 + i, stride,
918
                                      tbl_pos + 8, 8))
919
                        return AVERROR_INVALIDDATA;
920
                dst   += stride * 8;
921
                prev1 += stride * 8;
922
                prev2 += stride * 8;
923
            }
924
        }
925
        break;
926
    case 3:
927
        memcpy(ctx->frm0, ctx->frm2, ctx->pitch * ctx->height);
928
        break;
929
    case 4:
930
        memcpy(ctx->frm0, ctx->frm1, ctx->pitch * ctx->height);
931
        break;
932
    case 5:
933
        if (rle_decode(ctx, dst, decoded_size))
934
            return AVERROR_INVALIDDATA;
935
        break;
936
    default:
937
        avpriv_report_missing_feature(ctx->avctx,
938
                                      "Subcodec 47 compression %d", compr);
939
        return AVERROR_PATCHWELCOME;
940
    }
941
    if (seq == ctx->prev_seq + 1)
942
        ctx->rotate_code = new_rot;
943
    else
944
        ctx->rotate_code = 0;
945
    ctx->prev_seq = seq;
946
947
    return 0;
948
}
949
950
static int process_frame_obj(SANMVideoContext *ctx)
951
{
952
    uint16_t codec = bytestream2_get_le16u(&ctx->gb);
953
    uint16_t left  = bytestream2_get_le16u(&ctx->gb);
954
    uint16_t top   = bytestream2_get_le16u(&ctx->gb);
955
    uint16_t w     = bytestream2_get_le16u(&ctx->gb);
956
    uint16_t h     = bytestream2_get_le16u(&ctx->gb);
957
958
    if (!w || !h) {
959
        av_log(ctx->avctx, AV_LOG_ERROR, "Dimensions are invalid.\n");
960
        return AVERROR_INVALIDDATA;
961
    }
962
963
    if (ctx->width < left + w || ctx->height < top + h) {
964
        int ret = ff_set_dimensions(ctx->avctx, FFMAX(left + w, ctx->width),
965
                                    FFMAX(top + h, ctx->height));
966
        if (ret < 0)
967
            return ret;
968
        init_sizes(ctx, FFMAX(left + w, ctx->width),
969
                   FFMAX(top + h, ctx->height));
970
        if (init_buffers(ctx)) {
971
            av_log(ctx->avctx, AV_LOG_ERROR, "Error resizing buffers.\n");
972
            return AVERROR(ENOMEM);
973
        }
974
    }
975
    bytestream2_skip(&ctx->gb, 4);
976
977
    switch (codec) {
978
    case 1:
979
    case 3:
980
        return old_codec1(ctx, top, left, w, h);
981
    case 37:
982
        return old_codec37(ctx, top, left, w, h);
983
    case 47:
984
        return old_codec47(ctx, top, left, w, h);
985
    default:
986
        avpriv_request_sample(ctx->avctx, "Subcodec %d", codec);
987
        return AVERROR_PATCHWELCOME;
988
    }
989
}
990
991
static int decode_0(SANMVideoContext *ctx)
992
{
993
    uint16_t *frm = ctx->frm0;
994
    int x, y;
995
996
    if (bytestream2_get_bytes_left(&ctx->gb) < ctx->width * ctx->height * 2) {
997
        av_log(ctx->avctx, AV_LOG_ERROR, "Insufficient data for raw frame.\n");
998
        return AVERROR_INVALIDDATA;
999
    }
1000
    for (y = 0; y < ctx->height; y++) {
1001
        for (x = 0; x < ctx->width; x++)
1002
            frm[x] = bytestream2_get_le16u(&ctx->gb);
1003
        frm += ctx->pitch;
1004
    }
1005
    return 0;
1006
}
1007
1008
static int decode_nop(SANMVideoContext *ctx)
1009
{
1010
    avpriv_request_sample(ctx->avctx, "Unknown/unsupported compression type");
1011
    return AVERROR_PATCHWELCOME;
1012
}
1013
1014
42964
static void copy_block(uint16_t *pdest, uint16_t *psrc, int block_size, ptrdiff_t pitch)
1015
{
1016
42964
    uint8_t *dst = (uint8_t *)pdest;
1017
42964
    uint8_t *src = (uint8_t *)psrc;
1018
42964
    ptrdiff_t stride = pitch * 2;
1019
1020

42964
    switch (block_size) {
1021
14526
    case 2:
1022
14526
        copy_block4(dst, src, stride, stride, 2);
1023
14526
        break;
1024
12400
    case 4:
1025
12400
        copy_block8(dst, src, stride, stride, 4);
1026
12400
        break;
1027
16038
    case 8:
1028
16038
        copy_block16(dst, src, stride, stride, 8);
1029
16038
        break;
1030
    }
1031
42964
}
1032
1033
7913
static void fill_block(uint16_t *pdest, uint16_t color, int block_size, ptrdiff_t pitch)
1034
{
1035
    int x, y;
1036
1037
7913
    pitch -= block_size;
1038
38351
    for (y = 0; y < block_size; y++, pdest += pitch)
1039
179978
        for (x = 0; x < block_size; x++)
1040
149540
            *pdest++ = color;
1041
7913
}
1042
1043
8368
static int draw_glyph(SANMVideoContext *ctx, uint16_t *dst, int index,
1044
                      uint16_t fg_color, uint16_t bg_color, int block_size,
1045
                      ptrdiff_t pitch)
1046
{
1047
    int8_t *pglyph;
1048
8368
    uint16_t colors[2] = { fg_color, bg_color };
1049
    int x, y;
1050
1051
8368
    if (index >= NGLYPHS) {
1052
        av_log(ctx->avctx, AV_LOG_ERROR, "Ignoring nonexistent glyph #%u.\n", index);
1053
        return AVERROR_INVALIDDATA;
1054
    }
1055
1056
8368
    pglyph = block_size == 8 ? ctx->p8x8glyphs[index] : ctx->p4x4glyphs[index];
1057
8368
    pitch -= block_size;
1058
1059
46472
    for (y = 0; y < block_size; y++, dst += pitch)
1060
227576
        for (x = 0; x < block_size; x++)
1061
189472
            *dst++ = colors[*pglyph++];
1062
8368
    return 0;
1063
}
1064
1065
8029
static int opcode_0xf7(SANMVideoContext *ctx, int cx, int cy, int block_size, ptrdiff_t pitch)
1066
{
1067
8029
    uint16_t *dst = ctx->frm0 + cx + cy * ctx->pitch;
1068
1069
8029
    if (block_size == 2) {
1070
        uint32_t indices;
1071
1072
825
        if (bytestream2_get_bytes_left(&ctx->gb) < 4)
1073
            return AVERROR_INVALIDDATA;
1074
1075
825
        indices        = bytestream2_get_le32u(&ctx->gb);
1076
825
        dst[0]         = ctx->codebook[indices & 0xFF];
1077
825
        indices      >>= 8;
1078
825
        dst[1]         = ctx->codebook[indices & 0xFF];
1079
825
        indices      >>= 8;
1080
825
        dst[pitch]     = ctx->codebook[indices & 0xFF];
1081
825
        indices      >>= 8;
1082
825
        dst[pitch + 1] = ctx->codebook[indices & 0xFF];
1083
    } else {
1084
        uint16_t fgcolor, bgcolor;
1085
        int glyph;
1086
1087
7204
        if (bytestream2_get_bytes_left(&ctx->gb) < 3)
1088
1
            return AVERROR_INVALIDDATA;
1089
1090
7203
        glyph   = bytestream2_get_byteu(&ctx->gb);
1091
7203
        bgcolor = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
1092
7203
        fgcolor = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
1093
1094
7203
        draw_glyph(ctx, dst, glyph, fgcolor, bgcolor, block_size, pitch);
1095
    }
1096
8028
    return 0;
1097
}
1098
1099
1169
static int opcode_0xf8(SANMVideoContext *ctx, int cx, int cy, int block_size, ptrdiff_t pitch)
1100
{
1101
1169
    uint16_t *dst = ctx->frm0 + cx + cy * ctx->pitch;
1102
1103
1169
    if (block_size == 2) {
1104
4
        if (bytestream2_get_bytes_left(&ctx->gb) < 8)
1105
            return AVERROR_INVALIDDATA;
1106
1107
4
        dst[0]         = bytestream2_get_le16u(&ctx->gb);
1108
4
        dst[1]         = bytestream2_get_le16u(&ctx->gb);
1109
4
        dst[pitch]     = bytestream2_get_le16u(&ctx->gb);
1110
4
        dst[pitch + 1] = bytestream2_get_le16u(&ctx->gb);
1111
    } else {
1112
        uint16_t fgcolor, bgcolor;
1113
        int glyph;
1114
1115
1165
        if (bytestream2_get_bytes_left(&ctx->gb) < 5)
1116
            return AVERROR_INVALIDDATA;
1117
1118
1165
        glyph   = bytestream2_get_byteu(&ctx->gb);
1119
1165
        bgcolor = bytestream2_get_le16u(&ctx->gb);
1120
1165
        fgcolor = bytestream2_get_le16u(&ctx->gb);
1121
1122
1165
        draw_glyph(ctx, dst, glyph, fgcolor, bgcolor, block_size, pitch);
1123
    }
1124
1169
    return 0;
1125
}
1126
1127
30376
static int good_mvec(SANMVideoContext *ctx, int cx, int cy, int mx, int my,
1128
                     int block_size)
1129
{
1130
30376
    int start_pos = cx + mx + (cy + my) * ctx->pitch;
1131
30376
    int end_pos = start_pos + (block_size - 1) * (ctx->pitch + 1);
1132
1133

30376
    int good = start_pos >= 0 && end_pos < (ctx->buf_size >> 1);
1134
1135
30376
    if (!good)
1136
        av_log(ctx->avctx, AV_LOG_ERROR,
1137
               "Ignoring invalid motion vector (%i, %i)->(%u, %u), block size = %u\n",
1138
               cx + mx, cy + my, cx, cy, block_size);
1139
1140
30376
    return good;
1141
}
1142
1143
71636
static int codec2subblock(SANMVideoContext *ctx, int cx, int cy, int blk_size)
1144
{
1145
    int16_t mx, my, index;
1146
    int opcode;
1147
1148
71636
    if (bytestream2_get_bytes_left(&ctx->gb) < 1)
1149
1
        return AVERROR_INVALIDDATA;
1150
1151
71635
    opcode = bytestream2_get_byteu(&ctx->gb);
1152
1153


71635
    switch (opcode) {
1154
28212
    default:
1155
28212
        mx = motion_vectors[opcode][0];
1156
28212
        my = motion_vectors[opcode][1];
1157
1158
28212
        if (good_mvec(ctx, cx, cy, mx, my, blk_size)) {
1159
28212
            copy_block(ctx->frm0 + cx      + ctx->pitch *  cy,
1160
28212
                       ctx->frm2 + cx + mx + ctx->pitch * (cy + my),
1161
                       blk_size, ctx->pitch);
1162
        }
1163
28212
        break;
1164
2164
    case 0xF5:
1165
2164
        if (bytestream2_get_bytes_left(&ctx->gb) < 2)
1166
            return AVERROR_INVALIDDATA;
1167
2164
        index = bytestream2_get_le16u(&ctx->gb);
1168
1169
2164
        mx = index % ctx->width;
1170
2164
        my = index / ctx->width;
1171
1172
2164
        if (good_mvec(ctx, cx, cy, mx, my, blk_size)) {
1173
2164
            copy_block(ctx->frm0 + cx      + ctx->pitch *  cy,
1174
2164
                       ctx->frm2 + cx + mx + ctx->pitch * (cy + my),
1175
                       blk_size, ctx->pitch);
1176
        }
1177
2164
        break;
1178
12588
    case 0xF6:
1179
12588
        copy_block(ctx->frm0 + cx + ctx->pitch * cy,
1180
12588
                   ctx->frm1 + cx + ctx->pitch * cy,
1181
                   blk_size, ctx->pitch);
1182
12588
        break;
1183
8029
    case 0xF7:
1184
8029
        opcode_0xf7(ctx, cx, cy, blk_size, ctx->pitch);
1185
8029
        break;
1186
1187
1169
    case 0xF8:
1188
1169
        opcode_0xf8(ctx, cx, cy, blk_size, ctx->pitch);
1189
1169
        break;
1190
315
    case 0xF9:
1191
    case 0xFA:
1192
    case 0xFB:
1193
    case 0xFC:
1194
315
        fill_block(ctx->frm0 + cx + cy * ctx->pitch,
1195
315
                   ctx->small_codebook[opcode - 0xf9], blk_size, ctx->pitch);
1196
315
        break;
1197
5496
    case 0xFD:
1198
5496
        if (bytestream2_get_bytes_left(&ctx->gb) < 1)
1199
            return AVERROR_INVALIDDATA;
1200
10992
        fill_block(ctx->frm0 + cx + cy * ctx->pitch,
1201
5496
                   ctx->codebook[bytestream2_get_byteu(&ctx->gb)], blk_size, ctx->pitch);
1202
5496
        break;
1203
2102
    case 0xFE:
1204
2102
        if (bytestream2_get_bytes_left(&ctx->gb) < 2)
1205
            return AVERROR_INVALIDDATA;
1206
2102
        fill_block(ctx->frm0 + cx + cy * ctx->pitch,
1207
2102
                   bytestream2_get_le16u(&ctx->gb), blk_size, ctx->pitch);
1208
2102
        break;
1209
11560
    case 0xFF:
1210
11560
        if (blk_size == 2) {
1211
            opcode_0xf8(ctx, cx, cy, blk_size, ctx->pitch);
1212
        } else {
1213
11560
            blk_size >>= 1;
1214
11560
            if (codec2subblock(ctx, cx, cy, blk_size))
1215
                return AVERROR_INVALIDDATA;
1216
11560
            if (codec2subblock(ctx, cx + blk_size, cy, blk_size))
1217
                return AVERROR_INVALIDDATA;
1218
11560
            if (codec2subblock(ctx, cx, cy + blk_size, blk_size))
1219
                return AVERROR_INVALIDDATA;
1220
11560
            if (codec2subblock(ctx, cx + blk_size, cy + blk_size, blk_size))
1221
                return AVERROR_INVALIDDATA;
1222
        }
1223
11560
        break;
1224
    }
1225
71635
    return 0;
1226
}
1227
1228
6
static int decode_2(SANMVideoContext *ctx)
1229
{
1230
    int cx, cy, ret;
1231
1232
323
    for (cy = 0; cy < ctx->aligned_height; cy += 8)
1233
25713
        for (cx = 0; cx < ctx->aligned_width; cx += 8)
1234
25396
            if (ret = codec2subblock(ctx, cx, cy, 8))
1235
1
                return ret;
1236
1237
5
    return 0;
1238
}
1239
1240
static int decode_3(SANMVideoContext *ctx)
1241
{
1242
    memcpy(ctx->frm0, ctx->frm2, ctx->frm2_size);
1243
    return 0;
1244
}
1245
1246
9
static int decode_4(SANMVideoContext *ctx)
1247
{
1248
9
    memcpy(ctx->frm0, ctx->frm1, ctx->frm1_size);
1249
9
    return 0;
1250
}
1251
1252
1
static int decode_5(SANMVideoContext *ctx)
1253
{
1254
#if HAVE_BIGENDIAN
1255
    uint16_t *frm;
1256
    int npixels;
1257
#endif
1258
1
    uint8_t *dst = (uint8_t*)ctx->frm0;
1259
1260
1
    if (rle_decode(ctx, dst, ctx->buf_size))
1261
        return AVERROR_INVALIDDATA;
1262
1263
#if HAVE_BIGENDIAN
1264
    npixels = ctx->npixels;
1265
    frm = ctx->frm0;
1266
    while (npixels--) {
1267
        *frm = av_bswap16(*frm);
1268
        frm++;
1269
    }
1270
#endif
1271
1272
1
    return 0;
1273
}
1274
1275
static int decode_6(SANMVideoContext *ctx)
1276
{
1277
    int npixels = ctx->npixels;
1278
    uint16_t *frm = ctx->frm0;
1279
1280
    if (bytestream2_get_bytes_left(&ctx->gb) < npixels) {
1281
        av_log(ctx->avctx, AV_LOG_ERROR, "Insufficient data for frame.\n");
1282
        return AVERROR_INVALIDDATA;
1283
    }
1284
    while (npixels--)
1285
        *frm++ = ctx->codebook[bytestream2_get_byteu(&ctx->gb)];
1286
1287
    return 0;
1288
}
1289
1290
static int decode_8(SANMVideoContext *ctx)
1291
{
1292
    uint16_t *pdest = ctx->frm0;
1293
    uint8_t *rsrc;
1294
    long npixels = ctx->npixels;
1295
1296
    av_fast_malloc(&ctx->rle_buf, &ctx->rle_buf_size, npixels);
1297
    if (!ctx->rle_buf) {
1298
        av_log(ctx->avctx, AV_LOG_ERROR, "RLE buffer allocation failed.\n");
1299
        return AVERROR(ENOMEM);
1300
    }
1301
    rsrc = ctx->rle_buf;
1302
1303
    if (rle_decode(ctx, rsrc, npixels))
1304
        return AVERROR_INVALIDDATA;
1305
1306
    while (npixels--)
1307
        *pdest++ = ctx->codebook[*rsrc++];
1308
1309
    return 0;
1310
}
1311
1312
typedef int (*frm_decoder)(SANMVideoContext *ctx);
1313
1314
static const frm_decoder v1_decoders[] = {
1315
    decode_0, decode_nop, decode_2, decode_3, decode_4, decode_5,
1316
    decode_6, decode_nop, decode_8
1317
};
1318
1319
16
static int read_frame_header(SANMVideoContext *ctx, SANMFrameHeader *hdr)
1320
{
1321
    int i, ret;
1322
1323
16
    if ((ret = bytestream2_get_bytes_left(&ctx->gb)) < 560) {
1324
        av_log(ctx->avctx, AV_LOG_ERROR, "Input frame too short (%d bytes).\n",
1325
               ret);
1326
        return AVERROR_INVALIDDATA;
1327
    }
1328
16
    bytestream2_skip(&ctx->gb, 8); // skip pad
1329
1330
16
    hdr->width  = bytestream2_get_le32u(&ctx->gb);
1331
16
    hdr->height = bytestream2_get_le32u(&ctx->gb);
1332
1333

16
    if (hdr->width != ctx->width || hdr->height != ctx->height) {
1334
        avpriv_report_missing_feature(ctx->avctx, "Variable size frames");
1335
        return AVERROR_PATCHWELCOME;
1336
    }
1337
1338
16
    hdr->seq_num     = bytestream2_get_le16u(&ctx->gb);
1339
16
    hdr->codec       = bytestream2_get_byteu(&ctx->gb);
1340
16
    hdr->rotate_code = bytestream2_get_byteu(&ctx->gb);
1341
1342
16
    bytestream2_skip(&ctx->gb, 4); // skip pad
1343
1344
80
    for (i = 0; i < 4; i++)
1345
64
        ctx->small_codebook[i] = bytestream2_get_le16u(&ctx->gb);
1346
16
    hdr->bg_color = bytestream2_get_le16u(&ctx->gb);
1347
1348
16
    bytestream2_skip(&ctx->gb, 2); // skip pad
1349
1350
16
    hdr->rle_output_size = bytestream2_get_le32u(&ctx->gb);
1351
4112
    for (i = 0; i < 256; i++)
1352
4096
        ctx->codebook[i] = bytestream2_get_le16u(&ctx->gb);
1353
1354
16
    bytestream2_skip(&ctx->gb, 8); // skip pad
1355
1356
16
    return 0;
1357
}
1358
1359
2
static void fill_frame(uint16_t *pbuf, int buf_size, uint16_t color)
1360
{
1361
2
    if (buf_size--) {
1362
2
        *pbuf++ = color;
1363
2
        av_memcpy_backptr((uint8_t*)pbuf, 2, 2*buf_size);
1364
    }
1365
2
}
1366
1367
15
static int copy_output(SANMVideoContext *ctx, SANMFrameHeader *hdr)
1368
{
1369
    uint8_t *dst;
1370
15
    const uint8_t *src = (uint8_t*) ctx->frm0;
1371
15
    int ret, height = ctx->height;
1372
15
    ptrdiff_t dstpitch, srcpitch = ctx->pitch * (hdr ? sizeof(ctx->frm0[0]) : 1);
1373
1374
15
    if ((ret = ff_get_buffer(ctx->avctx, ctx->frame, 0)) < 0)
1375
        return ret;
1376
1377
15
    dst      = ctx->frame->data[0];
1378
15
    dstpitch = ctx->frame->linesize[0];
1379
1380
7215
    while (height--) {
1381
7200
        memcpy(dst, src, srcpitch);
1382
7200
        src += srcpitch;
1383
7200
        dst += dstpitch;
1384
    }
1385
1386
15
    return 0;
1387
}
1388
1389
16
static int decode_frame(AVCodecContext *avctx, void *data,
1390
                        int *got_frame_ptr, AVPacket *pkt)
1391
{
1392
16
    SANMVideoContext *ctx = avctx->priv_data;
1393
    int i, ret;
1394
1395
16
    ctx->frame = data;
1396
16
    bytestream2_init(&ctx->gb, pkt->data, pkt->size);
1397
1398
16
    if (!ctx->version) {
1399
        int to_store = 0;
1400
1401
        while (bytestream2_get_bytes_left(&ctx->gb) >= 8) {
1402
            uint32_t sig, size;
1403
            int pos;
1404
1405
            sig  = bytestream2_get_be32u(&ctx->gb);
1406
            size = bytestream2_get_be32u(&ctx->gb);
1407
            pos  = bytestream2_tell(&ctx->gb);
1408
1409
            if (bytestream2_get_bytes_left(&ctx->gb) < size) {
1410
                av_log(avctx, AV_LOG_ERROR, "Incorrect chunk size %"PRIu32".\n", size);
1411
                break;
1412
            }
1413
            switch (sig) {
1414
            case MKBETAG('N', 'P', 'A', 'L'):
1415
                if (size != PALETTE_SIZE * 3) {
1416
                    av_log(avctx, AV_LOG_ERROR,
1417
                           "Incorrect palette block size %"PRIu32".\n", size);
1418
                    return AVERROR_INVALIDDATA;
1419
                }
1420
                for (i = 0; i < PALETTE_SIZE; i++)
1421
                    ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb);
1422
                break;
1423
            case MKBETAG('F', 'O', 'B', 'J'):
1424
                if (size < 16)
1425
                    return AVERROR_INVALIDDATA;
1426
                if (ret = process_frame_obj(ctx))
1427
                    return ret;
1428
                break;
1429
            case MKBETAG('X', 'P', 'A', 'L'):
1430
                if (size == 6 || size == 4) {
1431
                    uint8_t tmp[3];
1432
                    int j;
1433
1434
                    for (i = 0; i < PALETTE_SIZE; i++) {
1435
                        for (j = 0; j < 3; j++) {
1436
                            int t = (ctx->pal[i] >> (16 - j * 8)) & 0xFF;
1437
                            tmp[j] = av_clip_uint8((t * 129 + ctx->delta_pal[i * 3 + j]) >> 7);
1438
                        }
1439
                        ctx->pal[i] = 0xFFU << 24 | AV_RB24(tmp);
1440
                    }
1441
                } else {
1442
                    if (size < PALETTE_DELTA * 2 + 4) {
1443
                        av_log(avctx, AV_LOG_ERROR,
1444
                               "Incorrect palette change block size %"PRIu32".\n",
1445
                               size);
1446
                        return AVERROR_INVALIDDATA;
1447
                    }
1448
                    bytestream2_skipu(&ctx->gb, 4);
1449
                    for (i = 0; i < PALETTE_DELTA; i++)
1450
                        ctx->delta_pal[i] = bytestream2_get_le16u(&ctx->gb);
1451
                    if (size >= PALETTE_DELTA * 5 + 4) {
1452
                        for (i = 0; i < PALETTE_SIZE; i++)
1453
                            ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->gb);
1454
                    } else {
1455
                        memset(ctx->pal, 0, sizeof(ctx->pal));
1456
                    }
1457
                }
1458
                break;
1459
            case MKBETAG('S', 'T', 'O', 'R'):
1460
                to_store = 1;
1461
                break;
1462
            case MKBETAG('F', 'T', 'C', 'H'):
1463
                memcpy(ctx->frm0, ctx->stored_frame, ctx->buf_size);
1464
                break;
1465
            default:
1466
                bytestream2_skip(&ctx->gb, size);
1467
                av_log(avctx, AV_LOG_DEBUG,
1468
                       "Unknown/unsupported chunk %"PRIx32".\n", sig);
1469
                break;
1470
            }
1471
1472
            bytestream2_seek(&ctx->gb, pos + size, SEEK_SET);
1473
            if (size & 1)
1474
                bytestream2_skip(&ctx->gb, 1);
1475
        }
1476
        if (to_store)
1477
            memcpy(ctx->stored_frame, ctx->frm0, ctx->buf_size);
1478
        if ((ret = copy_output(ctx, NULL)))
1479
            return ret;
1480
        memcpy(ctx->frame->data[1], ctx->pal, 1024);
1481
    } else {
1482
        SANMFrameHeader header;
1483
1484
16
        if ((ret = read_frame_header(ctx, &header)))
1485
1
            return ret;
1486
1487
16
        ctx->rotate_code = header.rotate_code;
1488
16
        if ((ctx->frame->key_frame = !header.seq_num)) {
1489
1
            ctx->frame->pict_type = AV_PICTURE_TYPE_I;
1490
1
            fill_frame(ctx->frm1, ctx->npixels, header.bg_color);
1491
1
            fill_frame(ctx->frm2, ctx->npixels, header.bg_color);
1492
        } else {
1493
15
            ctx->frame->pict_type = AV_PICTURE_TYPE_P;
1494
        }
1495
1496
16
        if (header.codec < FF_ARRAY_ELEMS(v1_decoders)) {
1497
16
            if ((ret = v1_decoders[header.codec](ctx))) {
1498
1
                av_log(avctx, AV_LOG_ERROR,
1499
                       "Subcodec %d: error decoding frame.\n", header.codec);
1500
1
                return ret;
1501
            }
1502
        } else {
1503
            avpriv_request_sample(avctx, "Subcodec %d", header.codec);
1504
            return AVERROR_PATCHWELCOME;
1505
        }
1506
1507
15
        if ((ret = copy_output(ctx, &header)))
1508
            return ret;
1509
    }
1510
15
    if (ctx->rotate_code)
1511
9
        rotate_bufs(ctx, ctx->rotate_code);
1512
1513
15
    *got_frame_ptr = 1;
1514
1515
15
    return pkt->size;
1516
}
1517
1518
AVCodec ff_sanm_decoder = {
1519
    .name           = "sanm",
1520
    .long_name      = NULL_IF_CONFIG_SMALL("LucasArts SANM/Smush video"),
1521
    .type           = AVMEDIA_TYPE_VIDEO,
1522
    .id             = AV_CODEC_ID_SANM,
1523
    .priv_data_size = sizeof(SANMVideoContext),
1524
    .init           = decode_init,
1525
    .close          = decode_end,
1526
    .decode         = decode_frame,
1527
    .capabilities   = AV_CODEC_CAP_DR1,
1528
};