1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Resolume DXV decoder 3cabdff1aSopenharmony_ci * Copyright (C) 2015 Vittorio Giovara <vittorio.giovara@gmail.com> 4cabdff1aSopenharmony_ci * Copyright (C) 2018 Paul B Mahol 5cabdff1aSopenharmony_ci * 6cabdff1aSopenharmony_ci * This file is part of FFmpeg. 7cabdff1aSopenharmony_ci * 8cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 9cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 10cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 11cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 12cabdff1aSopenharmony_ci * 13cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 14cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 15cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16cabdff1aSopenharmony_ci * Lesser General Public License for more details. 17cabdff1aSopenharmony_ci * 18cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 19cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 20cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21cabdff1aSopenharmony_ci */ 22cabdff1aSopenharmony_ci 23cabdff1aSopenharmony_ci#include <stdint.h> 24cabdff1aSopenharmony_ci 25cabdff1aSopenharmony_ci#include "libavutil/imgutils.h" 26cabdff1aSopenharmony_ci 27cabdff1aSopenharmony_ci#include "mathops.h" 28cabdff1aSopenharmony_ci#include "avcodec.h" 29cabdff1aSopenharmony_ci#include "bytestream.h" 30cabdff1aSopenharmony_ci#include "codec_internal.h" 31cabdff1aSopenharmony_ci#include "lzf.h" 32cabdff1aSopenharmony_ci#include "texturedsp.h" 33cabdff1aSopenharmony_ci#include "thread.h" 34cabdff1aSopenharmony_ci 35cabdff1aSopenharmony_citypedef struct DXVContext { 36cabdff1aSopenharmony_ci TextureDSPContext texdsp; 37cabdff1aSopenharmony_ci GetByteContext gbc; 38cabdff1aSopenharmony_ci 39cabdff1aSopenharmony_ci uint8_t *tex_data; // Compressed texture 40cabdff1aSopenharmony_ci uint8_t *ctex_data; // Compressed texture 41cabdff1aSopenharmony_ci int tex_rat; // Compression ratio 42cabdff1aSopenharmony_ci int tex_step; // Distance between blocks 43cabdff1aSopenharmony_ci int ctex_step; // Distance between blocks 44cabdff1aSopenharmony_ci int64_t tex_size; // Texture size 45cabdff1aSopenharmony_ci int64_t ctex_size; // Texture size 46cabdff1aSopenharmony_ci 47cabdff1aSopenharmony_ci /* Optimal number of slices for parallel decoding */ 48cabdff1aSopenharmony_ci int slice_count; 49cabdff1aSopenharmony_ci 50cabdff1aSopenharmony_ci uint8_t *op_data[4]; // Opcodes 51cabdff1aSopenharmony_ci int64_t op_size[4]; // Opcodes size 52cabdff1aSopenharmony_ci 53cabdff1aSopenharmony_ci int texture_block_w; 54cabdff1aSopenharmony_ci int texture_block_h; 55cabdff1aSopenharmony_ci 56cabdff1aSopenharmony_ci int ctexture_block_w; 57cabdff1aSopenharmony_ci int ctexture_block_h; 58cabdff1aSopenharmony_ci 59cabdff1aSopenharmony_ci /* Pointer to the selected decompression function */ 60cabdff1aSopenharmony_ci int (*tex_funct)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block); 61cabdff1aSopenharmony_ci int (*tex_funct_planar[2])(uint8_t *plane0, ptrdiff_t stride0, 62cabdff1aSopenharmony_ci uint8_t *plane1, ptrdiff_t stride1, 63cabdff1aSopenharmony_ci const uint8_t *block); 64cabdff1aSopenharmony_ci} DXVContext; 65cabdff1aSopenharmony_ci 66cabdff1aSopenharmony_cistatic void decompress_indices(uint8_t *dst, const uint8_t *src) 67cabdff1aSopenharmony_ci{ 68cabdff1aSopenharmony_ci int block, i; 69cabdff1aSopenharmony_ci 70cabdff1aSopenharmony_ci for (block = 0; block < 2; block++) { 71cabdff1aSopenharmony_ci int tmp = AV_RL24(src); 72cabdff1aSopenharmony_ci 73cabdff1aSopenharmony_ci /* Unpack 8x3 bit from last 3 byte block */ 74cabdff1aSopenharmony_ci for (i = 0; i < 8; i++) 75cabdff1aSopenharmony_ci dst[i] = (tmp >> (i * 3)) & 0x7; 76cabdff1aSopenharmony_ci 77cabdff1aSopenharmony_ci src += 3; 78cabdff1aSopenharmony_ci dst += 8; 79cabdff1aSopenharmony_ci } 80cabdff1aSopenharmony_ci} 81cabdff1aSopenharmony_ci 82cabdff1aSopenharmony_cistatic int extract_component(int yo0, int yo1, int code) 83cabdff1aSopenharmony_ci{ 84cabdff1aSopenharmony_ci int yo; 85cabdff1aSopenharmony_ci 86cabdff1aSopenharmony_ci if (yo0 == yo1) { 87cabdff1aSopenharmony_ci yo = yo0; 88cabdff1aSopenharmony_ci } else if (code == 0) { 89cabdff1aSopenharmony_ci yo = yo0; 90cabdff1aSopenharmony_ci } else if (code == 1) { 91cabdff1aSopenharmony_ci yo = yo1; 92cabdff1aSopenharmony_ci } else { 93cabdff1aSopenharmony_ci if (yo0 > yo1) { 94cabdff1aSopenharmony_ci yo = (uint8_t) (((8 - code) * yo0 + 95cabdff1aSopenharmony_ci (code - 1) * yo1) / 7); 96cabdff1aSopenharmony_ci } else { 97cabdff1aSopenharmony_ci if (code == 6) { 98cabdff1aSopenharmony_ci yo = 0; 99cabdff1aSopenharmony_ci } else if (code == 7) { 100cabdff1aSopenharmony_ci yo = 255; 101cabdff1aSopenharmony_ci } else { 102cabdff1aSopenharmony_ci yo = (uint8_t) (((6 - code) * yo0 + 103cabdff1aSopenharmony_ci (code - 1) * yo1) / 5); 104cabdff1aSopenharmony_ci } 105cabdff1aSopenharmony_ci } 106cabdff1aSopenharmony_ci } 107cabdff1aSopenharmony_ci 108cabdff1aSopenharmony_ci return yo; 109cabdff1aSopenharmony_ci} 110cabdff1aSopenharmony_ci 111cabdff1aSopenharmony_cistatic int cocg_block(uint8_t *plane0, ptrdiff_t stride0, 112cabdff1aSopenharmony_ci uint8_t *plane1, ptrdiff_t stride1, 113cabdff1aSopenharmony_ci const uint8_t *block) 114cabdff1aSopenharmony_ci{ 115cabdff1aSopenharmony_ci uint8_t co_indices[16]; 116cabdff1aSopenharmony_ci uint8_t cg_indices[16]; 117cabdff1aSopenharmony_ci uint8_t co0 = *(block); 118cabdff1aSopenharmony_ci uint8_t co1 = *(block + 1); 119cabdff1aSopenharmony_ci uint8_t cg0 = *(block + 8); 120cabdff1aSopenharmony_ci uint8_t cg1 = *(block + 9); 121cabdff1aSopenharmony_ci int x, y; 122cabdff1aSopenharmony_ci 123cabdff1aSopenharmony_ci decompress_indices(co_indices, block + 2); 124cabdff1aSopenharmony_ci decompress_indices(cg_indices, block + 10); 125cabdff1aSopenharmony_ci 126cabdff1aSopenharmony_ci for (y = 0; y < 4; y++) { 127cabdff1aSopenharmony_ci for (x = 0; x < 4; x++) { 128cabdff1aSopenharmony_ci int co_code = co_indices[x + y * 4]; 129cabdff1aSopenharmony_ci int cg_code = cg_indices[x + y * 4]; 130cabdff1aSopenharmony_ci 131cabdff1aSopenharmony_ci plane0[x] = extract_component(cg0, cg1, cg_code); 132cabdff1aSopenharmony_ci plane1[x] = extract_component(co0, co1, co_code); 133cabdff1aSopenharmony_ci } 134cabdff1aSopenharmony_ci plane0 += stride0; 135cabdff1aSopenharmony_ci plane1 += stride1; 136cabdff1aSopenharmony_ci } 137cabdff1aSopenharmony_ci 138cabdff1aSopenharmony_ci return 16; 139cabdff1aSopenharmony_ci} 140cabdff1aSopenharmony_ci 141cabdff1aSopenharmony_cistatic void yao_subblock(uint8_t *dst, uint8_t *yo_indices, 142cabdff1aSopenharmony_ci ptrdiff_t stride, const uint8_t *block) 143cabdff1aSopenharmony_ci{ 144cabdff1aSopenharmony_ci uint8_t yo0 = *(block); 145cabdff1aSopenharmony_ci uint8_t yo1 = *(block + 1); 146cabdff1aSopenharmony_ci int x, y; 147cabdff1aSopenharmony_ci 148cabdff1aSopenharmony_ci decompress_indices(yo_indices, block + 2); 149cabdff1aSopenharmony_ci 150cabdff1aSopenharmony_ci for (y = 0; y < 4; y++) { 151cabdff1aSopenharmony_ci for (x = 0; x < 4; x++) { 152cabdff1aSopenharmony_ci int yo_code = yo_indices[x + y * 4]; 153cabdff1aSopenharmony_ci 154cabdff1aSopenharmony_ci dst[x] = extract_component(yo0, yo1, yo_code); 155cabdff1aSopenharmony_ci } 156cabdff1aSopenharmony_ci dst += stride; 157cabdff1aSopenharmony_ci } 158cabdff1aSopenharmony_ci} 159cabdff1aSopenharmony_ci 160cabdff1aSopenharmony_cistatic int yo_block(uint8_t *dst, ptrdiff_t stride, 161cabdff1aSopenharmony_ci uint8_t *unused0, ptrdiff_t unused1, 162cabdff1aSopenharmony_ci const uint8_t *block) 163cabdff1aSopenharmony_ci{ 164cabdff1aSopenharmony_ci uint8_t yo_indices[16]; 165cabdff1aSopenharmony_ci 166cabdff1aSopenharmony_ci yao_subblock(dst, yo_indices, stride, block); 167cabdff1aSopenharmony_ci yao_subblock(dst + 4, yo_indices, stride, block + 8); 168cabdff1aSopenharmony_ci yao_subblock(dst + 8, yo_indices, stride, block + 16); 169cabdff1aSopenharmony_ci yao_subblock(dst + 12, yo_indices, stride, block + 24); 170cabdff1aSopenharmony_ci 171cabdff1aSopenharmony_ci return 32; 172cabdff1aSopenharmony_ci} 173cabdff1aSopenharmony_ci 174cabdff1aSopenharmony_cistatic int yao_block(uint8_t *plane0, ptrdiff_t stride0, 175cabdff1aSopenharmony_ci uint8_t *plane3, ptrdiff_t stride1, 176cabdff1aSopenharmony_ci const uint8_t *block) 177cabdff1aSopenharmony_ci{ 178cabdff1aSopenharmony_ci uint8_t yo_indices[16]; 179cabdff1aSopenharmony_ci uint8_t a_indices[16]; 180cabdff1aSopenharmony_ci 181cabdff1aSopenharmony_ci yao_subblock(plane0, yo_indices, stride0, block); 182cabdff1aSopenharmony_ci yao_subblock(plane3, a_indices, stride1, block + 8); 183cabdff1aSopenharmony_ci yao_subblock(plane0 + 4, yo_indices, stride0, block + 16); 184cabdff1aSopenharmony_ci yao_subblock(plane3 + 4, a_indices, stride1, block + 24); 185cabdff1aSopenharmony_ci yao_subblock(plane0 + 8, yo_indices, stride0, block + 32); 186cabdff1aSopenharmony_ci yao_subblock(plane3 + 8, a_indices, stride1, block + 40); 187cabdff1aSopenharmony_ci yao_subblock(plane0 + 12, yo_indices, stride0, block + 48); 188cabdff1aSopenharmony_ci yao_subblock(plane3 + 12, a_indices, stride1, block + 56); 189cabdff1aSopenharmony_ci 190cabdff1aSopenharmony_ci return 64; 191cabdff1aSopenharmony_ci} 192cabdff1aSopenharmony_ci 193cabdff1aSopenharmony_cistatic int decompress_texture_thread(AVCodecContext *avctx, void *arg, 194cabdff1aSopenharmony_ci int slice, int thread_nb) 195cabdff1aSopenharmony_ci{ 196cabdff1aSopenharmony_ci DXVContext *ctx = avctx->priv_data; 197cabdff1aSopenharmony_ci AVFrame *frame = arg; 198cabdff1aSopenharmony_ci const uint8_t *d = ctx->tex_data; 199cabdff1aSopenharmony_ci int w_block = avctx->coded_width / ctx->texture_block_w; 200cabdff1aSopenharmony_ci int h_block = avctx->coded_height / ctx->texture_block_h; 201cabdff1aSopenharmony_ci int x, y; 202cabdff1aSopenharmony_ci int start_slice, end_slice; 203cabdff1aSopenharmony_ci 204cabdff1aSopenharmony_ci start_slice = h_block * slice / ctx->slice_count; 205cabdff1aSopenharmony_ci end_slice = h_block * (slice + 1) / ctx->slice_count; 206cabdff1aSopenharmony_ci 207cabdff1aSopenharmony_ci if (ctx->tex_funct) { 208cabdff1aSopenharmony_ci for (y = start_slice; y < end_slice; y++) { 209cabdff1aSopenharmony_ci uint8_t *p = frame->data[0] + y * frame->linesize[0] * ctx->texture_block_h; 210cabdff1aSopenharmony_ci int off = y * w_block; 211cabdff1aSopenharmony_ci for (x = 0; x < w_block; x++) { 212cabdff1aSopenharmony_ci ctx->tex_funct(p + x * 4 * ctx->texture_block_w, frame->linesize[0], 213cabdff1aSopenharmony_ci d + (off + x) * ctx->tex_step); 214cabdff1aSopenharmony_ci } 215cabdff1aSopenharmony_ci } 216cabdff1aSopenharmony_ci } else { 217cabdff1aSopenharmony_ci const uint8_t *c = ctx->ctex_data; 218cabdff1aSopenharmony_ci 219cabdff1aSopenharmony_ci for (y = start_slice; y < end_slice; y++) { 220cabdff1aSopenharmony_ci uint8_t *p0 = frame->data[0] + y * frame->linesize[0] * ctx->texture_block_h; 221cabdff1aSopenharmony_ci uint8_t *p3 = ctx->tex_step != 64 ? NULL : frame->data[3] + y * frame->linesize[3] * ctx->texture_block_h; 222cabdff1aSopenharmony_ci int off = y * w_block; 223cabdff1aSopenharmony_ci for (x = 0; x < w_block; x++) { 224cabdff1aSopenharmony_ci ctx->tex_funct_planar[0](p0 + x * ctx->texture_block_w, frame->linesize[0], 225cabdff1aSopenharmony_ci p3 != NULL ? p3 + x * ctx->texture_block_w : NULL, frame->linesize[3], 226cabdff1aSopenharmony_ci d + (off + x) * ctx->tex_step); 227cabdff1aSopenharmony_ci } 228cabdff1aSopenharmony_ci } 229cabdff1aSopenharmony_ci 230cabdff1aSopenharmony_ci w_block = (avctx->coded_width / 2) / ctx->ctexture_block_w; 231cabdff1aSopenharmony_ci h_block = (avctx->coded_height / 2) / ctx->ctexture_block_h; 232cabdff1aSopenharmony_ci start_slice = h_block * slice / ctx->slice_count; 233cabdff1aSopenharmony_ci end_slice = h_block * (slice + 1) / ctx->slice_count; 234cabdff1aSopenharmony_ci 235cabdff1aSopenharmony_ci for (y = start_slice; y < end_slice; y++) { 236cabdff1aSopenharmony_ci uint8_t *p0 = frame->data[1] + y * frame->linesize[1] * ctx->ctexture_block_h; 237cabdff1aSopenharmony_ci uint8_t *p1 = frame->data[2] + y * frame->linesize[2] * ctx->ctexture_block_h; 238cabdff1aSopenharmony_ci int off = y * w_block; 239cabdff1aSopenharmony_ci for (x = 0; x < w_block; x++) { 240cabdff1aSopenharmony_ci ctx->tex_funct_planar[1](p0 + x * ctx->ctexture_block_w, frame->linesize[1], 241cabdff1aSopenharmony_ci p1 + x * ctx->ctexture_block_w, frame->linesize[2], 242cabdff1aSopenharmony_ci c + (off + x) * ctx->ctex_step); 243cabdff1aSopenharmony_ci } 244cabdff1aSopenharmony_ci } 245cabdff1aSopenharmony_ci } 246cabdff1aSopenharmony_ci 247cabdff1aSopenharmony_ci return 0; 248cabdff1aSopenharmony_ci} 249cabdff1aSopenharmony_ci 250cabdff1aSopenharmony_ci/* This scheme addresses already decoded elements depending on 2-bit status: 251cabdff1aSopenharmony_ci * 0 -> copy new element 252cabdff1aSopenharmony_ci * 1 -> copy one element from position -x 253cabdff1aSopenharmony_ci * 2 -> copy one element from position -(get_byte() + 2) * x 254cabdff1aSopenharmony_ci * 3 -> copy one element from position -(get_16le() + 0x102) * x 255cabdff1aSopenharmony_ci * x is always 2 for dxt1 and 4 for dxt5. */ 256cabdff1aSopenharmony_ci#define CHECKPOINT(x) \ 257cabdff1aSopenharmony_ci do { \ 258cabdff1aSopenharmony_ci if (state == 0) { \ 259cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(gbc) < 4) \ 260cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; \ 261cabdff1aSopenharmony_ci value = bytestream2_get_le32(gbc); \ 262cabdff1aSopenharmony_ci state = 16; \ 263cabdff1aSopenharmony_ci } \ 264cabdff1aSopenharmony_ci op = value & 0x3; \ 265cabdff1aSopenharmony_ci value >>= 2; \ 266cabdff1aSopenharmony_ci state--; \ 267cabdff1aSopenharmony_ci switch (op) { \ 268cabdff1aSopenharmony_ci case 1: \ 269cabdff1aSopenharmony_ci idx = x; \ 270cabdff1aSopenharmony_ci break; \ 271cabdff1aSopenharmony_ci case 2: \ 272cabdff1aSopenharmony_ci idx = (bytestream2_get_byte(gbc) + 2) * x; \ 273cabdff1aSopenharmony_ci if (idx > pos) { \ 274cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "idx %d > %d\n", idx, pos); \ 275cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; \ 276cabdff1aSopenharmony_ci } \ 277cabdff1aSopenharmony_ci break; \ 278cabdff1aSopenharmony_ci case 3: \ 279cabdff1aSopenharmony_ci idx = (bytestream2_get_le16(gbc) + 0x102) * x; \ 280cabdff1aSopenharmony_ci if (idx > pos) { \ 281cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "idx %d > %d\n", idx, pos); \ 282cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; \ 283cabdff1aSopenharmony_ci } \ 284cabdff1aSopenharmony_ci break; \ 285cabdff1aSopenharmony_ci } \ 286cabdff1aSopenharmony_ci } while(0) 287cabdff1aSopenharmony_ci 288cabdff1aSopenharmony_cistatic int dxv_decompress_dxt1(AVCodecContext *avctx) 289cabdff1aSopenharmony_ci{ 290cabdff1aSopenharmony_ci DXVContext *ctx = avctx->priv_data; 291cabdff1aSopenharmony_ci GetByteContext *gbc = &ctx->gbc; 292cabdff1aSopenharmony_ci uint32_t value, prev, op; 293cabdff1aSopenharmony_ci int idx = 0, state = 0; 294cabdff1aSopenharmony_ci int pos = 2; 295cabdff1aSopenharmony_ci 296cabdff1aSopenharmony_ci /* Copy the first two elements */ 297cabdff1aSopenharmony_ci AV_WL32(ctx->tex_data, bytestream2_get_le32(gbc)); 298cabdff1aSopenharmony_ci AV_WL32(ctx->tex_data + 4, bytestream2_get_le32(gbc)); 299cabdff1aSopenharmony_ci 300cabdff1aSopenharmony_ci /* Process input until the whole texture has been filled */ 301cabdff1aSopenharmony_ci while (pos + 2 <= ctx->tex_size / 4) { 302cabdff1aSopenharmony_ci CHECKPOINT(2); 303cabdff1aSopenharmony_ci 304cabdff1aSopenharmony_ci /* Copy two elements from a previous offset or from the input buffer */ 305cabdff1aSopenharmony_ci if (op) { 306cabdff1aSopenharmony_ci prev = AV_RL32(ctx->tex_data + 4 * (pos - idx)); 307cabdff1aSopenharmony_ci AV_WL32(ctx->tex_data + 4 * pos, prev); 308cabdff1aSopenharmony_ci pos++; 309cabdff1aSopenharmony_ci 310cabdff1aSopenharmony_ci prev = AV_RL32(ctx->tex_data + 4 * (pos - idx)); 311cabdff1aSopenharmony_ci AV_WL32(ctx->tex_data + 4 * pos, prev); 312cabdff1aSopenharmony_ci pos++; 313cabdff1aSopenharmony_ci } else { 314cabdff1aSopenharmony_ci CHECKPOINT(2); 315cabdff1aSopenharmony_ci 316cabdff1aSopenharmony_ci if (op) 317cabdff1aSopenharmony_ci prev = AV_RL32(ctx->tex_data + 4 * (pos - idx)); 318cabdff1aSopenharmony_ci else 319cabdff1aSopenharmony_ci prev = bytestream2_get_le32(gbc); 320cabdff1aSopenharmony_ci AV_WL32(ctx->tex_data + 4 * pos, prev); 321cabdff1aSopenharmony_ci pos++; 322cabdff1aSopenharmony_ci 323cabdff1aSopenharmony_ci CHECKPOINT(2); 324cabdff1aSopenharmony_ci 325cabdff1aSopenharmony_ci if (op) 326cabdff1aSopenharmony_ci prev = AV_RL32(ctx->tex_data + 4 * (pos - idx)); 327cabdff1aSopenharmony_ci else 328cabdff1aSopenharmony_ci prev = bytestream2_get_le32(gbc); 329cabdff1aSopenharmony_ci AV_WL32(ctx->tex_data + 4 * pos, prev); 330cabdff1aSopenharmony_ci pos++; 331cabdff1aSopenharmony_ci } 332cabdff1aSopenharmony_ci } 333cabdff1aSopenharmony_ci 334cabdff1aSopenharmony_ci return 0; 335cabdff1aSopenharmony_ci} 336cabdff1aSopenharmony_ci 337cabdff1aSopenharmony_citypedef struct OpcodeTable { 338cabdff1aSopenharmony_ci int16_t next; 339cabdff1aSopenharmony_ci uint8_t val1; 340cabdff1aSopenharmony_ci uint8_t val2; 341cabdff1aSopenharmony_ci} OpcodeTable; 342cabdff1aSopenharmony_ci 343cabdff1aSopenharmony_cistatic int fill_ltable(GetByteContext *gb, uint32_t *table, int *nb_elements) 344cabdff1aSopenharmony_ci{ 345cabdff1aSopenharmony_ci unsigned half = 512, bits = 1023, left = 1024, input, mask; 346cabdff1aSopenharmony_ci int value, counter = 0, rshift = 10, lshift = 30; 347cabdff1aSopenharmony_ci 348cabdff1aSopenharmony_ci mask = bytestream2_get_le32(gb) >> 2; 349cabdff1aSopenharmony_ci while (left) { 350cabdff1aSopenharmony_ci if (counter >= 256) 351cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 352cabdff1aSopenharmony_ci value = bits & mask; 353cabdff1aSopenharmony_ci left -= bits & mask; 354cabdff1aSopenharmony_ci mask >>= rshift; 355cabdff1aSopenharmony_ci lshift -= rshift; 356cabdff1aSopenharmony_ci table[counter++] = value; 357cabdff1aSopenharmony_ci if (lshift < 16) { 358cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(gb) <= 0) 359cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 360cabdff1aSopenharmony_ci 361cabdff1aSopenharmony_ci input = bytestream2_get_le16(gb); 362cabdff1aSopenharmony_ci mask += input << lshift; 363cabdff1aSopenharmony_ci lshift += 16; 364cabdff1aSopenharmony_ci } 365cabdff1aSopenharmony_ci if (left < half) { 366cabdff1aSopenharmony_ci half >>= 1; 367cabdff1aSopenharmony_ci bits >>= 1; 368cabdff1aSopenharmony_ci rshift--; 369cabdff1aSopenharmony_ci } 370cabdff1aSopenharmony_ci } 371cabdff1aSopenharmony_ci 372cabdff1aSopenharmony_ci for (; !table[counter - 1]; counter--) 373cabdff1aSopenharmony_ci if (counter <= 0) 374cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 375cabdff1aSopenharmony_ci 376cabdff1aSopenharmony_ci *nb_elements = counter; 377cabdff1aSopenharmony_ci 378cabdff1aSopenharmony_ci if (counter < 256) 379cabdff1aSopenharmony_ci memset(&table[counter], 0, 4 * (256 - counter)); 380cabdff1aSopenharmony_ci 381cabdff1aSopenharmony_ci if (lshift >= 16) 382cabdff1aSopenharmony_ci bytestream2_seek(gb, -2, SEEK_CUR); 383cabdff1aSopenharmony_ci 384cabdff1aSopenharmony_ci return 0; 385cabdff1aSopenharmony_ci} 386cabdff1aSopenharmony_ci 387cabdff1aSopenharmony_cistatic int fill_optable(unsigned *table0, OpcodeTable *table1, int nb_elements) 388cabdff1aSopenharmony_ci{ 389cabdff1aSopenharmony_ci unsigned table2[256] = { 0 }; 390cabdff1aSopenharmony_ci unsigned x = 0; 391cabdff1aSopenharmony_ci int val0, val1, i, j = 2, k = 0; 392cabdff1aSopenharmony_ci 393cabdff1aSopenharmony_ci table2[0] = table0[0]; 394cabdff1aSopenharmony_ci for (i = 0; i < nb_elements - 1; i++, table2[i] = val0) { 395cabdff1aSopenharmony_ci val0 = table0[i + 1] + table2[i]; 396cabdff1aSopenharmony_ci } 397cabdff1aSopenharmony_ci 398cabdff1aSopenharmony_ci if (!table2[0]) { 399cabdff1aSopenharmony_ci do { 400cabdff1aSopenharmony_ci k++; 401cabdff1aSopenharmony_ci } while (!table2[k]); 402cabdff1aSopenharmony_ci } 403cabdff1aSopenharmony_ci 404cabdff1aSopenharmony_ci j = 2; 405cabdff1aSopenharmony_ci for (i = 1024; i > 0; i--) { 406cabdff1aSopenharmony_ci for (table1[x].val1 = k; k < 256 && j > table2[k]; k++); 407cabdff1aSopenharmony_ci x = (x - 383) & 0x3FF; 408cabdff1aSopenharmony_ci j++; 409cabdff1aSopenharmony_ci } 410cabdff1aSopenharmony_ci 411cabdff1aSopenharmony_ci if (nb_elements > 0) 412cabdff1aSopenharmony_ci memcpy(&table2[0], table0, 4 * nb_elements); 413cabdff1aSopenharmony_ci 414cabdff1aSopenharmony_ci for (i = 0; i < 1024; i++) { 415cabdff1aSopenharmony_ci val0 = table1[i].val1; 416cabdff1aSopenharmony_ci val1 = table2[val0]; 417cabdff1aSopenharmony_ci table2[val0]++; 418cabdff1aSopenharmony_ci x = 31 - ff_clz(val1); 419cabdff1aSopenharmony_ci if (x > 10) 420cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 421cabdff1aSopenharmony_ci table1[i].val2 = 10 - x; 422cabdff1aSopenharmony_ci table1[i].next = (val1 << table1[i].val2) - 1024; 423cabdff1aSopenharmony_ci } 424cabdff1aSopenharmony_ci 425cabdff1aSopenharmony_ci return 0; 426cabdff1aSopenharmony_ci} 427cabdff1aSopenharmony_ci 428cabdff1aSopenharmony_cistatic int get_opcodes(GetByteContext *gb, uint32_t *table, uint8_t *dst, int op_size, int nb_elements) 429cabdff1aSopenharmony_ci{ 430cabdff1aSopenharmony_ci OpcodeTable optable[1024]; 431cabdff1aSopenharmony_ci int sum, x, val, lshift, rshift, ret, i, idx; 432cabdff1aSopenharmony_ci int64_t size_in_bits; 433cabdff1aSopenharmony_ci unsigned endoffset, newoffset, offset; 434cabdff1aSopenharmony_ci unsigned next; 435cabdff1aSopenharmony_ci uint8_t *src = (uint8_t *)gb->buffer; 436cabdff1aSopenharmony_ci 437cabdff1aSopenharmony_ci ret = fill_optable(table, optable, nb_elements); 438cabdff1aSopenharmony_ci if (ret < 0) 439cabdff1aSopenharmony_ci return ret; 440cabdff1aSopenharmony_ci 441cabdff1aSopenharmony_ci size_in_bits = bytestream2_get_le32(gb); 442cabdff1aSopenharmony_ci endoffset = ((size_in_bits + 7) >> 3) - 4; 443cabdff1aSopenharmony_ci if (endoffset <= 0 || bytestream2_get_bytes_left(gb) < endoffset) 444cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 445cabdff1aSopenharmony_ci 446cabdff1aSopenharmony_ci offset = endoffset; 447cabdff1aSopenharmony_ci next = AV_RL32(src + endoffset); 448cabdff1aSopenharmony_ci rshift = (((size_in_bits & 0xFF) - 1) & 7) + 15; 449cabdff1aSopenharmony_ci lshift = 32 - rshift; 450cabdff1aSopenharmony_ci idx = (next >> rshift) & 0x3FF; 451cabdff1aSopenharmony_ci for (i = 0; i < op_size; i++) { 452cabdff1aSopenharmony_ci dst[i] = optable[idx].val1; 453cabdff1aSopenharmony_ci val = optable[idx].val2; 454cabdff1aSopenharmony_ci sum = val + lshift; 455cabdff1aSopenharmony_ci x = (next << lshift) >> 1 >> (31 - val); 456cabdff1aSopenharmony_ci newoffset = offset - (sum >> 3); 457cabdff1aSopenharmony_ci lshift = sum & 7; 458cabdff1aSopenharmony_ci idx = x + optable[idx].next; 459cabdff1aSopenharmony_ci offset = newoffset; 460cabdff1aSopenharmony_ci if (offset > endoffset) 461cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 462cabdff1aSopenharmony_ci next = AV_RL32(src + offset); 463cabdff1aSopenharmony_ci } 464cabdff1aSopenharmony_ci 465cabdff1aSopenharmony_ci bytestream2_skip(gb, (size_in_bits + 7 >> 3) - 4); 466cabdff1aSopenharmony_ci 467cabdff1aSopenharmony_ci return 0; 468cabdff1aSopenharmony_ci} 469cabdff1aSopenharmony_ci 470cabdff1aSopenharmony_cistatic int dxv_decompress_opcodes(GetByteContext *gb, void *dstp, size_t op_size) 471cabdff1aSopenharmony_ci{ 472cabdff1aSopenharmony_ci int pos = bytestream2_tell(gb); 473cabdff1aSopenharmony_ci int flag = bytestream2_peek_byte(gb); 474cabdff1aSopenharmony_ci 475cabdff1aSopenharmony_ci if ((flag & 3) == 0) { 476cabdff1aSopenharmony_ci bytestream2_skip(gb, 1); 477cabdff1aSopenharmony_ci bytestream2_get_buffer(gb, dstp, op_size); 478cabdff1aSopenharmony_ci } else if ((flag & 3) == 1) { 479cabdff1aSopenharmony_ci bytestream2_skip(gb, 1); 480cabdff1aSopenharmony_ci memset(dstp, bytestream2_get_byte(gb), op_size); 481cabdff1aSopenharmony_ci } else { 482cabdff1aSopenharmony_ci uint32_t table[256]; 483cabdff1aSopenharmony_ci int ret, elements = 0; 484cabdff1aSopenharmony_ci 485cabdff1aSopenharmony_ci ret = fill_ltable(gb, table, &elements); 486cabdff1aSopenharmony_ci if (ret < 0) 487cabdff1aSopenharmony_ci return ret; 488cabdff1aSopenharmony_ci ret = get_opcodes(gb, table, dstp, op_size, elements); 489cabdff1aSopenharmony_ci if (ret < 0) 490cabdff1aSopenharmony_ci return ret; 491cabdff1aSopenharmony_ci } 492cabdff1aSopenharmony_ci return bytestream2_tell(gb) - pos; 493cabdff1aSopenharmony_ci} 494cabdff1aSopenharmony_ci 495cabdff1aSopenharmony_cistatic int dxv_decompress_cgo(DXVContext *ctx, GetByteContext *gb, 496cabdff1aSopenharmony_ci uint8_t *tex_data, int tex_size, 497cabdff1aSopenharmony_ci uint8_t *op_data, int *oindex, 498cabdff1aSopenharmony_ci int op_size, 499cabdff1aSopenharmony_ci uint8_t **dstp, int *statep, 500cabdff1aSopenharmony_ci uint8_t **tab0, uint8_t **tab1, 501cabdff1aSopenharmony_ci int offset) 502cabdff1aSopenharmony_ci{ 503cabdff1aSopenharmony_ci uint8_t *dst = *dstp; 504cabdff1aSopenharmony_ci uint8_t *tptr0, *tptr1, *tptr3; 505cabdff1aSopenharmony_ci int oi = *oindex; 506cabdff1aSopenharmony_ci int state = *statep; 507cabdff1aSopenharmony_ci int opcode, v, vv; 508cabdff1aSopenharmony_ci 509cabdff1aSopenharmony_ci if (state <= 0) { 510cabdff1aSopenharmony_ci if (oi >= op_size) 511cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 512cabdff1aSopenharmony_ci opcode = op_data[oi++]; 513cabdff1aSopenharmony_ci if (!opcode) { 514cabdff1aSopenharmony_ci v = bytestream2_get_byte(gb); 515cabdff1aSopenharmony_ci if (v == 255) { 516cabdff1aSopenharmony_ci do { 517cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(gb) <= 0) 518cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 519cabdff1aSopenharmony_ci opcode = bytestream2_get_le16(gb); 520cabdff1aSopenharmony_ci v += opcode; 521cabdff1aSopenharmony_ci } while (opcode == 0xFFFF); 522cabdff1aSopenharmony_ci } 523cabdff1aSopenharmony_ci AV_WL32(dst, AV_RL32(dst - (8 + offset))); 524cabdff1aSopenharmony_ci AV_WL32(dst + 4, AV_RL32(dst - (4 + offset))); 525cabdff1aSopenharmony_ci state = v + 4; 526cabdff1aSopenharmony_ci goto done; 527cabdff1aSopenharmony_ci } 528cabdff1aSopenharmony_ci 529cabdff1aSopenharmony_ci switch (opcode) { 530cabdff1aSopenharmony_ci case 1: 531cabdff1aSopenharmony_ci AV_WL32(dst, AV_RL32(dst - (8 + offset))); 532cabdff1aSopenharmony_ci AV_WL32(dst + 4, AV_RL32(dst - (4 + offset))); 533cabdff1aSopenharmony_ci break; 534cabdff1aSopenharmony_ci case 2: 535cabdff1aSopenharmony_ci vv = (8 + offset) * (bytestream2_get_le16(gb) + 1); 536cabdff1aSopenharmony_ci if (vv < 0 || vv > dst - tex_data) 537cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 538cabdff1aSopenharmony_ci tptr0 = dst - vv; 539cabdff1aSopenharmony_ci v = AV_RL32(tptr0); 540cabdff1aSopenharmony_ci AV_WL32(dst, AV_RL32(tptr0)); 541cabdff1aSopenharmony_ci AV_WL32(dst + 4, AV_RL32(tptr0 + 4)); 542cabdff1aSopenharmony_ci tab0[0x9E3779B1 * (uint16_t)v >> 24] = dst; 543cabdff1aSopenharmony_ci tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2; 544cabdff1aSopenharmony_ci break; 545cabdff1aSopenharmony_ci case 3: 546cabdff1aSopenharmony_ci AV_WL32(dst, bytestream2_get_le32(gb)); 547cabdff1aSopenharmony_ci AV_WL32(dst + 4, bytestream2_get_le32(gb)); 548cabdff1aSopenharmony_ci tab0[0x9E3779B1 * AV_RL16(dst) >> 24] = dst; 549cabdff1aSopenharmony_ci tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2; 550cabdff1aSopenharmony_ci break; 551cabdff1aSopenharmony_ci case 4: 552cabdff1aSopenharmony_ci tptr3 = tab1[bytestream2_get_byte(gb)]; 553cabdff1aSopenharmony_ci if (!tptr3) 554cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 555cabdff1aSopenharmony_ci AV_WL16(dst, bytestream2_get_le16(gb)); 556cabdff1aSopenharmony_ci AV_WL16(dst + 2, AV_RL16(tptr3)); 557cabdff1aSopenharmony_ci dst[4] = tptr3[2]; 558cabdff1aSopenharmony_ci AV_WL16(dst + 5, bytestream2_get_le16(gb)); 559cabdff1aSopenharmony_ci dst[7] = bytestream2_get_byte(gb); 560cabdff1aSopenharmony_ci tab0[0x9E3779B1 * AV_RL16(dst) >> 24] = dst; 561cabdff1aSopenharmony_ci break; 562cabdff1aSopenharmony_ci case 5: 563cabdff1aSopenharmony_ci tptr3 = tab1[bytestream2_get_byte(gb)]; 564cabdff1aSopenharmony_ci if (!tptr3) 565cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 566cabdff1aSopenharmony_ci AV_WL16(dst, bytestream2_get_le16(gb)); 567cabdff1aSopenharmony_ci AV_WL16(dst + 2, bytestream2_get_le16(gb)); 568cabdff1aSopenharmony_ci dst[4] = bytestream2_get_byte(gb); 569cabdff1aSopenharmony_ci AV_WL16(dst + 5, AV_RL16(tptr3)); 570cabdff1aSopenharmony_ci dst[7] = tptr3[2]; 571cabdff1aSopenharmony_ci tab0[0x9E3779B1 * AV_RL16(dst) >> 24] = dst; 572cabdff1aSopenharmony_ci tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2; 573cabdff1aSopenharmony_ci break; 574cabdff1aSopenharmony_ci case 6: 575cabdff1aSopenharmony_ci tptr0 = tab1[bytestream2_get_byte(gb)]; 576cabdff1aSopenharmony_ci if (!tptr0) 577cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 578cabdff1aSopenharmony_ci tptr1 = tab1[bytestream2_get_byte(gb)]; 579cabdff1aSopenharmony_ci if (!tptr1) 580cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 581cabdff1aSopenharmony_ci AV_WL16(dst, bytestream2_get_le16(gb)); 582cabdff1aSopenharmony_ci AV_WL16(dst + 2, AV_RL16(tptr0)); 583cabdff1aSopenharmony_ci dst[4] = tptr0[2]; 584cabdff1aSopenharmony_ci AV_WL16(dst + 5, AV_RL16(tptr1)); 585cabdff1aSopenharmony_ci dst[7] = tptr1[2]; 586cabdff1aSopenharmony_ci tab0[0x9E3779B1 * AV_RL16(dst) >> 24] = dst; 587cabdff1aSopenharmony_ci break; 588cabdff1aSopenharmony_ci case 7: 589cabdff1aSopenharmony_ci v = (8 + offset) * (bytestream2_get_le16(gb) + 1); 590cabdff1aSopenharmony_ci if (v < 0 || v > dst - tex_data) 591cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 592cabdff1aSopenharmony_ci tptr0 = dst - v; 593cabdff1aSopenharmony_ci AV_WL16(dst, bytestream2_get_le16(gb)); 594cabdff1aSopenharmony_ci AV_WL16(dst + 2, AV_RL16(tptr0 + 2)); 595cabdff1aSopenharmony_ci AV_WL32(dst + 4, AV_RL32(tptr0 + 4)); 596cabdff1aSopenharmony_ci tab0[0x9E3779B1 * AV_RL16(dst) >> 24] = dst; 597cabdff1aSopenharmony_ci tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2; 598cabdff1aSopenharmony_ci break; 599cabdff1aSopenharmony_ci case 8: 600cabdff1aSopenharmony_ci tptr1 = tab0[bytestream2_get_byte(gb)]; 601cabdff1aSopenharmony_ci if (!tptr1) 602cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 603cabdff1aSopenharmony_ci AV_WL16(dst, AV_RL16(tptr1)); 604cabdff1aSopenharmony_ci AV_WL16(dst + 2, bytestream2_get_le16(gb)); 605cabdff1aSopenharmony_ci AV_WL32(dst + 4, bytestream2_get_le32(gb)); 606cabdff1aSopenharmony_ci tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2; 607cabdff1aSopenharmony_ci break; 608cabdff1aSopenharmony_ci case 9: 609cabdff1aSopenharmony_ci tptr1 = tab0[bytestream2_get_byte(gb)]; 610cabdff1aSopenharmony_ci if (!tptr1) 611cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 612cabdff1aSopenharmony_ci tptr3 = tab1[bytestream2_get_byte(gb)]; 613cabdff1aSopenharmony_ci if (!tptr3) 614cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 615cabdff1aSopenharmony_ci AV_WL16(dst, AV_RL16(tptr1)); 616cabdff1aSopenharmony_ci AV_WL16(dst + 2, AV_RL16(tptr3)); 617cabdff1aSopenharmony_ci dst[4] = tptr3[2]; 618cabdff1aSopenharmony_ci AV_WL16(dst + 5, bytestream2_get_le16(gb)); 619cabdff1aSopenharmony_ci dst[7] = bytestream2_get_byte(gb); 620cabdff1aSopenharmony_ci tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2; 621cabdff1aSopenharmony_ci break; 622cabdff1aSopenharmony_ci case 10: 623cabdff1aSopenharmony_ci tptr1 = tab0[bytestream2_get_byte(gb)]; 624cabdff1aSopenharmony_ci if (!tptr1) 625cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 626cabdff1aSopenharmony_ci tptr3 = tab1[bytestream2_get_byte(gb)]; 627cabdff1aSopenharmony_ci if (!tptr3) 628cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 629cabdff1aSopenharmony_ci AV_WL16(dst, AV_RL16(tptr1)); 630cabdff1aSopenharmony_ci AV_WL16(dst + 2, bytestream2_get_le16(gb)); 631cabdff1aSopenharmony_ci dst[4] = bytestream2_get_byte(gb); 632cabdff1aSopenharmony_ci AV_WL16(dst + 5, AV_RL16(tptr3)); 633cabdff1aSopenharmony_ci dst[7] = tptr3[2]; 634cabdff1aSopenharmony_ci tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2; 635cabdff1aSopenharmony_ci break; 636cabdff1aSopenharmony_ci case 11: 637cabdff1aSopenharmony_ci tptr0 = tab0[bytestream2_get_byte(gb)]; 638cabdff1aSopenharmony_ci if (!tptr0) 639cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 640cabdff1aSopenharmony_ci tptr3 = tab1[bytestream2_get_byte(gb)]; 641cabdff1aSopenharmony_ci if (!tptr3) 642cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 643cabdff1aSopenharmony_ci tptr1 = tab1[bytestream2_get_byte(gb)]; 644cabdff1aSopenharmony_ci if (!tptr1) 645cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 646cabdff1aSopenharmony_ci AV_WL16(dst, AV_RL16(tptr0)); 647cabdff1aSopenharmony_ci AV_WL16(dst + 2, AV_RL16(tptr3)); 648cabdff1aSopenharmony_ci dst[4] = tptr3[2]; 649cabdff1aSopenharmony_ci AV_WL16(dst + 5, AV_RL16(tptr1)); 650cabdff1aSopenharmony_ci dst[7] = tptr1[2]; 651cabdff1aSopenharmony_ci break; 652cabdff1aSopenharmony_ci case 12: 653cabdff1aSopenharmony_ci tptr1 = tab0[bytestream2_get_byte(gb)]; 654cabdff1aSopenharmony_ci if (!tptr1) 655cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 656cabdff1aSopenharmony_ci v = (8 + offset) * (bytestream2_get_le16(gb) + 1); 657cabdff1aSopenharmony_ci if (v < 0 || v > dst - tex_data) 658cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 659cabdff1aSopenharmony_ci tptr0 = dst - v; 660cabdff1aSopenharmony_ci AV_WL16(dst, AV_RL16(tptr1)); 661cabdff1aSopenharmony_ci AV_WL16(dst + 2, AV_RL16(tptr0 + 2)); 662cabdff1aSopenharmony_ci AV_WL32(dst + 4, AV_RL32(tptr0 + 4)); 663cabdff1aSopenharmony_ci tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2; 664cabdff1aSopenharmony_ci break; 665cabdff1aSopenharmony_ci case 13: 666cabdff1aSopenharmony_ci AV_WL16(dst, AV_RL16(dst - (8 + offset))); 667cabdff1aSopenharmony_ci AV_WL16(dst + 2, bytestream2_get_le16(gb)); 668cabdff1aSopenharmony_ci AV_WL32(dst + 4, bytestream2_get_le32(gb)); 669cabdff1aSopenharmony_ci tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2; 670cabdff1aSopenharmony_ci break; 671cabdff1aSopenharmony_ci case 14: 672cabdff1aSopenharmony_ci tptr3 = tab1[bytestream2_get_byte(gb)]; 673cabdff1aSopenharmony_ci if (!tptr3) 674cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 675cabdff1aSopenharmony_ci AV_WL16(dst, AV_RL16(dst - (8 + offset))); 676cabdff1aSopenharmony_ci AV_WL16(dst + 2, AV_RL16(tptr3)); 677cabdff1aSopenharmony_ci dst[4] = tptr3[2]; 678cabdff1aSopenharmony_ci AV_WL16(dst + 5, bytestream2_get_le16(gb)); 679cabdff1aSopenharmony_ci dst[7] = bytestream2_get_byte(gb); 680cabdff1aSopenharmony_ci tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2; 681cabdff1aSopenharmony_ci break; 682cabdff1aSopenharmony_ci case 15: 683cabdff1aSopenharmony_ci tptr3 = tab1[bytestream2_get_byte(gb)]; 684cabdff1aSopenharmony_ci if (!tptr3) 685cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 686cabdff1aSopenharmony_ci AV_WL16(dst, AV_RL16(dst - (8 + offset))); 687cabdff1aSopenharmony_ci AV_WL16(dst + 2, bytestream2_get_le16(gb)); 688cabdff1aSopenharmony_ci dst[4] = bytestream2_get_byte(gb); 689cabdff1aSopenharmony_ci AV_WL16(dst + 5, AV_RL16(tptr3)); 690cabdff1aSopenharmony_ci dst[7] = tptr3[2]; 691cabdff1aSopenharmony_ci tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2; 692cabdff1aSopenharmony_ci break; 693cabdff1aSopenharmony_ci case 16: 694cabdff1aSopenharmony_ci tptr3 = tab1[bytestream2_get_byte(gb)]; 695cabdff1aSopenharmony_ci if (!tptr3) 696cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 697cabdff1aSopenharmony_ci tptr1 = tab1[bytestream2_get_byte(gb)]; 698cabdff1aSopenharmony_ci if (!tptr1) 699cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 700cabdff1aSopenharmony_ci AV_WL16(dst, AV_RL16(dst - (8 + offset))); 701cabdff1aSopenharmony_ci AV_WL16(dst + 2, AV_RL16(tptr3)); 702cabdff1aSopenharmony_ci dst[4] = tptr3[2]; 703cabdff1aSopenharmony_ci AV_WL16(dst + 5, AV_RL16(tptr1)); 704cabdff1aSopenharmony_ci dst[7] = tptr1[2]; 705cabdff1aSopenharmony_ci break; 706cabdff1aSopenharmony_ci case 17: 707cabdff1aSopenharmony_ci v = (8 + offset) * (bytestream2_get_le16(gb) + 1); 708cabdff1aSopenharmony_ci if (v < 0 || v > dst - tex_data) 709cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 710cabdff1aSopenharmony_ci AV_WL16(dst, AV_RL16(dst - (8 + offset))); 711cabdff1aSopenharmony_ci AV_WL16(dst + 2, AV_RL16(&dst[-v + 2])); 712cabdff1aSopenharmony_ci AV_WL32(dst + 4, AV_RL32(&dst[-v + 4])); 713cabdff1aSopenharmony_ci tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2; 714cabdff1aSopenharmony_ci break; 715cabdff1aSopenharmony_ci default: 716cabdff1aSopenharmony_ci break; 717cabdff1aSopenharmony_ci } 718cabdff1aSopenharmony_ci } else { 719cabdff1aSopenharmony_cidone: 720cabdff1aSopenharmony_ci AV_WL32(dst, AV_RL32(dst - (8 + offset))); 721cabdff1aSopenharmony_ci AV_WL32(dst + 4, AV_RL32(dst - (4 + offset))); 722cabdff1aSopenharmony_ci state--; 723cabdff1aSopenharmony_ci } 724cabdff1aSopenharmony_ci if (dst - tex_data + 8 > tex_size) 725cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 726cabdff1aSopenharmony_ci dst += 8; 727cabdff1aSopenharmony_ci 728cabdff1aSopenharmony_ci *oindex = oi; 729cabdff1aSopenharmony_ci *dstp = dst; 730cabdff1aSopenharmony_ci *statep = state; 731cabdff1aSopenharmony_ci 732cabdff1aSopenharmony_ci return 0; 733cabdff1aSopenharmony_ci} 734cabdff1aSopenharmony_ci 735cabdff1aSopenharmony_cistatic int dxv_decompress_cocg(DXVContext *ctx, GetByteContext *gb, 736cabdff1aSopenharmony_ci uint8_t *tex_data, int tex_size, 737cabdff1aSopenharmony_ci uint8_t *op_data0, uint8_t *op_data1, 738cabdff1aSopenharmony_ci int max_op_size0, int max_op_size1) 739cabdff1aSopenharmony_ci{ 740cabdff1aSopenharmony_ci uint8_t *dst, *tab2[256] = { 0 }, *tab0[256] = { 0 }, *tab3[256] = { 0 }, *tab1[256] = { 0 }; 741cabdff1aSopenharmony_ci int op_offset = bytestream2_get_le32(gb); 742cabdff1aSopenharmony_ci unsigned op_size0 = bytestream2_get_le32(gb); 743cabdff1aSopenharmony_ci unsigned op_size1 = bytestream2_get_le32(gb); 744cabdff1aSopenharmony_ci int data_start = bytestream2_tell(gb); 745cabdff1aSopenharmony_ci int skip0, skip1, oi0 = 0, oi1 = 0; 746cabdff1aSopenharmony_ci int ret, state0 = 0, state1 = 0; 747cabdff1aSopenharmony_ci 748cabdff1aSopenharmony_ci if (op_offset < 12 || op_offset - 12 > bytestream2_get_bytes_left(gb)) 749cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 750cabdff1aSopenharmony_ci 751cabdff1aSopenharmony_ci dst = tex_data; 752cabdff1aSopenharmony_ci bytestream2_skip(gb, op_offset - 12); 753cabdff1aSopenharmony_ci if (op_size0 > max_op_size0) 754cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 755cabdff1aSopenharmony_ci skip0 = dxv_decompress_opcodes(gb, op_data0, op_size0); 756cabdff1aSopenharmony_ci if (skip0 < 0) 757cabdff1aSopenharmony_ci return skip0; 758cabdff1aSopenharmony_ci if (op_size1 > max_op_size1) 759cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 760cabdff1aSopenharmony_ci skip1 = dxv_decompress_opcodes(gb, op_data1, op_size1); 761cabdff1aSopenharmony_ci if (skip1 < 0) 762cabdff1aSopenharmony_ci return skip1; 763cabdff1aSopenharmony_ci bytestream2_seek(gb, data_start, SEEK_SET); 764cabdff1aSopenharmony_ci 765cabdff1aSopenharmony_ci AV_WL32(dst, bytestream2_get_le32(gb)); 766cabdff1aSopenharmony_ci AV_WL32(dst + 4, bytestream2_get_le32(gb)); 767cabdff1aSopenharmony_ci AV_WL32(dst + 8, bytestream2_get_le32(gb)); 768cabdff1aSopenharmony_ci AV_WL32(dst + 12, bytestream2_get_le32(gb)); 769cabdff1aSopenharmony_ci 770cabdff1aSopenharmony_ci tab0[0x9E3779B1 * AV_RL16(dst) >> 24] = dst; 771cabdff1aSopenharmony_ci tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFF) >> 24] = dst + 2; 772cabdff1aSopenharmony_ci tab2[0x9E3779B1 * AV_RL16(dst + 8) >> 24] = dst + 8; 773cabdff1aSopenharmony_ci tab3[0x9E3779B1 * (AV_RL32(dst + 10) & 0xFFFFFF) >> 24] = dst + 10; 774cabdff1aSopenharmony_ci dst += 16; 775cabdff1aSopenharmony_ci while (dst + 10 < tex_data + tex_size) { 776cabdff1aSopenharmony_ci ret = dxv_decompress_cgo(ctx, gb, tex_data, tex_size, op_data0, &oi0, op_size0, 777cabdff1aSopenharmony_ci &dst, &state0, tab0, tab1, 8); 778cabdff1aSopenharmony_ci if (ret < 0) 779cabdff1aSopenharmony_ci return ret; 780cabdff1aSopenharmony_ci ret = dxv_decompress_cgo(ctx, gb, tex_data, tex_size, op_data1, &oi1, op_size1, 781cabdff1aSopenharmony_ci &dst, &state1, tab2, tab3, 8); 782cabdff1aSopenharmony_ci if (ret < 0) 783cabdff1aSopenharmony_ci return ret; 784cabdff1aSopenharmony_ci } 785cabdff1aSopenharmony_ci 786cabdff1aSopenharmony_ci bytestream2_seek(gb, data_start - 12 + op_offset + skip0 + skip1, SEEK_SET); 787cabdff1aSopenharmony_ci 788cabdff1aSopenharmony_ci return 0; 789cabdff1aSopenharmony_ci} 790cabdff1aSopenharmony_ci 791cabdff1aSopenharmony_cistatic int dxv_decompress_yo(DXVContext *ctx, GetByteContext *gb, 792cabdff1aSopenharmony_ci uint8_t *tex_data, int tex_size, 793cabdff1aSopenharmony_ci uint8_t *op_data, int max_op_size) 794cabdff1aSopenharmony_ci{ 795cabdff1aSopenharmony_ci int op_offset = bytestream2_get_le32(gb); 796cabdff1aSopenharmony_ci unsigned op_size = bytestream2_get_le32(gb); 797cabdff1aSopenharmony_ci int data_start = bytestream2_tell(gb); 798cabdff1aSopenharmony_ci uint8_t *dst, *table0[256] = { 0 }, *table1[256] = { 0 }; 799cabdff1aSopenharmony_ci int ret, state = 0, skip, oi = 0, v, vv; 800cabdff1aSopenharmony_ci 801cabdff1aSopenharmony_ci if (op_offset < 8 || op_offset - 8 > bytestream2_get_bytes_left(gb)) 802cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 803cabdff1aSopenharmony_ci 804cabdff1aSopenharmony_ci dst = tex_data; 805cabdff1aSopenharmony_ci bytestream2_skip(gb, op_offset - 8); 806cabdff1aSopenharmony_ci if (op_size > max_op_size) 807cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 808cabdff1aSopenharmony_ci skip = dxv_decompress_opcodes(gb, op_data, op_size); 809cabdff1aSopenharmony_ci if (skip < 0) 810cabdff1aSopenharmony_ci return skip; 811cabdff1aSopenharmony_ci bytestream2_seek(gb, data_start, SEEK_SET); 812cabdff1aSopenharmony_ci 813cabdff1aSopenharmony_ci v = bytestream2_get_le32(gb); 814cabdff1aSopenharmony_ci AV_WL32(dst, v); 815cabdff1aSopenharmony_ci vv = bytestream2_get_le32(gb); 816cabdff1aSopenharmony_ci table0[0x9E3779B1 * (uint16_t)v >> 24] = dst; 817cabdff1aSopenharmony_ci AV_WL32(dst + 4, vv); 818cabdff1aSopenharmony_ci table1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFF) >> 24] = dst + 2; 819cabdff1aSopenharmony_ci dst += 8; 820cabdff1aSopenharmony_ci 821cabdff1aSopenharmony_ci while (dst < tex_data + tex_size) { 822cabdff1aSopenharmony_ci ret = dxv_decompress_cgo(ctx, gb, tex_data, tex_size, op_data, &oi, op_size, 823cabdff1aSopenharmony_ci &dst, &state, table0, table1, 0); 824cabdff1aSopenharmony_ci if (ret < 0) 825cabdff1aSopenharmony_ci return ret; 826cabdff1aSopenharmony_ci } 827cabdff1aSopenharmony_ci 828cabdff1aSopenharmony_ci bytestream2_seek(gb, data_start + op_offset + skip - 8, SEEK_SET); 829cabdff1aSopenharmony_ci 830cabdff1aSopenharmony_ci return 0; 831cabdff1aSopenharmony_ci} 832cabdff1aSopenharmony_ci 833cabdff1aSopenharmony_cistatic int dxv_decompress_ycg6(AVCodecContext *avctx) 834cabdff1aSopenharmony_ci{ 835cabdff1aSopenharmony_ci DXVContext *ctx = avctx->priv_data; 836cabdff1aSopenharmony_ci GetByteContext *gb = &ctx->gbc; 837cabdff1aSopenharmony_ci int ret; 838cabdff1aSopenharmony_ci 839cabdff1aSopenharmony_ci ret = dxv_decompress_yo(ctx, gb, ctx->tex_data, ctx->tex_size, 840cabdff1aSopenharmony_ci ctx->op_data[0], ctx->op_size[0]); 841cabdff1aSopenharmony_ci if (ret < 0) 842cabdff1aSopenharmony_ci return ret; 843cabdff1aSopenharmony_ci 844cabdff1aSopenharmony_ci return dxv_decompress_cocg(ctx, gb, ctx->ctex_data, ctx->ctex_size, 845cabdff1aSopenharmony_ci ctx->op_data[1], ctx->op_data[2], 846cabdff1aSopenharmony_ci ctx->op_size[1], ctx->op_size[2]); 847cabdff1aSopenharmony_ci} 848cabdff1aSopenharmony_ci 849cabdff1aSopenharmony_cistatic int dxv_decompress_yg10(AVCodecContext *avctx) 850cabdff1aSopenharmony_ci{ 851cabdff1aSopenharmony_ci DXVContext *ctx = avctx->priv_data; 852cabdff1aSopenharmony_ci GetByteContext *gb = &ctx->gbc; 853cabdff1aSopenharmony_ci int ret; 854cabdff1aSopenharmony_ci 855cabdff1aSopenharmony_ci ret = dxv_decompress_cocg(ctx, gb, ctx->tex_data, ctx->tex_size, 856cabdff1aSopenharmony_ci ctx->op_data[0], ctx->op_data[3], 857cabdff1aSopenharmony_ci ctx->op_size[0], ctx->op_size[3]); 858cabdff1aSopenharmony_ci if (ret < 0) 859cabdff1aSopenharmony_ci return ret; 860cabdff1aSopenharmony_ci 861cabdff1aSopenharmony_ci return dxv_decompress_cocg(ctx, gb, ctx->ctex_data, ctx->ctex_size, 862cabdff1aSopenharmony_ci ctx->op_data[1], ctx->op_data[2], 863cabdff1aSopenharmony_ci ctx->op_size[1], ctx->op_size[2]); 864cabdff1aSopenharmony_ci} 865cabdff1aSopenharmony_ci 866cabdff1aSopenharmony_cistatic int dxv_decompress_dxt5(AVCodecContext *avctx) 867cabdff1aSopenharmony_ci{ 868cabdff1aSopenharmony_ci DXVContext *ctx = avctx->priv_data; 869cabdff1aSopenharmony_ci GetByteContext *gbc = &ctx->gbc; 870cabdff1aSopenharmony_ci uint32_t value, op, prev; 871cabdff1aSopenharmony_ci int idx, state = 0; 872cabdff1aSopenharmony_ci int pos = 4; 873cabdff1aSopenharmony_ci int run = 0; 874cabdff1aSopenharmony_ci int probe, check; 875cabdff1aSopenharmony_ci 876cabdff1aSopenharmony_ci /* Copy the first four elements */ 877cabdff1aSopenharmony_ci AV_WL32(ctx->tex_data + 0, bytestream2_get_le32(gbc)); 878cabdff1aSopenharmony_ci AV_WL32(ctx->tex_data + 4, bytestream2_get_le32(gbc)); 879cabdff1aSopenharmony_ci AV_WL32(ctx->tex_data + 8, bytestream2_get_le32(gbc)); 880cabdff1aSopenharmony_ci AV_WL32(ctx->tex_data + 12, bytestream2_get_le32(gbc)); 881cabdff1aSopenharmony_ci 882cabdff1aSopenharmony_ci /* Process input until the whole texture has been filled */ 883cabdff1aSopenharmony_ci while (pos + 2 <= ctx->tex_size / 4) { 884cabdff1aSopenharmony_ci if (run) { 885cabdff1aSopenharmony_ci run--; 886cabdff1aSopenharmony_ci 887cabdff1aSopenharmony_ci prev = AV_RL32(ctx->tex_data + 4 * (pos - 4)); 888cabdff1aSopenharmony_ci AV_WL32(ctx->tex_data + 4 * pos, prev); 889cabdff1aSopenharmony_ci pos++; 890cabdff1aSopenharmony_ci prev = AV_RL32(ctx->tex_data + 4 * (pos - 4)); 891cabdff1aSopenharmony_ci AV_WL32(ctx->tex_data + 4 * pos, prev); 892cabdff1aSopenharmony_ci pos++; 893cabdff1aSopenharmony_ci } else { 894cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(gbc) < 1) 895cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 896cabdff1aSopenharmony_ci if (state == 0) { 897cabdff1aSopenharmony_ci value = bytestream2_get_le32(gbc); 898cabdff1aSopenharmony_ci state = 16; 899cabdff1aSopenharmony_ci } 900cabdff1aSopenharmony_ci op = value & 0x3; 901cabdff1aSopenharmony_ci value >>= 2; 902cabdff1aSopenharmony_ci state--; 903cabdff1aSopenharmony_ci 904cabdff1aSopenharmony_ci switch (op) { 905cabdff1aSopenharmony_ci case 0: 906cabdff1aSopenharmony_ci /* Long copy */ 907cabdff1aSopenharmony_ci check = bytestream2_get_byte(gbc) + 1; 908cabdff1aSopenharmony_ci if (check == 256) { 909cabdff1aSopenharmony_ci do { 910cabdff1aSopenharmony_ci probe = bytestream2_get_le16(gbc); 911cabdff1aSopenharmony_ci check += probe; 912cabdff1aSopenharmony_ci } while (probe == 0xFFFF); 913cabdff1aSopenharmony_ci } 914cabdff1aSopenharmony_ci while (check && pos + 4 <= ctx->tex_size / 4) { 915cabdff1aSopenharmony_ci prev = AV_RL32(ctx->tex_data + 4 * (pos - 4)); 916cabdff1aSopenharmony_ci AV_WL32(ctx->tex_data + 4 * pos, prev); 917cabdff1aSopenharmony_ci pos++; 918cabdff1aSopenharmony_ci 919cabdff1aSopenharmony_ci prev = AV_RL32(ctx->tex_data + 4 * (pos - 4)); 920cabdff1aSopenharmony_ci AV_WL32(ctx->tex_data + 4 * pos, prev); 921cabdff1aSopenharmony_ci pos++; 922cabdff1aSopenharmony_ci 923cabdff1aSopenharmony_ci prev = AV_RL32(ctx->tex_data + 4 * (pos - 4)); 924cabdff1aSopenharmony_ci AV_WL32(ctx->tex_data + 4 * pos, prev); 925cabdff1aSopenharmony_ci pos++; 926cabdff1aSopenharmony_ci 927cabdff1aSopenharmony_ci prev = AV_RL32(ctx->tex_data + 4 * (pos - 4)); 928cabdff1aSopenharmony_ci AV_WL32(ctx->tex_data + 4 * pos, prev); 929cabdff1aSopenharmony_ci pos++; 930cabdff1aSopenharmony_ci 931cabdff1aSopenharmony_ci check--; 932cabdff1aSopenharmony_ci } 933cabdff1aSopenharmony_ci 934cabdff1aSopenharmony_ci /* Restart (or exit) the loop */ 935cabdff1aSopenharmony_ci continue; 936cabdff1aSopenharmony_ci break; 937cabdff1aSopenharmony_ci case 1: 938cabdff1aSopenharmony_ci /* Load new run value */ 939cabdff1aSopenharmony_ci run = bytestream2_get_byte(gbc); 940cabdff1aSopenharmony_ci if (run == 255) { 941cabdff1aSopenharmony_ci do { 942cabdff1aSopenharmony_ci probe = bytestream2_get_le16(gbc); 943cabdff1aSopenharmony_ci run += probe; 944cabdff1aSopenharmony_ci } while (probe == 0xFFFF); 945cabdff1aSopenharmony_ci } 946cabdff1aSopenharmony_ci 947cabdff1aSopenharmony_ci /* Copy two dwords from previous data */ 948cabdff1aSopenharmony_ci prev = AV_RL32(ctx->tex_data + 4 * (pos - 4)); 949cabdff1aSopenharmony_ci AV_WL32(ctx->tex_data + 4 * pos, prev); 950cabdff1aSopenharmony_ci pos++; 951cabdff1aSopenharmony_ci 952cabdff1aSopenharmony_ci prev = AV_RL32(ctx->tex_data + 4 * (pos - 4)); 953cabdff1aSopenharmony_ci AV_WL32(ctx->tex_data + 4 * pos, prev); 954cabdff1aSopenharmony_ci pos++; 955cabdff1aSopenharmony_ci break; 956cabdff1aSopenharmony_ci case 2: 957cabdff1aSopenharmony_ci /* Copy two dwords from a previous index */ 958cabdff1aSopenharmony_ci idx = 8 + bytestream2_get_le16(gbc); 959cabdff1aSopenharmony_ci if (idx > pos || (unsigned int)(pos - idx) + 2 > ctx->tex_size / 4) 960cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 961cabdff1aSopenharmony_ci prev = AV_RL32(ctx->tex_data + 4 * (pos - idx)); 962cabdff1aSopenharmony_ci AV_WL32(ctx->tex_data + 4 * pos, prev); 963cabdff1aSopenharmony_ci pos++; 964cabdff1aSopenharmony_ci 965cabdff1aSopenharmony_ci prev = AV_RL32(ctx->tex_data + 4 * (pos - idx)); 966cabdff1aSopenharmony_ci AV_WL32(ctx->tex_data + 4 * pos, prev); 967cabdff1aSopenharmony_ci pos++; 968cabdff1aSopenharmony_ci break; 969cabdff1aSopenharmony_ci case 3: 970cabdff1aSopenharmony_ci /* Copy two dwords from input */ 971cabdff1aSopenharmony_ci prev = bytestream2_get_le32(gbc); 972cabdff1aSopenharmony_ci AV_WL32(ctx->tex_data + 4 * pos, prev); 973cabdff1aSopenharmony_ci pos++; 974cabdff1aSopenharmony_ci 975cabdff1aSopenharmony_ci prev = bytestream2_get_le32(gbc); 976cabdff1aSopenharmony_ci AV_WL32(ctx->tex_data + 4 * pos, prev); 977cabdff1aSopenharmony_ci pos++; 978cabdff1aSopenharmony_ci break; 979cabdff1aSopenharmony_ci } 980cabdff1aSopenharmony_ci } 981cabdff1aSopenharmony_ci 982cabdff1aSopenharmony_ci CHECKPOINT(4); 983cabdff1aSopenharmony_ci if (pos + 2 > ctx->tex_size / 4) 984cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 985cabdff1aSopenharmony_ci 986cabdff1aSopenharmony_ci /* Copy two elements from a previous offset or from the input buffer */ 987cabdff1aSopenharmony_ci if (op) { 988cabdff1aSopenharmony_ci if (idx > pos || (unsigned int)(pos - idx) + 2 > ctx->tex_size / 4) 989cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 990cabdff1aSopenharmony_ci prev = AV_RL32(ctx->tex_data + 4 * (pos - idx)); 991cabdff1aSopenharmony_ci AV_WL32(ctx->tex_data + 4 * pos, prev); 992cabdff1aSopenharmony_ci pos++; 993cabdff1aSopenharmony_ci 994cabdff1aSopenharmony_ci prev = AV_RL32(ctx->tex_data + 4 * (pos - idx)); 995cabdff1aSopenharmony_ci AV_WL32(ctx->tex_data + 4 * pos, prev); 996cabdff1aSopenharmony_ci pos++; 997cabdff1aSopenharmony_ci } else { 998cabdff1aSopenharmony_ci CHECKPOINT(4); 999cabdff1aSopenharmony_ci 1000cabdff1aSopenharmony_ci if (op && (idx > pos || (unsigned int)(pos - idx) + 2 > ctx->tex_size / 4)) 1001cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1002cabdff1aSopenharmony_ci if (op) 1003cabdff1aSopenharmony_ci prev = AV_RL32(ctx->tex_data + 4 * (pos - idx)); 1004cabdff1aSopenharmony_ci else 1005cabdff1aSopenharmony_ci prev = bytestream2_get_le32(gbc); 1006cabdff1aSopenharmony_ci AV_WL32(ctx->tex_data + 4 * pos, prev); 1007cabdff1aSopenharmony_ci pos++; 1008cabdff1aSopenharmony_ci 1009cabdff1aSopenharmony_ci CHECKPOINT(4); 1010cabdff1aSopenharmony_ci 1011cabdff1aSopenharmony_ci if (op) 1012cabdff1aSopenharmony_ci prev = AV_RL32(ctx->tex_data + 4 * (pos - idx)); 1013cabdff1aSopenharmony_ci else 1014cabdff1aSopenharmony_ci prev = bytestream2_get_le32(gbc); 1015cabdff1aSopenharmony_ci AV_WL32(ctx->tex_data + 4 * pos, prev); 1016cabdff1aSopenharmony_ci pos++; 1017cabdff1aSopenharmony_ci } 1018cabdff1aSopenharmony_ci } 1019cabdff1aSopenharmony_ci 1020cabdff1aSopenharmony_ci return 0; 1021cabdff1aSopenharmony_ci} 1022cabdff1aSopenharmony_ci 1023cabdff1aSopenharmony_cistatic int dxv_decompress_lzf(AVCodecContext *avctx) 1024cabdff1aSopenharmony_ci{ 1025cabdff1aSopenharmony_ci DXVContext *ctx = avctx->priv_data; 1026cabdff1aSopenharmony_ci return ff_lzf_uncompress(&ctx->gbc, &ctx->tex_data, &ctx->tex_size); 1027cabdff1aSopenharmony_ci} 1028cabdff1aSopenharmony_ci 1029cabdff1aSopenharmony_cistatic int dxv_decompress_raw(AVCodecContext *avctx) 1030cabdff1aSopenharmony_ci{ 1031cabdff1aSopenharmony_ci DXVContext *ctx = avctx->priv_data; 1032cabdff1aSopenharmony_ci GetByteContext *gbc = &ctx->gbc; 1033cabdff1aSopenharmony_ci 1034cabdff1aSopenharmony_ci if (bytestream2_get_bytes_left(gbc) < ctx->tex_size) 1035cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1036cabdff1aSopenharmony_ci 1037cabdff1aSopenharmony_ci bytestream2_get_buffer(gbc, ctx->tex_data, ctx->tex_size); 1038cabdff1aSopenharmony_ci return 0; 1039cabdff1aSopenharmony_ci} 1040cabdff1aSopenharmony_ci 1041cabdff1aSopenharmony_cistatic int dxv_decode(AVCodecContext *avctx, AVFrame *frame, 1042cabdff1aSopenharmony_ci int *got_frame, AVPacket *avpkt) 1043cabdff1aSopenharmony_ci{ 1044cabdff1aSopenharmony_ci DXVContext *ctx = avctx->priv_data; 1045cabdff1aSopenharmony_ci GetByteContext *gbc = &ctx->gbc; 1046cabdff1aSopenharmony_ci int (*decompress_tex)(AVCodecContext *avctx); 1047cabdff1aSopenharmony_ci const char *msgcomp, *msgtext; 1048cabdff1aSopenharmony_ci uint32_t tag; 1049cabdff1aSopenharmony_ci int version_major, version_minor = 0; 1050cabdff1aSopenharmony_ci int size = 0, old_type = 0; 1051cabdff1aSopenharmony_ci int ret; 1052cabdff1aSopenharmony_ci 1053cabdff1aSopenharmony_ci bytestream2_init(gbc, avpkt->data, avpkt->size); 1054cabdff1aSopenharmony_ci 1055cabdff1aSopenharmony_ci ctx->texture_block_h = 4; 1056cabdff1aSopenharmony_ci ctx->texture_block_w = 4; 1057cabdff1aSopenharmony_ci 1058cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_RGBA; 1059cabdff1aSopenharmony_ci avctx->colorspace = AVCOL_SPC_RGB; 1060cabdff1aSopenharmony_ci 1061cabdff1aSopenharmony_ci ctx->tex_funct = NULL; 1062cabdff1aSopenharmony_ci ctx->tex_funct_planar[0] = NULL; 1063cabdff1aSopenharmony_ci ctx->tex_funct_planar[1] = NULL; 1064cabdff1aSopenharmony_ci 1065cabdff1aSopenharmony_ci tag = bytestream2_get_le32(gbc); 1066cabdff1aSopenharmony_ci switch (tag) { 1067cabdff1aSopenharmony_ci case MKBETAG('D', 'X', 'T', '1'): 1068cabdff1aSopenharmony_ci decompress_tex = dxv_decompress_dxt1; 1069cabdff1aSopenharmony_ci ctx->tex_funct = ctx->texdsp.dxt1_block; 1070cabdff1aSopenharmony_ci ctx->tex_rat = 8; 1071cabdff1aSopenharmony_ci ctx->tex_step = 8; 1072cabdff1aSopenharmony_ci msgcomp = "DXTR1"; 1073cabdff1aSopenharmony_ci msgtext = "DXT1"; 1074cabdff1aSopenharmony_ci break; 1075cabdff1aSopenharmony_ci case MKBETAG('D', 'X', 'T', '5'): 1076cabdff1aSopenharmony_ci decompress_tex = dxv_decompress_dxt5; 1077cabdff1aSopenharmony_ci ctx->tex_funct = ctx->texdsp.dxt5_block; 1078cabdff1aSopenharmony_ci ctx->tex_rat = 4; 1079cabdff1aSopenharmony_ci ctx->tex_step = 16; 1080cabdff1aSopenharmony_ci msgcomp = "DXTR5"; 1081cabdff1aSopenharmony_ci msgtext = "DXT5"; 1082cabdff1aSopenharmony_ci break; 1083cabdff1aSopenharmony_ci case MKBETAG('Y', 'C', 'G', '6'): 1084cabdff1aSopenharmony_ci decompress_tex = dxv_decompress_ycg6; 1085cabdff1aSopenharmony_ci ctx->tex_funct_planar[0] = yo_block; 1086cabdff1aSopenharmony_ci ctx->tex_funct_planar[1] = cocg_block; 1087cabdff1aSopenharmony_ci ctx->tex_rat = 8; 1088cabdff1aSopenharmony_ci ctx->tex_step = 32; 1089cabdff1aSopenharmony_ci ctx->ctex_step = 16; 1090cabdff1aSopenharmony_ci msgcomp = "YOCOCG6"; 1091cabdff1aSopenharmony_ci msgtext = "YCG6"; 1092cabdff1aSopenharmony_ci ctx->ctex_size = avctx->coded_width * avctx->coded_height / 4; 1093cabdff1aSopenharmony_ci ctx->texture_block_h = 4; 1094cabdff1aSopenharmony_ci ctx->texture_block_w = 16; 1095cabdff1aSopenharmony_ci ctx->ctexture_block_h = 4; 1096cabdff1aSopenharmony_ci ctx->ctexture_block_w = 4; 1097cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_YUV420P; 1098cabdff1aSopenharmony_ci avctx->colorspace = AVCOL_SPC_YCOCG; 1099cabdff1aSopenharmony_ci break; 1100cabdff1aSopenharmony_ci case MKBETAG('Y', 'G', '1', '0'): 1101cabdff1aSopenharmony_ci decompress_tex = dxv_decompress_yg10; 1102cabdff1aSopenharmony_ci ctx->tex_funct_planar[0] = yao_block; 1103cabdff1aSopenharmony_ci ctx->tex_funct_planar[1] = cocg_block; 1104cabdff1aSopenharmony_ci ctx->tex_rat = 4; 1105cabdff1aSopenharmony_ci ctx->tex_step = 64; 1106cabdff1aSopenharmony_ci ctx->ctex_step = 16; 1107cabdff1aSopenharmony_ci msgcomp = "YAOCOCG10"; 1108cabdff1aSopenharmony_ci msgtext = "YG10"; 1109cabdff1aSopenharmony_ci ctx->ctex_size = avctx->coded_width * avctx->coded_height / 4; 1110cabdff1aSopenharmony_ci ctx->texture_block_h = 4; 1111cabdff1aSopenharmony_ci ctx->texture_block_w = 16; 1112cabdff1aSopenharmony_ci ctx->ctexture_block_h = 4; 1113cabdff1aSopenharmony_ci ctx->ctexture_block_w = 4; 1114cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_YUVA420P; 1115cabdff1aSopenharmony_ci avctx->colorspace = AVCOL_SPC_YCOCG; 1116cabdff1aSopenharmony_ci break; 1117cabdff1aSopenharmony_ci default: 1118cabdff1aSopenharmony_ci /* Old version does not have a real header, just size and type. */ 1119cabdff1aSopenharmony_ci size = tag & 0x00FFFFFF; 1120cabdff1aSopenharmony_ci old_type = tag >> 24; 1121cabdff1aSopenharmony_ci version_major = (old_type & 0x0F) - 1; 1122cabdff1aSopenharmony_ci 1123cabdff1aSopenharmony_ci if (old_type & 0x80) { 1124cabdff1aSopenharmony_ci msgcomp = "RAW"; 1125cabdff1aSopenharmony_ci decompress_tex = dxv_decompress_raw; 1126cabdff1aSopenharmony_ci } else { 1127cabdff1aSopenharmony_ci msgcomp = "LZF"; 1128cabdff1aSopenharmony_ci decompress_tex = dxv_decompress_lzf; 1129cabdff1aSopenharmony_ci } 1130cabdff1aSopenharmony_ci 1131cabdff1aSopenharmony_ci if (old_type & 0x40) { 1132cabdff1aSopenharmony_ci msgtext = "DXT5"; 1133cabdff1aSopenharmony_ci 1134cabdff1aSopenharmony_ci ctx->tex_funct = ctx->texdsp.dxt5_block; 1135cabdff1aSopenharmony_ci ctx->tex_step = 16; 1136cabdff1aSopenharmony_ci } else if (old_type & 0x20 || version_major == 1) { 1137cabdff1aSopenharmony_ci msgtext = "DXT1"; 1138cabdff1aSopenharmony_ci 1139cabdff1aSopenharmony_ci ctx->tex_funct = ctx->texdsp.dxt1_block; 1140cabdff1aSopenharmony_ci ctx->tex_step = 8; 1141cabdff1aSopenharmony_ci } else { 1142cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Unsupported header (0x%08"PRIX32")\n.", tag); 1143cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1144cabdff1aSopenharmony_ci } 1145cabdff1aSopenharmony_ci ctx->tex_rat = 1; 1146cabdff1aSopenharmony_ci break; 1147cabdff1aSopenharmony_ci } 1148cabdff1aSopenharmony_ci 1149cabdff1aSopenharmony_ci ctx->slice_count = av_clip(avctx->thread_count, 1, 1150cabdff1aSopenharmony_ci avctx->coded_height / FFMAX(ctx->texture_block_h, 1151cabdff1aSopenharmony_ci ctx->ctexture_block_h)); 1152cabdff1aSopenharmony_ci 1153cabdff1aSopenharmony_ci /* New header is 12 bytes long. */ 1154cabdff1aSopenharmony_ci if (!old_type) { 1155cabdff1aSopenharmony_ci version_major = bytestream2_get_byte(gbc) - 1; 1156cabdff1aSopenharmony_ci version_minor = bytestream2_get_byte(gbc); 1157cabdff1aSopenharmony_ci 1158cabdff1aSopenharmony_ci /* Encoder copies texture data when compression is not advantageous. */ 1159cabdff1aSopenharmony_ci if (bytestream2_get_byte(gbc)) { 1160cabdff1aSopenharmony_ci msgcomp = "RAW"; 1161cabdff1aSopenharmony_ci ctx->tex_rat = 1; 1162cabdff1aSopenharmony_ci decompress_tex = dxv_decompress_raw; 1163cabdff1aSopenharmony_ci } 1164cabdff1aSopenharmony_ci 1165cabdff1aSopenharmony_ci bytestream2_skip(gbc, 1); // unknown 1166cabdff1aSopenharmony_ci size = bytestream2_get_le32(gbc); 1167cabdff1aSopenharmony_ci } 1168cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_DEBUG, 1169cabdff1aSopenharmony_ci "%s compression with %s texture (version %d.%d)\n", 1170cabdff1aSopenharmony_ci msgcomp, msgtext, version_major, version_minor); 1171cabdff1aSopenharmony_ci 1172cabdff1aSopenharmony_ci if (size != bytestream2_get_bytes_left(gbc)) { 1173cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, 1174cabdff1aSopenharmony_ci "Incomplete or invalid file (header %d, left %u).\n", 1175cabdff1aSopenharmony_ci size, bytestream2_get_bytes_left(gbc)); 1176cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1177cabdff1aSopenharmony_ci } 1178cabdff1aSopenharmony_ci 1179cabdff1aSopenharmony_ci ctx->tex_size = avctx->coded_width * avctx->coded_height * 4 / ctx->tex_rat; 1180cabdff1aSopenharmony_ci ret = av_reallocp(&ctx->tex_data, ctx->tex_size + AV_INPUT_BUFFER_PADDING_SIZE); 1181cabdff1aSopenharmony_ci if (ret < 0) 1182cabdff1aSopenharmony_ci return ret; 1183cabdff1aSopenharmony_ci 1184cabdff1aSopenharmony_ci if (ctx->ctex_size) { 1185cabdff1aSopenharmony_ci int i; 1186cabdff1aSopenharmony_ci 1187cabdff1aSopenharmony_ci ctx->op_size[0] = avctx->coded_width * avctx->coded_height / 16; 1188cabdff1aSopenharmony_ci ctx->op_size[1] = avctx->coded_width * avctx->coded_height / 32; 1189cabdff1aSopenharmony_ci ctx->op_size[2] = avctx->coded_width * avctx->coded_height / 32; 1190cabdff1aSopenharmony_ci ctx->op_size[3] = avctx->coded_width * avctx->coded_height / 16; 1191cabdff1aSopenharmony_ci 1192cabdff1aSopenharmony_ci ret = av_reallocp(&ctx->ctex_data, ctx->ctex_size + AV_INPUT_BUFFER_PADDING_SIZE); 1193cabdff1aSopenharmony_ci if (ret < 0) 1194cabdff1aSopenharmony_ci return ret; 1195cabdff1aSopenharmony_ci for (i = 0; i < 4; i++) { 1196cabdff1aSopenharmony_ci ret = av_reallocp(&ctx->op_data[i], ctx->op_size[i]); 1197cabdff1aSopenharmony_ci if (ret < 0) 1198cabdff1aSopenharmony_ci return ret; 1199cabdff1aSopenharmony_ci } 1200cabdff1aSopenharmony_ci } 1201cabdff1aSopenharmony_ci 1202cabdff1aSopenharmony_ci /* Decompress texture out of the intermediate compression. */ 1203cabdff1aSopenharmony_ci ret = decompress_tex(avctx); 1204cabdff1aSopenharmony_ci if (ret < 0) 1205cabdff1aSopenharmony_ci return ret; 1206cabdff1aSopenharmony_ci { 1207cabdff1aSopenharmony_ci int w_block = avctx->coded_width / ctx->texture_block_w; 1208cabdff1aSopenharmony_ci int h_block = avctx->coded_height / ctx->texture_block_h; 1209cabdff1aSopenharmony_ci if (w_block * h_block * ctx->tex_step > ctx->tex_size * 8LL) 1210cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1211cabdff1aSopenharmony_ci } 1212cabdff1aSopenharmony_ci 1213cabdff1aSopenharmony_ci ret = ff_thread_get_buffer(avctx, frame, 0); 1214cabdff1aSopenharmony_ci if (ret < 0) 1215cabdff1aSopenharmony_ci return ret; 1216cabdff1aSopenharmony_ci 1217cabdff1aSopenharmony_ci /* Now decompress the texture with the standard functions. */ 1218cabdff1aSopenharmony_ci avctx->execute2(avctx, decompress_texture_thread, 1219cabdff1aSopenharmony_ci frame, NULL, ctx->slice_count); 1220cabdff1aSopenharmony_ci 1221cabdff1aSopenharmony_ci /* Frame is ready to be output. */ 1222cabdff1aSopenharmony_ci frame->pict_type = AV_PICTURE_TYPE_I; 1223cabdff1aSopenharmony_ci frame->key_frame = 1; 1224cabdff1aSopenharmony_ci *got_frame = 1; 1225cabdff1aSopenharmony_ci 1226cabdff1aSopenharmony_ci return avpkt->size; 1227cabdff1aSopenharmony_ci} 1228cabdff1aSopenharmony_ci 1229cabdff1aSopenharmony_cistatic int dxv_init(AVCodecContext *avctx) 1230cabdff1aSopenharmony_ci{ 1231cabdff1aSopenharmony_ci DXVContext *ctx = avctx->priv_data; 1232cabdff1aSopenharmony_ci int ret = av_image_check_size(avctx->width, avctx->height, 0, avctx); 1233cabdff1aSopenharmony_ci 1234cabdff1aSopenharmony_ci if (ret < 0) { 1235cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Invalid image size %dx%d.\n", 1236cabdff1aSopenharmony_ci avctx->width, avctx->height); 1237cabdff1aSopenharmony_ci return ret; 1238cabdff1aSopenharmony_ci } 1239cabdff1aSopenharmony_ci 1240cabdff1aSopenharmony_ci /* Codec requires 16x16 alignment. */ 1241cabdff1aSopenharmony_ci avctx->coded_width = FFALIGN(avctx->width, 16); 1242cabdff1aSopenharmony_ci avctx->coded_height = FFALIGN(avctx->height, 16); 1243cabdff1aSopenharmony_ci 1244cabdff1aSopenharmony_ci ff_texturedsp_init(&ctx->texdsp); 1245cabdff1aSopenharmony_ci 1246cabdff1aSopenharmony_ci return 0; 1247cabdff1aSopenharmony_ci} 1248cabdff1aSopenharmony_ci 1249cabdff1aSopenharmony_cistatic int dxv_close(AVCodecContext *avctx) 1250cabdff1aSopenharmony_ci{ 1251cabdff1aSopenharmony_ci DXVContext *ctx = avctx->priv_data; 1252cabdff1aSopenharmony_ci 1253cabdff1aSopenharmony_ci av_freep(&ctx->tex_data); 1254cabdff1aSopenharmony_ci av_freep(&ctx->ctex_data); 1255cabdff1aSopenharmony_ci av_freep(&ctx->op_data[0]); 1256cabdff1aSopenharmony_ci av_freep(&ctx->op_data[1]); 1257cabdff1aSopenharmony_ci av_freep(&ctx->op_data[2]); 1258cabdff1aSopenharmony_ci av_freep(&ctx->op_data[3]); 1259cabdff1aSopenharmony_ci 1260cabdff1aSopenharmony_ci return 0; 1261cabdff1aSopenharmony_ci} 1262cabdff1aSopenharmony_ci 1263cabdff1aSopenharmony_ciconst FFCodec ff_dxv_decoder = { 1264cabdff1aSopenharmony_ci .p.name = "dxv", 1265cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("Resolume DXV"), 1266cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 1267cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_DXV, 1268cabdff1aSopenharmony_ci .init = dxv_init, 1269cabdff1aSopenharmony_ci FF_CODEC_DECODE_CB(dxv_decode), 1270cabdff1aSopenharmony_ci .close = dxv_close, 1271cabdff1aSopenharmony_ci .priv_data_size = sizeof(DXVContext), 1272cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1 | 1273cabdff1aSopenharmony_ci AV_CODEC_CAP_SLICE_THREADS | 1274cabdff1aSopenharmony_ci AV_CODEC_CAP_FRAME_THREADS, 1275cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | 1276cabdff1aSopenharmony_ci FF_CODEC_CAP_INIT_CLEANUP, 1277cabdff1aSopenharmony_ci}; 1278