/src/ffmpeg/libavcodec/sga.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2021 Paul B Mahol |
3 | | * |
4 | | * This file is part of FFmpeg. |
5 | | * |
6 | | * FFmpeg is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU Lesser General Public |
8 | | * License as published by the Free Software Foundation; either |
9 | | * version 2.1 of the License, or (at your option) any later version. |
10 | | * |
11 | | * FFmpeg is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | | * Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public |
17 | | * License along with FFmpeg; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | | */ |
20 | | |
21 | | #include "libavutil/common.h" |
22 | | #include "libavutil/mem.h" |
23 | | #include "avcodec.h" |
24 | | #include "get_bits.h" |
25 | | #include "bytestream.h" |
26 | | #include "codec_internal.h" |
27 | | #include "decode.h" |
28 | | |
29 | 213k | #define PALDATA_FOLLOWS_TILEDATA 4 |
30 | | #define HAVE_COMPRESSED_TILEMAP 32 |
31 | 652k | #define HAVE_TILEMAP 128 |
32 | | |
33 | | typedef struct SGAVideoContext { |
34 | | GetByteContext gb; |
35 | | |
36 | | int metadata_size; |
37 | | int tiledata_size; |
38 | | int tiledata_offset; |
39 | | int tilemapdata_size; |
40 | | int tilemapdata_offset; |
41 | | int paldata_size; |
42 | | int paldata_offset; |
43 | | int palmapdata_offset; |
44 | | int palmapdata_size; |
45 | | |
46 | | int flags; |
47 | | int nb_pal; |
48 | | int nb_tiles; |
49 | | int tiles_w, tiles_h; |
50 | | int shift; |
51 | | int plus; |
52 | | int swap; |
53 | | |
54 | | uint32_t pal[256]; |
55 | | uint8_t *tileindex_data; |
56 | | unsigned tileindex_size; |
57 | | uint8_t *palmapindex_data; |
58 | | unsigned palmapindex_size; |
59 | | uint8_t uncompressed[65536]; |
60 | | } SGAVideoContext; |
61 | | |
62 | | static av_cold int sga_decode_init(AVCodecContext *avctx) |
63 | 1.73k | { |
64 | 1.73k | avctx->pix_fmt = AV_PIX_FMT_PAL8; |
65 | 1.73k | return 0; |
66 | 1.73k | } |
67 | | |
68 | | static int decode_palette(GetByteContext *gb, uint32_t *pal) |
69 | 6.22k | { |
70 | 6.22k | GetBitContext gbit; |
71 | | |
72 | 6.22k | if (bytestream2_get_bytes_left(gb) < 18) |
73 | 1.21k | return AVERROR_INVALIDDATA; |
74 | | |
75 | 5.01k | memset(pal, 0, 16 * sizeof(*pal)); |
76 | 5.01k | (void)init_get_bits8(&gbit, gb->buffer, 18); |
77 | | |
78 | 20.0k | for (int RGBIndex = 0; RGBIndex < 3; RGBIndex++) { |
79 | 255k | for (int index = 0; index < 16; index++) { |
80 | 240k | unsigned color = get_bits1(&gbit) << RGBIndex; |
81 | 240k | pal[15 - index] |= color << (5 + 16); |
82 | 240k | } |
83 | 15.0k | } |
84 | | |
85 | 20.0k | for (int RGBIndex = 0; RGBIndex < 3; RGBIndex++) { |
86 | 255k | for (int index = 0; index < 16; index++) { |
87 | 240k | unsigned color = get_bits1(&gbit) << RGBIndex; |
88 | 240k | pal[15 - index] |= color << (5 + 8); |
89 | 240k | } |
90 | 15.0k | } |
91 | | |
92 | 20.0k | for (int RGBIndex = 0; RGBIndex < 3; RGBIndex++) { |
93 | 255k | for (int index = 0; index < 16; index++) { |
94 | 240k | unsigned color = get_bits1(&gbit) << RGBIndex; |
95 | 240k | pal[15 - index] |= color << (5 + 0); |
96 | 240k | } |
97 | 15.0k | } |
98 | | |
99 | 85.2k | for (int index = 0; index < 16; index++) |
100 | 80.2k | pal[index] = (0xFFU << 24) | pal[index] | (pal[index] >> 3); |
101 | | |
102 | 5.01k | bytestream2_skip(gb, 18); |
103 | | |
104 | 5.01k | return 0; |
105 | 6.22k | } |
106 | | |
107 | | static int decode_index_palmap(SGAVideoContext *s, AVFrame *frame) |
108 | 455 | { |
109 | 455 | const uint8_t *tt = s->tileindex_data; |
110 | | |
111 | 6.06k | for (int y = 0; y < s->tiles_h; y++) { |
112 | 146k | for (int x = 0; x < s->tiles_w; x++) { |
113 | 140k | int pal_idx = s->palmapindex_data[y * s->tiles_w + x] * 16; |
114 | 140k | uint8_t *dst = frame->data[0] + y * 8 * frame->linesize[0] + x * 8; |
115 | | |
116 | 1.26M | for (int yy = 0; yy < 8; yy++) { |
117 | 10.1M | for (int xx = 0; xx < 8; xx++) |
118 | 8.98M | dst[xx] = pal_idx + tt[xx]; |
119 | 1.12M | tt += 8; |
120 | | |
121 | 1.12M | dst += frame->linesize[0]; |
122 | 1.12M | } |
123 | 140k | } |
124 | 5.60k | } |
125 | | |
126 | 455 | return 0; |
127 | 455 | } |
128 | | |
129 | | static int decode_index_tilemap(SGAVideoContext *s, AVFrame *frame) |
130 | 721 | { |
131 | 721 | GetByteContext *gb = &s->gb, gb2; |
132 | | |
133 | 721 | bytestream2_seek(gb, s->tilemapdata_offset, SEEK_SET); |
134 | 721 | if (bytestream2_get_bytes_left(gb) < s->tilemapdata_size) |
135 | 395 | return AVERROR_INVALIDDATA; |
136 | | |
137 | 326 | gb2 = *gb; |
138 | | |
139 | 6.09k | for (int y = 0; y < s->tiles_h; y++) { |
140 | 416k | for (int x = 0; x < s->tiles_w; x++) { |
141 | 410k | uint8_t tile[64]; |
142 | 410k | int tilemap = bytestream2_get_be16u(&gb2); |
143 | 410k | int flip_x = (tilemap >> 11) & 1; |
144 | 410k | int flip_y = (tilemap >> 12) & 1; |
145 | 410k | int tindex = av_clip((tilemap & 511) - 1, 0, s->nb_tiles - 1); |
146 | 410k | const uint8_t *tt = s->tileindex_data + tindex * 64; |
147 | 410k | int pal_idx = ((tilemap >> 13) & 3) * 16; |
148 | 410k | uint8_t *dst = frame->data[0] + y * 8 * frame->linesize[0] + x * 8; |
149 | | |
150 | 410k | if (!flip_x && !flip_y) { |
151 | 286k | memcpy(tile, tt, 64); |
152 | 286k | } else if (flip_x && flip_y) { |
153 | 712k | for (int i = 0; i < 8; i++) { |
154 | 5.69M | for (int j = 0; j < 8; j++) |
155 | 5.06M | tile[i * 8 + j] = tt[(7 - i) * 8 + 7 - j]; |
156 | 632k | } |
157 | 79.1k | } else if (flip_x) { |
158 | 226k | for (int i = 0; i < 8; i++) { |
159 | 1.81M | for (int j = 0; j < 8; j++) |
160 | 1.61M | tile[i * 8 + j] = tt[i * 8 + 7 - j]; |
161 | 201k | } |
162 | 25.1k | } else { |
163 | 178k | for (int i = 0; i < 8; i++) { |
164 | 1.42M | for (int j = 0; j < 8; j++) |
165 | 1.26M | tile[i * 8 + j] = tt[(7 - i) * 8 + j]; |
166 | 158k | } |
167 | 19.8k | } |
168 | | |
169 | 3.69M | for (int yy = 0; yy < 8; yy++) { |
170 | 29.5M | for (int xx = 0; xx < 8; xx++) |
171 | 26.2M | dst[xx] = pal_idx + tile[xx + yy * 8]; |
172 | | |
173 | 3.28M | dst += frame->linesize[0]; |
174 | 3.28M | } |
175 | 410k | } |
176 | 5.77k | } |
177 | | |
178 | 326 | return 0; |
179 | 721 | } |
180 | | |
181 | | static int decode_index(SGAVideoContext *s, AVFrame *frame) |
182 | 323 | { |
183 | 323 | const uint8_t *src = s->tileindex_data; |
184 | 323 | uint8_t *dst = frame->data[0]; |
185 | | |
186 | 4.51k | for (int y = 0; y < frame->height; y += 8) { |
187 | 55.4k | for (int x = 0; x < frame->width; x += 8) { |
188 | 461k | for (int yy = 0; yy < 8; yy++) { |
189 | 3.69M | for (int xx = 0; xx < 8; xx++) |
190 | 3.28M | dst[x + xx + yy * frame->linesize[0]] = src[xx]; |
191 | 410k | src += 8; |
192 | 410k | } |
193 | 51.2k | } |
194 | | |
195 | 4.18k | dst += 8 * frame->linesize[0]; |
196 | 4.18k | } |
197 | | |
198 | 323 | return 0; |
199 | 323 | } |
200 | | |
201 | | static int lzss_decompress(AVCodecContext *avctx, |
202 | | GetByteContext *gb, uint8_t *dst, |
203 | | int dst_size, int shift, int plus) |
204 | 12.8k | { |
205 | 12.8k | int oi = 0; |
206 | | |
207 | 92.6k | while (bytestream2_get_bytes_left(gb) > 0 && oi < dst_size) { |
208 | 91.0k | uint16_t displace, header = bytestream2_get_be16(gb); |
209 | 91.0k | int count, offset; |
210 | | |
211 | 1.45M | for (int i = 0; i < 16; i++) { |
212 | 1.37M | switch (header >> 15) { |
213 | 735k | case 0: |
214 | 735k | if (oi + 2 < dst_size) { |
215 | 725k | dst[oi++] = bytestream2_get_byte(gb); |
216 | 725k | dst[oi++] = bytestream2_get_byte(gb); |
217 | 725k | } |
218 | 735k | break; |
219 | 640k | case 1: |
220 | 640k | displace = bytestream2_get_be16(gb); |
221 | 640k | count = displace >> shift; |
222 | 640k | offset = displace & ((1 << shift) - 1); |
223 | | |
224 | 640k | if (displace == 0) { |
225 | 3.20M | while (bytestream2_get_bytes_left(gb) > 0 && |
226 | 3.19M | oi < dst_size) |
227 | 3.19M | dst[oi++] = bytestream2_get_byte(gb); |
228 | 10.2k | return oi; |
229 | 10.2k | } |
230 | | |
231 | 630k | count += plus; |
232 | | |
233 | 630k | if (offset <= 0) |
234 | 1.62k | offset = 1; |
235 | 630k | if (oi < offset || oi + count * 2 > dst_size) |
236 | 1.01k | return AVERROR_INVALIDDATA; |
237 | 18.3M | for (int j = 0; j < count * 2; j++) { |
238 | 17.7M | dst[oi] = dst[oi - offset]; |
239 | 17.7M | oi++; |
240 | 17.7M | } |
241 | 629k | break; |
242 | 1.37M | } |
243 | | |
244 | 1.36M | header <<= 1; |
245 | 1.36M | } |
246 | 91.0k | } |
247 | | |
248 | 1.62k | return AVERROR_INVALIDDATA; |
249 | 12.8k | } |
250 | | |
251 | | static int decode_palmapdata(AVCodecContext *avctx) |
252 | 735 | { |
253 | 735 | SGAVideoContext *s = avctx->priv_data; |
254 | 735 | const int bits = (s->nb_pal + 1) / 2; |
255 | 735 | GetByteContext *gb = &s->gb; |
256 | 735 | GetBitContext pm; |
257 | 735 | av_unused int ret; |
258 | | |
259 | 735 | bytestream2_seek(gb, s->palmapdata_offset, SEEK_SET); |
260 | 735 | if (bytestream2_get_bytes_left(gb) < s->palmapdata_size) |
261 | 280 | return AVERROR_INVALIDDATA; |
262 | 455 | ret = init_get_bits8(&pm, gb->buffer, s->palmapdata_size); |
263 | 455 | av_assert1(ret >= 0); |
264 | | |
265 | 6.06k | for (int y = 0; y < s->tiles_h; y++) { |
266 | 5.60k | uint8_t *dst = s->palmapindex_data + y * s->tiles_w; |
267 | | |
268 | 146k | for (int x = 0; x < s->tiles_w; x++) |
269 | 140k | dst[x] = get_bits(&pm, bits); |
270 | | |
271 | 5.60k | dst += s->tiles_w; |
272 | 5.60k | } |
273 | | |
274 | 455 | return 0; |
275 | 735 | } |
276 | | |
277 | | static int decode_tiledata(AVCodecContext *avctx) |
278 | 4.27k | { |
279 | 4.27k | SGAVideoContext *s = avctx->priv_data; |
280 | 4.27k | GetByteContext *gb = &s->gb; |
281 | 4.27k | GetBitContext tm; |
282 | 4.27k | av_unused int ret; |
283 | | |
284 | 4.27k | bytestream2_seek(gb, s->tiledata_offset, SEEK_SET); |
285 | 4.27k | if (bytestream2_get_bytes_left(gb) < s->tiledata_size) |
286 | 2.49k | return AVERROR_INVALIDDATA; |
287 | 1.77k | ret = init_get_bits8(&tm, gb->buffer, s->tiledata_size); |
288 | 1.77k | av_assert1(ret >= 0); |
289 | | |
290 | 385k | for (int n = 0; n < s->nb_tiles; n++) { |
291 | 383k | uint8_t *dst = s->tileindex_data + n * 64; |
292 | | |
293 | 3.45M | for (int yy = 0; yy < 8; yy++) { |
294 | 27.6M | for (int xx = 0; xx < 8; xx++) |
295 | 24.5M | dst[xx] = get_bits(&tm, 4); |
296 | | |
297 | 3.07M | dst += 8; |
298 | 3.07M | } |
299 | 383k | } |
300 | | |
301 | 77.2k | for (int i = 0; i < s->nb_tiles && s->swap; i++) { |
302 | 75.4k | uint8_t *dst = s->tileindex_data + i * 64; |
303 | | |
304 | 377k | for (int j = 8; j < 64; j += 16) { |
305 | 1.50M | for (int k = 0; k < 8; k += 2) |
306 | 1.20M | FFSWAP(uint8_t, dst[j + k], dst[j+k+1]); |
307 | 301k | } |
308 | 75.4k | } |
309 | | |
310 | 1.77k | return 0; |
311 | 4.27k | } |
312 | | |
313 | | static int sga_decode_frame(AVCodecContext *avctx, AVFrame *frame, |
314 | | int *got_frame, AVPacket *avpkt) |
315 | 143k | { |
316 | 143k | SGAVideoContext *s = avctx->priv_data; |
317 | 143k | GetByteContext *gb = &s->gb; |
318 | 143k | int ret, type; |
319 | | |
320 | 143k | if (avpkt->size <= 14) |
321 | 24.5k | return AVERROR_INVALIDDATA; |
322 | | |
323 | 119k | s->flags = avpkt->data[8]; |
324 | 119k | s->nb_pal = avpkt->data[9]; |
325 | 119k | s->tiles_w = avpkt->data[10]; |
326 | 119k | s->tiles_h = avpkt->data[11]; |
327 | | |
328 | 119k | if (s->nb_pal > 4) |
329 | 4.86k | return AVERROR_INVALIDDATA; |
330 | | |
331 | 114k | if ((ret = ff_set_dimensions(avctx, |
332 | 114k | s->tiles_w * 8, |
333 | 114k | s->tiles_h * 8)) < 0) |
334 | 1.27k | return ret; |
335 | | |
336 | 113k | av_fast_padded_malloc(&s->tileindex_data, &s->tileindex_size, |
337 | 113k | avctx->width * avctx->height); |
338 | 113k | if (!s->tileindex_data) |
339 | 0 | return AVERROR(ENOMEM); |
340 | | |
341 | 113k | av_fast_padded_malloc(&s->palmapindex_data, &s->palmapindex_size, |
342 | 113k | s->tiles_w * s->tiles_h); |
343 | 113k | if (!s->palmapindex_data) |
344 | 0 | return AVERROR(ENOMEM); |
345 | | |
346 | 113k | if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) |
347 | 0 | return ret; |
348 | | |
349 | 113k | bytestream2_init(gb, avpkt->data, avpkt->size); |
350 | | |
351 | 113k | type = bytestream2_get_byte(gb); |
352 | 113k | s->metadata_size = 12 + ((!!(s->flags & HAVE_TILEMAP)) * 2); |
353 | 113k | s->nb_tiles = s->flags & HAVE_TILEMAP ? AV_RB16(avpkt->data + 12) : s->tiles_w * s->tiles_h; |
354 | 113k | if (s->nb_tiles > s->tiles_w * s->tiles_h) |
355 | 647 | return AVERROR_INVALIDDATA; |
356 | | |
357 | 112k | av_log(avctx, AV_LOG_DEBUG, "type: %X flags: %X nb_tiles: %d\n", type, s->flags, s->nb_tiles); |
358 | | |
359 | 112k | switch (type) { |
360 | 4.46k | case 0xE7: |
361 | 5.37k | case 0xCB: |
362 | 6.67k | case 0xCD: |
363 | 6.67k | s->swap = 1; |
364 | 6.67k | s->shift = 12; |
365 | 6.67k | s->plus = 1; |
366 | 6.67k | break; |
367 | 555 | case 0xC9: |
368 | 555 | s->swap = 1; |
369 | 555 | s->shift = 13; |
370 | 555 | s->plus = 1; |
371 | 555 | break; |
372 | 621 | case 0xC8: |
373 | 621 | s->swap = 1; |
374 | 621 | s->shift = 13; |
375 | 621 | s->plus = 0; |
376 | 621 | break; |
377 | 241 | case 0xC7: |
378 | 241 | s->swap = 0; |
379 | 241 | s->shift = 13; |
380 | 241 | s->plus = 1; |
381 | 241 | break; |
382 | 3.19k | case 0xC6: |
383 | 3.19k | s->swap = 0; |
384 | 3.19k | s->shift = 13; |
385 | 3.19k | s->plus = 0; |
386 | 3.19k | break; |
387 | 112k | } |
388 | | |
389 | 112k | if (type == 0xE7) { |
390 | 4.46k | int offset = s->metadata_size, left; |
391 | 4.46k | int sizes[3]; |
392 | | |
393 | 4.46k | bytestream2_seek(gb, s->metadata_size, SEEK_SET); |
394 | | |
395 | 17.8k | for (int i = 0; i < 3; i++) |
396 | 13.3k | sizes[i] = bytestream2_get_be16(gb); |
397 | | |
398 | 11.5k | for (int i = 0; i < 3; i++) { |
399 | 9.43k | int size = sizes[i]; |
400 | 9.43k | int raw = size >> 15; |
401 | | |
402 | 9.43k | size &= (1 << 15) - 1; |
403 | | |
404 | 9.43k | if (raw) { |
405 | 2.54k | if (bytestream2_get_bytes_left(gb) < size) |
406 | 425 | return AVERROR_INVALIDDATA; |
407 | | |
408 | 2.11k | if (sizeof(s->uncompressed) - offset < size) |
409 | 34 | return AVERROR_INVALIDDATA; |
410 | | |
411 | 2.08k | memcpy(s->uncompressed + offset, gb->buffer, size); |
412 | 2.08k | bytestream2_skip(gb, size); |
413 | 6.89k | } else { |
414 | 6.89k | GetByteContext gb2; |
415 | | |
416 | 6.89k | if (bytestream2_get_bytes_left(gb) < size) |
417 | 823 | return AVERROR_INVALIDDATA; |
418 | | |
419 | 6.07k | bytestream2_init(&gb2, gb->buffer, size); |
420 | 6.07k | ret = lzss_decompress(avctx, &gb2, s->uncompressed + offset, |
421 | 6.07k | sizeof(s->uncompressed) - offset, s->shift, s->plus); |
422 | 6.07k | if (ret < 0) |
423 | 1.11k | return ret; |
424 | 4.95k | bytestream2_skip(gb, size); |
425 | 4.95k | size = ret; |
426 | 4.95k | } |
427 | | |
428 | 7.03k | offset += size; |
429 | 7.03k | } |
430 | | |
431 | 2.06k | left = bytestream2_get_bytes_left(gb); |
432 | 2.06k | if (sizeof(s->uncompressed) - offset < left) |
433 | 49 | return AVERROR_INVALIDDATA; |
434 | | |
435 | 2.01k | bytestream2_get_buffer(gb, s->uncompressed + offset, left); |
436 | | |
437 | 2.01k | offset += left; |
438 | 2.01k | bytestream2_init(gb, s->uncompressed, offset); |
439 | 2.01k | } |
440 | | |
441 | 110k | switch (type) { |
442 | 1.29k | case 0xCD: |
443 | 2.21k | case 0xCB: |
444 | 2.77k | case 0xC9: |
445 | 3.39k | case 0xC8: |
446 | 3.63k | case 0xC7: |
447 | 6.82k | case 0xC6: |
448 | 6.82k | bytestream2_seek(gb, s->metadata_size, SEEK_SET); |
449 | 6.82k | ret = lzss_decompress(avctx, gb, s->uncompressed + s->metadata_size, |
450 | 6.82k | sizeof(s->uncompressed) - s->metadata_size, s->shift, s->plus); |
451 | 6.82k | if (ret < 0) |
452 | 1.52k | return ret; |
453 | 5.29k | bytestream2_init(gb, s->uncompressed, ret + s->metadata_size); |
454 | 7.31k | case 0xE7: |
455 | 106k | case 0xC1: |
456 | 106k | s->tiledata_size = s->nb_tiles * 32; |
457 | 106k | s->paldata_size = s->nb_pal * 18; |
458 | 106k | s->tiledata_offset = s->flags & PALDATA_FOLLOWS_TILEDATA ? s->metadata_size : s->metadata_size + s->paldata_size; |
459 | 106k | s->paldata_offset = s->flags & PALDATA_FOLLOWS_TILEDATA ? s->metadata_size + s->tiledata_size : s->metadata_size; |
460 | 106k | s->palmapdata_offset = (s->flags & HAVE_TILEMAP) ? -1 : s->paldata_offset + s->paldata_size; |
461 | 106k | s->palmapdata_size = (s->flags & HAVE_TILEMAP) || s->nb_pal < 2 ? 0 : (s->tiles_w * s->tiles_h * ((s->nb_pal + 1) / 2) + 7) / 8; |
462 | 106k | s->tilemapdata_size = (s->flags & HAVE_TILEMAP) ? s->tiles_w * s->tiles_h * 2 : 0; |
463 | 106k | s->tilemapdata_offset = (s->flags & HAVE_TILEMAP) ? s->paldata_offset + s->paldata_size: -1; |
464 | | |
465 | 106k | bytestream2_seek(gb, s->paldata_offset, SEEK_SET); |
466 | 111k | for (int n = 0; n < s->nb_pal; n++) { |
467 | 6.22k | ret = decode_palette(gb, s->pal + 16 * n); |
468 | 6.22k | if (ret < 0) |
469 | 1.21k | return ret; |
470 | 6.22k | } |
471 | | |
472 | 105k | if (s->tiledata_size > 0) { |
473 | 4.27k | ret = decode_tiledata(avctx); |
474 | 4.27k | if (ret < 0) |
475 | 2.49k | return ret; |
476 | 4.27k | } |
477 | | |
478 | 102k | if (s->palmapdata_size > 0) { |
479 | 735 | ret = decode_palmapdata(avctx); |
480 | 735 | if (ret < 0) |
481 | 280 | return ret; |
482 | 735 | } |
483 | | |
484 | 102k | if (s->palmapdata_size > 0 && s->tiledata_size > 0) { |
485 | 455 | ret = decode_index_palmap(s, frame); |
486 | 455 | if (ret < 0) |
487 | 0 | return ret; |
488 | 102k | } else if (s->tilemapdata_size > 0 && s->tiledata_size > 0) { |
489 | 721 | ret = decode_index_tilemap(s, frame); |
490 | 721 | if (ret < 0) |
491 | 395 | return ret; |
492 | 101k | } else if (s->tiledata_size > 0) { |
493 | 323 | ret = decode_index(s, frame); |
494 | 323 | if (ret < 0) |
495 | 0 | return ret; |
496 | 323 | } |
497 | 102k | break; |
498 | 102k | default: |
499 | 1.95k | av_log(avctx, AV_LOG_ERROR, "Unknown type: %X\n", type); |
500 | 1.95k | return AVERROR_INVALIDDATA; |
501 | 110k | } |
502 | | |
503 | 102k | memcpy(frame->data[1], s->pal, AVPALETTE_SIZE); |
504 | 102k | frame->pict_type = AV_PICTURE_TYPE_I; |
505 | 102k | frame->flags |= AV_FRAME_FLAG_KEY; |
506 | | |
507 | 102k | *got_frame = 1; |
508 | | |
509 | 102k | return avpkt->size; |
510 | 110k | } |
511 | | |
512 | | static av_cold int sga_decode_end(AVCodecContext *avctx) |
513 | 1.73k | { |
514 | 1.73k | SGAVideoContext *s = avctx->priv_data; |
515 | | |
516 | 1.73k | av_freep(&s->tileindex_data); |
517 | 1.73k | s->tileindex_size = 0; |
518 | | |
519 | 1.73k | av_freep(&s->palmapindex_data); |
520 | 1.73k | s->palmapindex_size = 0; |
521 | | |
522 | 1.73k | return 0; |
523 | 1.73k | } |
524 | | |
525 | | const FFCodec ff_sga_decoder = { |
526 | | .p.name = "sga", |
527 | | CODEC_LONG_NAME("Digital Pictures SGA Video"), |
528 | | .p.type = AVMEDIA_TYPE_VIDEO, |
529 | | .p.id = AV_CODEC_ID_SGA_VIDEO, |
530 | | .priv_data_size = sizeof(SGAVideoContext), |
531 | | .init = sga_decode_init, |
532 | | FF_CODEC_DECODE_CB(sga_decode_frame), |
533 | | .close = sga_decode_end, |
534 | | .p.capabilities = AV_CODEC_CAP_DR1, |
535 | | }; |