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 "avcodec.h" 23#include "get_bits.h" 24#include "bytestream.h" 25#include "codec_internal.h" 26#include "internal.h" 27 28#define PALDATA_FOLLOWS_TILEDATA 4 29#define HAVE_COMPRESSED_TILEMAP 32 30#define HAVE_TILEMAP 128 31 32typedef struct SGAVideoContext { 33 GetByteContext gb; 34 35 int metadata_size; 36 int tiledata_size; 37 int tiledata_offset; 38 int tilemapdata_size; 39 int tilemapdata_offset; 40 int paldata_size; 41 int paldata_offset; 42 int palmapdata_offset; 43 int palmapdata_size; 44 45 int flags; 46 int nb_pal; 47 int nb_tiles; 48 int tiles_w, tiles_h; 49 int shift; 50 int plus; 51 int swap; 52 53 uint32_t pal[256]; 54 uint8_t *tileindex_data; 55 unsigned tileindex_size; 56 uint8_t *palmapindex_data; 57 unsigned palmapindex_size; 58 uint8_t uncompressed[65536]; 59} SGAVideoContext; 60 61static av_cold int sga_decode_init(AVCodecContext *avctx) 62{ 63 avctx->pix_fmt = AV_PIX_FMT_PAL8; 64 return 0; 65} 66 67static int decode_palette(GetByteContext *gb, uint32_t *pal) 68{ 69 GetBitContext gbit; 70 71 if (bytestream2_get_bytes_left(gb) < 18) 72 return AVERROR_INVALIDDATA; 73 74 memset(pal, 0, 16 * sizeof(*pal)); 75 init_get_bits8(&gbit, gb->buffer, 18); 76 77 for (int RGBIndex = 0; RGBIndex < 3; RGBIndex++) { 78 for (int index = 0; index < 16; index++) { 79 unsigned color = get_bits1(&gbit) << RGBIndex; 80 pal[15 - index] |= color << (5 + 16); 81 } 82 } 83 84 for (int RGBIndex = 0; RGBIndex < 3; RGBIndex++) { 85 for (int index = 0; index < 16; index++) { 86 unsigned color = get_bits1(&gbit) << RGBIndex; 87 pal[15 - index] |= color << (5 + 8); 88 } 89 } 90 91 for (int RGBIndex = 0; RGBIndex < 3; RGBIndex++) { 92 for (int index = 0; index < 16; index++) { 93 unsigned color = get_bits1(&gbit) << RGBIndex; 94 pal[15 - index] |= color << (5 + 0); 95 } 96 } 97 98 for (int index = 0; index < 16; index++) 99 pal[index] = (0xFFU << 24) | pal[index] | (pal[index] >> 3); 100 101 bytestream2_skip(gb, 18); 102 103 return 0; 104} 105 106static int decode_index_palmap(SGAVideoContext *s, AVFrame *frame) 107{ 108 const uint8_t *tt = s->tileindex_data; 109 110 for (int y = 0; y < s->tiles_h; y++) { 111 for (int x = 0; x < s->tiles_w; x++) { 112 int pal_idx = s->palmapindex_data[y * s->tiles_w + x] * 16; 113 uint8_t *dst = frame->data[0] + y * 8 * frame->linesize[0] + x * 8; 114 115 for (int yy = 0; yy < 8; yy++) { 116 for (int xx = 0; xx < 8; xx++) 117 dst[xx] = pal_idx + tt[xx]; 118 tt += 8; 119 120 dst += frame->linesize[0]; 121 } 122 } 123 } 124 125 return 0; 126} 127 128static int decode_index_tilemap(SGAVideoContext *s, AVFrame *frame) 129{ 130 GetByteContext *gb = &s->gb; 131 GetBitContext pm; 132 133 bytestream2_seek(gb, s->tilemapdata_offset, SEEK_SET); 134 if (bytestream2_get_bytes_left(gb) < s->tilemapdata_size) 135 return AVERROR_INVALIDDATA; 136 137 init_get_bits8(&pm, gb->buffer, s->tilemapdata_size); 138 139 for (int y = 0; y < s->tiles_h; y++) { 140 for (int x = 0; x < s->tiles_w; x++) { 141 uint8_t tile[64]; 142 int tilemap = get_bits(&pm, 16); 143 int flip_x = (tilemap >> 11) & 1; 144 int flip_y = (tilemap >> 12) & 1; 145 int tindex = av_clip((tilemap & 511) - 1, 0, s->nb_tiles - 1); 146 const uint8_t *tt = s->tileindex_data + tindex * 64; 147 int pal_idx = ((tilemap >> 13) & 3) * 16; 148 uint8_t *dst = frame->data[0] + y * 8 * frame->linesize[0] + x * 8; 149 150 if (!flip_x && !flip_y) { 151 memcpy(tile, tt, 64); 152 } else if (flip_x && flip_y) { 153 for (int i = 0; i < 8; i++) { 154 for (int j = 0; j < 8; j++) 155 tile[i * 8 + j] = tt[(7 - i) * 8 + 7 - j]; 156 } 157 } else if (flip_x) { 158 for (int i = 0; i < 8; i++) { 159 for (int j = 0; j < 8; j++) 160 tile[i * 8 + j] = tt[i * 8 + 7 - j]; 161 } 162 } else { 163 for (int i = 0; i < 8; i++) { 164 for (int j = 0; j < 8; j++) 165 tile[i * 8 + j] = tt[(7 - i) * 8 + j]; 166 } 167 } 168 169 for (int yy = 0; yy < 8; yy++) { 170 for (int xx = 0; xx < 8; xx++) 171 dst[xx] = pal_idx + tile[xx + yy * 8]; 172 173 dst += frame->linesize[0]; 174 } 175 } 176 } 177 178 return 0; 179} 180 181static int decode_index(SGAVideoContext *s, AVFrame *frame) 182{ 183 const uint8_t *src = s->tileindex_data; 184 uint8_t *dst = frame->data[0]; 185 186 for (int y = 0; y < frame->height; y += 8) { 187 for (int x = 0; x < frame->width; x += 8) { 188 for (int yy = 0; yy < 8; yy++) { 189 for (int xx = 0; xx < 8; xx++) 190 dst[x + xx + yy * frame->linesize[0]] = src[xx]; 191 src += 8; 192 } 193 } 194 195 dst += 8 * frame->linesize[0]; 196 } 197 198 return 0; 199} 200 201static int lzss_decompress(AVCodecContext *avctx, 202 GetByteContext *gb, uint8_t *dst, 203 int dst_size, int shift, int plus) 204{ 205 int oi = 0; 206 207 while (bytestream2_get_bytes_left(gb) > 0 && oi < dst_size) { 208 uint16_t displace, header = bytestream2_get_be16(gb); 209 int count, offset; 210 211 for (int i = 0; i < 16; i++) { 212 switch (header >> 15) { 213 case 0: 214 if (oi + 2 < dst_size) { 215 dst[oi++] = bytestream2_get_byte(gb); 216 dst[oi++] = bytestream2_get_byte(gb); 217 } 218 break; 219 case 1: 220 displace = bytestream2_get_be16(gb); 221 count = displace >> shift; 222 offset = displace & ((1 << shift) - 1); 223 224 if (displace == 0) { 225 while (bytestream2_get_bytes_left(gb) > 0 && 226 oi < dst_size) 227 dst[oi++] = bytestream2_get_byte(gb); 228 return oi; 229 } 230 231 count += plus; 232 233 if (offset <= 0) 234 offset = 1; 235 if (oi < offset || oi + count * 2 > dst_size) 236 return AVERROR_INVALIDDATA; 237 for (int j = 0; j < count * 2; j++) { 238 dst[oi] = dst[oi - offset]; 239 oi++; 240 } 241 break; 242 } 243 244 header <<= 1; 245 } 246 } 247 248 return AVERROR_INVALIDDATA; 249} 250 251static int decode_palmapdata(AVCodecContext *avctx) 252{ 253 SGAVideoContext *s = avctx->priv_data; 254 const int bits = (s->nb_pal + 1) / 2; 255 GetByteContext *gb = &s->gb; 256 GetBitContext pm; 257 258 bytestream2_seek(gb, s->palmapdata_offset, SEEK_SET); 259 if (bytestream2_get_bytes_left(gb) < s->palmapdata_size) 260 return AVERROR_INVALIDDATA; 261 init_get_bits8(&pm, gb->buffer, s->palmapdata_size); 262 263 for (int y = 0; y < s->tiles_h; y++) { 264 uint8_t *dst = s->palmapindex_data + y * s->tiles_w; 265 266 for (int x = 0; x < s->tiles_w; x++) 267 dst[x] = get_bits(&pm, bits); 268 269 dst += s->tiles_w; 270 } 271 272 return 0; 273} 274 275static int decode_tiledata(AVCodecContext *avctx) 276{ 277 SGAVideoContext *s = avctx->priv_data; 278 GetByteContext *gb = &s->gb; 279 GetBitContext tm; 280 281 bytestream2_seek(gb, s->tiledata_offset, SEEK_SET); 282 if (bytestream2_get_bytes_left(gb) < s->tiledata_size) 283 return AVERROR_INVALIDDATA; 284 init_get_bits8(&tm, gb->buffer, s->tiledata_size); 285 286 for (int n = 0; n < s->nb_tiles; n++) { 287 uint8_t *dst = s->tileindex_data + n * 64; 288 289 for (int yy = 0; yy < 8; yy++) { 290 for (int xx = 0; xx < 8; xx++) 291 dst[xx] = get_bits(&tm, 4); 292 293 dst += 8; 294 } 295 } 296 297 for (int i = 0; i < s->nb_tiles && s->swap; i++) { 298 uint8_t *dst = s->tileindex_data + i * 64; 299 300 for (int j = 8; j < 64; j += 16) { 301 for (int k = 0; k < 8; k += 2) 302 FFSWAP(uint8_t, dst[j + k], dst[j+k+1]); 303 } 304 } 305 306 return 0; 307} 308 309static int sga_decode_frame(AVCodecContext *avctx, AVFrame *frame, 310 int *got_frame, AVPacket *avpkt) 311{ 312 SGAVideoContext *s = avctx->priv_data; 313 GetByteContext *gb = &s->gb; 314 int ret, type; 315 316 if (avpkt->size <= 14) 317 return AVERROR_INVALIDDATA; 318 319 s->flags = avpkt->data[8]; 320 s->nb_pal = avpkt->data[9]; 321 s->tiles_w = avpkt->data[10]; 322 s->tiles_h = avpkt->data[11]; 323 324 if (s->nb_pal > 4) 325 return AVERROR_INVALIDDATA; 326 327 if ((ret = ff_set_dimensions(avctx, 328 s->tiles_w * 8, 329 s->tiles_h * 8)) < 0) 330 return ret; 331 332 av_fast_padded_malloc(&s->tileindex_data, &s->tileindex_size, 333 avctx->width * avctx->height); 334 if (!s->tileindex_data) 335 return AVERROR(ENOMEM); 336 337 av_fast_padded_malloc(&s->palmapindex_data, &s->palmapindex_size, 338 s->tiles_w * s->tiles_h); 339 if (!s->palmapindex_data) 340 return AVERROR(ENOMEM); 341 342 if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) 343 return ret; 344 345 bytestream2_init(gb, avpkt->data, avpkt->size); 346 347 type = bytestream2_get_byte(gb); 348 s->metadata_size = 12 + ((!!(s->flags & HAVE_TILEMAP)) * 2); 349 s->nb_tiles = s->flags & HAVE_TILEMAP ? AV_RB16(avpkt->data + 12) : s->tiles_w * s->tiles_h; 350 if (s->nb_tiles > s->tiles_w * s->tiles_h) 351 return AVERROR_INVALIDDATA; 352 353 av_log(avctx, AV_LOG_DEBUG, "type: %X flags: %X nb_tiles: %d\n", type, s->flags, s->nb_tiles); 354 355 switch (type) { 356 case 0xE7: 357 case 0xCB: 358 case 0xCD: 359 s->swap = 1; 360 s->shift = 12; 361 s->plus = 1; 362 break; 363 case 0xC9: 364 s->swap = 1; 365 s->shift = 13; 366 s->plus = 1; 367 break; 368 case 0xC8: 369 s->swap = 1; 370 s->shift = 13; 371 s->plus = 0; 372 break; 373 case 0xC7: 374 s->swap = 0; 375 s->shift = 13; 376 s->plus = 1; 377 break; 378 case 0xC6: 379 s->swap = 0; 380 s->shift = 13; 381 s->plus = 0; 382 break; 383 } 384 385 if (type == 0xE7) { 386 int offset = s->metadata_size, left; 387 int sizes[3]; 388 389 bytestream2_seek(gb, s->metadata_size, SEEK_SET); 390 391 for (int i = 0; i < 3; i++) 392 sizes[i] = bytestream2_get_be16(gb); 393 394 for (int i = 0; i < 3; i++) { 395 int size = sizes[i]; 396 int raw = size >> 15; 397 398 size &= (1 << 15) - 1; 399 400 if (raw) { 401 if (bytestream2_get_bytes_left(gb) < size) 402 return AVERROR_INVALIDDATA; 403 404 if (sizeof(s->uncompressed) - offset < size) 405 return AVERROR_INVALIDDATA; 406 407 memcpy(s->uncompressed + offset, gb->buffer, size); 408 bytestream2_skip(gb, size); 409 } else { 410 GetByteContext gb2; 411 412 if (bytestream2_get_bytes_left(gb) < size) 413 return AVERROR_INVALIDDATA; 414 415 bytestream2_init(&gb2, gb->buffer, size); 416 ret = lzss_decompress(avctx, &gb2, s->uncompressed + offset, 417 sizeof(s->uncompressed) - offset, s->shift, s->plus); 418 if (ret < 0) 419 return ret; 420 bytestream2_skip(gb, size); 421 size = ret; 422 } 423 424 offset += size; 425 } 426 427 left = bytestream2_get_bytes_left(gb); 428 if (sizeof(s->uncompressed) - offset < left) 429 return AVERROR_INVALIDDATA; 430 431 bytestream2_get_buffer(gb, s->uncompressed + offset, left); 432 433 offset += left; 434 bytestream2_init(gb, s->uncompressed, offset); 435 } 436 437 switch (type) { 438 case 0xCD: 439 case 0xCB: 440 case 0xC9: 441 case 0xC8: 442 case 0xC7: 443 case 0xC6: 444 bytestream2_seek(gb, s->metadata_size, SEEK_SET); 445 ret = lzss_decompress(avctx, gb, s->uncompressed + s->metadata_size, 446 sizeof(s->uncompressed) - s->metadata_size, s->shift, s->plus); 447 if (ret < 0) 448 return ret; 449 bytestream2_init(gb, s->uncompressed, ret + s->metadata_size); 450 case 0xE7: 451 case 0xC1: 452 s->tiledata_size = s->nb_tiles * 32; 453 s->paldata_size = s->nb_pal * 18; 454 s->tiledata_offset = s->flags & PALDATA_FOLLOWS_TILEDATA ? s->metadata_size : s->metadata_size + s->paldata_size; 455 s->paldata_offset = s->flags & PALDATA_FOLLOWS_TILEDATA ? s->metadata_size + s->tiledata_size : s->metadata_size; 456 s->palmapdata_offset = (s->flags & HAVE_TILEMAP) ? -1 : s->paldata_offset + s->paldata_size; 457 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; 458 s->tilemapdata_size = (s->flags & HAVE_TILEMAP) ? s->tiles_w * s->tiles_h * 2 : 0; 459 s->tilemapdata_offset = (s->flags & HAVE_TILEMAP) ? s->paldata_offset + s->paldata_size: -1; 460 461 bytestream2_seek(gb, s->paldata_offset, SEEK_SET); 462 for (int n = 0; n < s->nb_pal; n++) { 463 ret = decode_palette(gb, s->pal + 16 * n); 464 if (ret < 0) 465 return ret; 466 } 467 468 if (s->tiledata_size > 0) { 469 ret = decode_tiledata(avctx); 470 if (ret < 0) 471 return ret; 472 } 473 474 if (s->palmapdata_size > 0) { 475 ret = decode_palmapdata(avctx); 476 if (ret < 0) 477 return ret; 478 } 479 480 if (s->palmapdata_size > 0 && s->tiledata_size > 0) { 481 ret = decode_index_palmap(s, frame); 482 if (ret < 0) 483 return ret; 484 } else if (s->tilemapdata_size > 0 && s->tiledata_size > 0) { 485 ret = decode_index_tilemap(s, frame); 486 if (ret < 0) 487 return ret; 488 } else if (s->tiledata_size > 0) { 489 ret = decode_index(s, frame); 490 if (ret < 0) 491 return ret; 492 } 493 break; 494 default: 495 av_log(avctx, AV_LOG_ERROR, "Unknown type: %X\n", type); 496 return AVERROR_INVALIDDATA; 497 } 498 499 memcpy(frame->data[1], s->pal, AVPALETTE_SIZE); 500 frame->palette_has_changed = 1; 501 frame->pict_type = AV_PICTURE_TYPE_I; 502 frame->key_frame = 1; 503 504 *got_frame = 1; 505 506 return avpkt->size; 507} 508 509static av_cold int sga_decode_end(AVCodecContext *avctx) 510{ 511 SGAVideoContext *s = avctx->priv_data; 512 513 av_freep(&s->tileindex_data); 514 s->tileindex_size = 0; 515 516 av_freep(&s->palmapindex_data); 517 s->palmapindex_size = 0; 518 519 return 0; 520} 521 522const FFCodec ff_sga_decoder = { 523 .p.name = "sga", 524 .p.long_name = NULL_IF_CONFIG_SMALL("Digital Pictures SGA Video"), 525 .p.type = AVMEDIA_TYPE_VIDEO, 526 .p.id = AV_CODEC_ID_SGA_VIDEO, 527 .priv_data_size = sizeof(SGAVideoContext), 528 .init = sga_decode_init, 529 FF_CODEC_DECODE_CB(sga_decode_frame), 530 .close = sga_decode_end, 531 .p.capabilities = AV_CODEC_CAP_DR1, 532 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 533}; 534