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